aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/assist_config.rs8
-rw-r--r--crates/assists/src/assist_context.rs5
-rw-r--r--crates/assists/src/handlers/auto_import.rs9
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs45
-rw-r--r--crates/assists/src/handlers/qualify_path.rs40
-rw-r--r--crates/assists/src/handlers/unmerge_use.rs231
-rw-r--r--crates/assists/src/lib.rs4
-rw-r--r--crates/assists/src/tests.rs9
-rw-r--r--crates/assists/src/tests/generated.rs14
-rw-r--r--crates/assists/src/utils.rs1
-rw-r--r--crates/completion/src/completions.rs1
-rw-r--r--crates/completion/src/completions/flyimport.rs291
-rw-r--r--crates/completion/src/completions/keyword.rs106
-rw-r--r--crates/completion/src/completions/unqualified_path.rs251
-rw-r--r--crates/completion/src/config.rs4
-rw-r--r--crates/completion/src/context.rs26
-rw-r--r--crates/completion/src/lib.rs5
-rw-r--r--crates/completion/src/render.rs15
-rw-r--r--crates/completion/src/test_utils.rs14
-rw-r--r--crates/hir/src/semantics.rs1
-rw-r--r--crates/hir/src/semantics/source_to_def.rs9
-rw-r--r--crates/hir_def/src/body/lower.rs4
-rw-r--r--crates/hir_def/src/expr.rs5
-rw-r--r--crates/hir_def/src/resolver.rs2
-rw-r--r--crates/hir_expand/src/ast_id_map.rs30
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/lib.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs7
-rw-r--r--crates/ide/src/diagnostics.rs4
-rw-r--r--crates/ide/src/display/navigation_target.rs23
-rw-r--r--crates/ide/src/extend_selection.rs6
-rw-r--r--crates/ide/src/goto_definition.rs35
-rw-r--r--crates/ide/src/hover.rs47
-rw-r--r--crates/ide/src/join_lines.rs4
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/references.rs119
-rw-r--r--crates/ide/src/references/rename.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs39
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html18
-rw-r--r--crates/ide/src/syntax_tree.rs4
-rw-r--r--crates/ide_db/src/defs.rs45
-rw-r--r--crates/ide_db/src/helpers.rs1
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs (renamed from crates/assists/src/utils/import_assets.rs)50
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs18
-rw-r--r--crates/ide_db/src/imports_locator.rs6
-rw-r--r--crates/ide_db/src/search.rs2
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs16
-rw-r--r--crates/parser/src/grammar/paths.rs6
-rw-r--r--crates/parser/src/syntax_kind/generated.rs8
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs5
-rw-r--r--crates/rust-analyzer/src/config.rs33
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt47
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt47
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt47
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt120
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs53
-rw-r--r--crates/rust-analyzer/src/to_proto.rs5
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/algo.rs8
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs40
-rw-r--r--crates/syntax/src/ast/make.rs8
-rw-r--r--crates/syntax/src/ast/node_ext.rs22
-rw-r--r--crates/syntax/src/parsing/reparsing.rs5
-rw-r--r--crates/syntax/src/validation.rs2
-rw-r--r--crates/syntax/test_data/parser/err/0018_incomplete_fn.rast6
-rw-r--r--crates/syntax/test_data/parser/err/0035_use_recover.rast3
-rw-r--r--crates/syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast15
-rw-r--r--crates/syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast15
-rw-r--r--crates/syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/err/0015_empty_segment.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0052_path_type.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0067_crate_path.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rast28
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rs4
-rw-r--r--crates/syntax/test_data/parser/ok/0013_use_path_self_super.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast3
-rw-r--r--crates/syntax/test_data/parser/ok/0034_crate_path_in_call.rast3
86 files changed, 1220 insertions, 968 deletions
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs
index 4fe8ea761..9cabf037c 100644
--- a/crates/assists/src/assist_config.rs
+++ b/crates/assists/src/assist_config.rs
@@ -4,7 +4,7 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! assists if we are allowed to. 5//! assists if we are allowed to.
6 6
7use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; 7use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
8 8
9use crate::AssistKind; 9use crate::AssistKind;
10 10
@@ -14,9 +14,3 @@ pub struct AssistConfig {
14 pub allowed: Option<Vec<AssistKind>>, 14 pub allowed: Option<Vec<AssistKind>>,
15 pub insert_use: InsertUseConfig, 15 pub insert_use: InsertUseConfig,
16} 16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct InsertUseConfig {
20 pub merge: Option<MergeBehavior>,
21 pub prefix_kind: hir::PrefixKind,
22}
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index 321fe77f3..8d93edba2 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -2,7 +2,6 @@
2 2
3use std::mem; 3use std::mem;
4 4
5use algo::find_covering_element;
6use hir::Semantics; 5use hir::Semantics;
7use ide_db::{ 6use ide_db::{
8 base_db::{AnchoredPathBuf, FileId, FileRange}, 7 base_db::{AnchoredPathBuf, FileId, FileRange},
@@ -94,11 +93,11 @@ impl<'a> AssistContext<'a> {
94 self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset()) 93 self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset())
95 } 94 }
96 pub(crate) fn covering_element(&self) -> SyntaxElement { 95 pub(crate) fn covering_element(&self) -> SyntaxElement {
97 find_covering_element(self.source_file.syntax(), self.frange.range) 96 self.source_file.syntax().covering_element(self.frange.range)
98 } 97 }
99 // FIXME: remove 98 // FIXME: remove
100 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { 99 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement {
101 find_covering_element(self.source_file.syntax(), range) 100 self.source_file.syntax().covering_element(range)
102 } 101 }
103} 102}
104 103
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index 55620f0f3..4e2a4fcd9 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -1,13 +1,11 @@
1use ide_db::helpers::{ 1use ide_db::helpers::{
2 import_assets::{ImportAssets, ImportCandidate},
2 insert_use::{insert_use, ImportScope}, 3 insert_use::{insert_use, ImportScope},
3 mod_path_to_ast, 4 mod_path_to_ast,
4}; 5};
5use syntax::ast; 6use syntax::ast;
6 7
7use crate::{ 8use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
8 utils::import_assets::{ImportAssets, ImportCandidate},
9 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
10};
11 9
12// Feature: Auto Import 10// Feature: Auto Import
13// 11//
@@ -121,8 +119,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
121 119
122fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { 120fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
123 let name = match import_candidate { 121 let name = match import_candidate {
124 ImportCandidate::UnqualifiedName(candidate) 122 ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name),
125 | ImportCandidate::QualifierStart(candidate) => format!("Import {}", &candidate.name),
126 ImportCandidate::TraitAssocItem(candidate) => { 123 ImportCandidate::TraitAssocItem(candidate) => {
127 format!("Import a trait for item {}", &candidate.name) 124 format!("Import a trait for item {}", &candidate.name)
128 } 125 }
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
index dc798daaa..0e63a60e8 100644
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ b/crates/assists/src/handlers/inline_local_variable.rs
@@ -79,29 +79,30 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
79 None => return Ok(false), 79 None => return Ok(false),
80 }; 80 };
81 81
82 Ok(!matches!((&initializer_expr, usage_parent), 82 Ok(!matches!(
83 (&initializer_expr, usage_parent),
83 (ast::Expr::CallExpr(_), _) 84 (ast::Expr::CallExpr(_), _)
84 | (ast::Expr::IndexExpr(_), _) 85 | (ast::Expr::IndexExpr(_), _)
85 | (ast::Expr::MethodCallExpr(_), _) 86 | (ast::Expr::MethodCallExpr(_), _)
86 | (ast::Expr::FieldExpr(_), _) 87 | (ast::Expr::FieldExpr(_), _)
87 | (ast::Expr::TryExpr(_), _) 88 | (ast::Expr::TryExpr(_), _)
88 | (ast::Expr::RefExpr(_), _) 89 | (ast::Expr::RefExpr(_), _)
89 | (ast::Expr::Literal(_), _) 90 | (ast::Expr::Literal(_), _)
90 | (ast::Expr::TupleExpr(_), _) 91 | (ast::Expr::TupleExpr(_), _)
91 | (ast::Expr::ArrayExpr(_), _) 92 | (ast::Expr::ArrayExpr(_), _)
92 | (ast::Expr::ParenExpr(_), _) 93 | (ast::Expr::ParenExpr(_), _)
93 | (ast::Expr::PathExpr(_), _) 94 | (ast::Expr::PathExpr(_), _)
94 | (ast::Expr::BlockExpr(_), _) 95 | (ast::Expr::BlockExpr(_), _)
95 | (ast::Expr::EffectExpr(_), _) 96 | (ast::Expr::EffectExpr(_), _)
96 | (_, ast::Expr::CallExpr(_)) 97 | (_, ast::Expr::CallExpr(_))
97 | (_, ast::Expr::TupleExpr(_)) 98 | (_, ast::Expr::TupleExpr(_))
98 | (_, ast::Expr::ArrayExpr(_)) 99 | (_, ast::Expr::ArrayExpr(_))
99 | (_, ast::Expr::ParenExpr(_)) 100 | (_, ast::Expr::ParenExpr(_))
100 | (_, ast::Expr::ForExpr(_)) 101 | (_, ast::Expr::ForExpr(_))
101 | (_, ast::Expr::WhileExpr(_)) 102 | (_, ast::Expr::WhileExpr(_))
102 | (_, ast::Expr::BreakExpr(_)) 103 | (_, ast::Expr::BreakExpr(_))
103 | (_, ast::Expr::ReturnExpr(_)) 104 | (_, ast::Expr::ReturnExpr(_))
104 | (_, ast::Expr::MatchExpr(_)) 105 | (_, ast::Expr::MatchExpr(_))
105 )) 106 ))
106 }) 107 })
107 .collect::<Result<Vec<_>, _>>()?; 108 .collect::<Result<Vec<_>, _>>()?;
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
index f7fbf37f4..a7d9fd4dc 100644
--- a/crates/assists/src/handlers/qualify_path.rs
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -1,7 +1,10 @@
1use std::iter; 1use std::iter;
2 2
3use hir::AsName; 3use hir::AsName;
4use ide_db::helpers::mod_path_to_ast; 4use ide_db::helpers::{
5 import_assets::{ImportAssets, ImportCandidate},
6 mod_path_to_ast,
7};
5use ide_db::RootDatabase; 8use ide_db::RootDatabase;
6use syntax::{ 9use syntax::{
7 ast, 10 ast,
@@ -12,7 +15,6 @@ use test_utils::mark;
12 15
13use crate::{ 16use crate::{
14 assist_context::{AssistContext, Assists}, 17 assist_context::{AssistContext, Assists},
15 utils::import_assets::{ImportAssets, ImportCandidate},
16 AssistId, AssistKind, GroupLabel, 18 AssistId, AssistKind, GroupLabel,
17}; 19};
18 20
@@ -53,17 +55,18 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
53 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; 55 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
54 56
55 let qualify_candidate = match candidate { 57 let qualify_candidate = match candidate {
56 ImportCandidate::QualifierStart(_) => { 58 ImportCandidate::Path(candidate) => {
57 mark::hit!(qualify_path_qualifier_start); 59 if candidate.qualifier.is_some() {
58 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 60 mark::hit!(qualify_path_qualifier_start);
59 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); 61 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
60 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) 62 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
61 } 63 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
62 ImportCandidate::UnqualifiedName(_) => { 64 } else {
63 mark::hit!(qualify_path_unqualified_name); 65 mark::hit!(qualify_path_unqualified_name);
64 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 66 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
65 let generics = path.segment()?.generic_arg_list(); 67 let generics = path.segment()?.generic_arg_list();
66 QualifyCandidate::UnqualifiedName(generics) 68 QualifyCandidate::UnqualifiedName(generics)
69 }
67 } 70 }
68 ImportCandidate::TraitAssocItem(_) => { 71 ImportCandidate::TraitAssocItem(_) => {
69 mark::hit!(qualify_path_trait_assoc_item); 72 mark::hit!(qualify_path_trait_assoc_item);
@@ -186,7 +189,7 @@ fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> {
186 189
187fn group_label(candidate: &ImportCandidate) -> GroupLabel { 190fn group_label(candidate: &ImportCandidate) -> GroupLabel {
188 let name = match candidate { 191 let name = match candidate {
189 ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name, 192 ImportCandidate::Path(it) => &it.name,
190 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, 193 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name,
191 }; 194 };
192 GroupLabel(format!("Qualify {}", name)) 195 GroupLabel(format!("Qualify {}", name))
@@ -194,8 +197,13 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
194 197
195fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { 198fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String {
196 match candidate { 199 match candidate {
197 ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import), 200 ImportCandidate::Path(candidate) => {
198 ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import), 201 if candidate.qualifier.is_some() {
202 format!("Qualify with `{}`", &import)
203 } else {
204 format!("Qualify as `{}`", &import)
205 }
206 }
199 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), 207 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import),
200 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), 208 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import),
201 } 209 }
diff --git a/crates/assists/src/handlers/unmerge_use.rs b/crates/assists/src/handlers/unmerge_use.rs
new file mode 100644
index 000000000..3dbef8e51
--- /dev/null
+++ b/crates/assists/src/handlers/unmerge_use.rs
@@ -0,0 +1,231 @@
1use syntax::{
2 algo::SyntaxRewriter,
3 ast::{self, edit::AstNodeEdit, VisibilityOwner},
4 AstNode, SyntaxKind,
5};
6use test_utils::mark;
7
8use crate::{
9 assist_context::{AssistContext, Assists},
10 AssistId, AssistKind,
11};
12
13// Assist: unmerge_use
14//
15// Extracts single use item from use list.
16//
17// ```
18// use std::fmt::{Debug, Display$0};
19// ```
20// ->
21// ```
22// use std::fmt::{Debug};
23// use std::fmt::Display;
24// ```
25pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let tree: ast::UseTree = ctx.find_node_at_offset()?;
27
28 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?;
29 if tree_list.use_trees().count() < 2 {
30 mark::hit!(skip_single_use_item);
31 return None;
32 }
33
34 let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?;
35 let path = resolve_full_path(&tree)?;
36
37 let target = tree.syntax().text_range();
38 acc.add(
39 AssistId("unmerge_use", AssistKind::RefactorRewrite),
40 "Unmerge use",
41 target,
42 |builder| {
43 let new_use = ast::make::use_(
44 use_.visibility(),
45 ast::make::use_tree(
46 path,
47 tree.use_tree_list(),
48 tree.rename(),
49 tree.star_token().is_some(),
50 ),
51 );
52
53 let mut rewriter = SyntaxRewriter::default();
54 rewriter += tree.remove();
55 rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline());
56 if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize {
57 rewriter.insert_after(
58 use_.syntax(),
59 &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)),
60 );
61 }
62 rewriter.insert_after(use_.syntax(), new_use.syntax());
63
64 builder.rewrite(rewriter);
65 },
66 )
67}
68
69fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> {
70 let mut paths = tree
71 .syntax()
72 .ancestors()
73 .take_while(|n| n.kind() != SyntaxKind::USE_KW)
74 .filter_map(ast::UseTree::cast)
75 .filter_map(|t| t.path());
76
77 let mut final_path = paths.next()?;
78 for path in paths {
79 final_path = ast::make::path_concat(path, final_path)
80 }
81 Some(final_path)
82}
83
84#[cfg(test)]
85mod tests {
86 use crate::tests::{check_assist, check_assist_not_applicable};
87
88 use super::*;
89
90 #[test]
91 fn skip_single_use_item() {
92 mark::check!(skip_single_use_item);
93 check_assist_not_applicable(
94 unmerge_use,
95 r"
96use std::fmt::Debug$0;
97",
98 );
99 check_assist_not_applicable(
100 unmerge_use,
101 r"
102use std::fmt::{Debug$0};
103",
104 );
105 check_assist_not_applicable(
106 unmerge_use,
107 r"
108use std::fmt::Debug as Dbg$0;
109",
110 );
111 }
112
113 #[test]
114 fn skip_single_glob_import() {
115 check_assist_not_applicable(
116 unmerge_use,
117 r"
118use std::fmt::*$0;
119",
120 );
121 }
122
123 #[test]
124 fn unmerge_use_item() {
125 check_assist(
126 unmerge_use,
127 r"
128use std::fmt::{Debug, Display$0};
129",
130 r"
131use std::fmt::{Debug};
132use std::fmt::Display;
133",
134 );
135
136 check_assist(
137 unmerge_use,
138 r"
139use std::fmt::{Debug, format$0, Display};
140",
141 r"
142use std::fmt::{Debug, Display};
143use std::fmt::format;
144",
145 );
146 }
147
148 #[test]
149 fn unmerge_glob_import() {
150 check_assist(
151 unmerge_use,
152 r"
153use std::fmt::{*$0, Display};
154",
155 r"
156use std::fmt::{Display};
157use std::fmt::*;
158",
159 );
160 }
161
162 #[test]
163 fn unmerge_renamed_use_item() {
164 check_assist(
165 unmerge_use,
166 r"
167use std::fmt::{Debug, Display as Disp$0};
168",
169 r"
170use std::fmt::{Debug};
171use std::fmt::Display as Disp;
172",
173 );
174 }
175
176 #[test]
177 fn unmerge_indented_use_item() {
178 check_assist(
179 unmerge_use,
180 r"
181mod format {
182 use std::fmt::{Debug, Display$0 as Disp, format};
183}
184",
185 r"
186mod format {
187 use std::fmt::{Debug, format};
188 use std::fmt::Display as Disp;
189}
190",
191 );
192 }
193
194 #[test]
195 fn unmerge_nested_use_item() {
196 check_assist(
197 unmerge_use,
198 r"
199use foo::bar::{baz::{qux$0, foobar}, barbaz};
200",
201 r"
202use foo::bar::{baz::{foobar}, barbaz};
203use foo::bar::baz::qux;
204",
205 );
206 check_assist(
207 unmerge_use,
208 r"
209use foo::bar::{baz$0::{qux, foobar}, barbaz};
210",
211 r"
212use foo::bar::{barbaz};
213use foo::bar::baz::{qux, foobar};
214",
215 );
216 }
217
218 #[test]
219 fn unmerge_use_item_with_visibility() {
220 check_assist(
221 unmerge_use,
222 r"
223pub use std::fmt::{Debug, Display$0};
224",
225 r"
226pub use std::fmt::{Debug};
227pub use std::fmt::Display;
228",
229 );
230 }
231}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 1080294ab..14178a651 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -24,7 +24,7 @@ use syntax::TextRange;
24 24
25pub(crate) use crate::assist_context::{AssistContext, Assists}; 25pub(crate) use crate::assist_context::{AssistContext, Assists};
26 26
27pub use assist_config::{AssistConfig, InsertUseConfig}; 27pub use assist_config::AssistConfig;
28 28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)] 29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum AssistKind { 30pub enum AssistKind {
@@ -156,6 +156,7 @@ mod handlers {
156 mod replace_unwrap_with_match; 156 mod replace_unwrap_with_match;
157 mod split_import; 157 mod split_import;
158 mod toggle_ignore; 158 mod toggle_ignore;
159 mod unmerge_use;
159 mod unwrap_block; 160 mod unwrap_block;
160 mod wrap_return_type_in_result; 161 mod wrap_return_type_in_result;
161 162
@@ -213,6 +214,7 @@ mod handlers {
213 replace_unwrap_with_match::replace_unwrap_with_match, 214 replace_unwrap_with_match::replace_unwrap_with_match,
214 split_import::split_import, 215 split_import::split_import,
215 toggle_ignore::toggle_ignore, 216 toggle_ignore::toggle_ignore,
217 unmerge_use::unmerge_use,
216 unwrap_block::unwrap_block, 218 unwrap_block::unwrap_block,
217 wrap_return_type_in_result::wrap_return_type_in_result, 219 wrap_return_type_in_result::wrap_return_type_in_result,
218 // These are manually sorted for better priorities 220 // These are manually sorted for better priorities
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index 71431b406..32bd8698b 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -3,16 +3,17 @@ mod generated;
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::{ 4use ide_db::{
5 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, 5 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
6 helpers::{insert_use::MergeBehavior, SnippetCap}, 6 helpers::{
7 insert_use::{InsertUseConfig, MergeBehavior},
8 SnippetCap,
9 },
7 source_change::FileSystemEdit, 10 source_change::FileSystemEdit,
8 RootDatabase, 11 RootDatabase,
9}; 12};
10use syntax::TextRange; 13use syntax::TextRange;
11use test_utils::{assert_eq_text, extract_offset, extract_range}; 14use test_utils::{assert_eq_text, extract_offset, extract_range};
12 15
13use crate::{ 16use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists};
14 handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig,
15};
16use stdx::{format_to, trim_indent}; 17use stdx::{format_to, trim_indent};
17 18
18pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { 19pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 217f577eb..d48d063b4 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -1138,6 +1138,20 @@ fn arithmetics {
1138} 1138}
1139 1139
1140#[test] 1140#[test]
1141fn doctest_unmerge_use() {
1142 check_doc_test(
1143 "unmerge_use",
1144 r#####"
1145use std::fmt::{Debug, Display$0};
1146"#####,
1147 r#####"
1148use std::fmt::{Debug};
1149use std::fmt::Display;
1150"#####,
1151 )
1152}
1153
1154#[test]
1141fn doctest_unwrap_block() { 1155fn doctest_unwrap_block() {
1142 check_doc_test( 1156 check_doc_test(
1143 "unwrap_block", 1157 "unwrap_block",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 9ea96eb73..fc9f83bab 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -1,5 +1,4 @@
1//! Assorted functions shared by several assists. 1//! Assorted functions shared by several assists.
2pub(crate) mod import_assets;
3 2
4use std::ops; 3use std::ops;
5 4
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index 00c9e76f0..c3ce6e51d 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -13,6 +13,7 @@ pub(crate) mod postfix;
13pub(crate) mod macro_in_item_position; 13pub(crate) mod macro_in_item_position;
14pub(crate) mod trait_impl; 14pub(crate) mod trait_impl;
15pub(crate) mod mod_; 15pub(crate) mod mod_;
16pub(crate) mod flyimport;
16 17
17use hir::{ModPath, ScopeDef, Type}; 18use hir::{ModPath, ScopeDef, Type};
18 19
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs
new file mode 100644
index 000000000..222809638
--- /dev/null
+++ b/crates/completion/src/completions/flyimport.rs
@@ -0,0 +1,291 @@
1//! Feature: completion with imports-on-the-fly
2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input
5//! (case-insensitive, in any order or places).
6//!
7//! ```
8//! fn main() {
9//! pda$0
10//! }
11//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
12//! ```
13//! ->
14//! ```
15//! use std::marker::PhantomData;
16//!
17//! fn main() {
18//! PhantomData
19//! }
20//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
21//! ```
22//!
23//! .Fuzzy search details
24//!
25//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
26//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
27//! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
28//!
29//! .Import configuration
30//!
31//! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
32//! Mimics the corresponding behavior of the `Auto Import` feature.
33//!
34//! .LSP and performance implications
35//!
36//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
37//! (case sensitive) resolve client capability in its client capabilities.
38//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
39//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
40//! which might be slow ergo the feature is automatically disabled.
41//!
42//! .Feature toggle
43//!
44//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
45//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
46//! capability enabled.
47
48use either::Either;
49use hir::{ModPath, ScopeDef};
50use ide_db::{helpers::insert_use::ImportScope, imports_locator};
51use syntax::AstNode;
52use test_utils::mark;
53
54use crate::{
55 context::CompletionContext,
56 render::{render_resolution_with_import, RenderContext},
57 ImportEdit,
58};
59
60use super::Completions;
61
62pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
63 if !ctx.config.enable_autoimport_completions {
64 return None;
65 }
66 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() {
67 return None;
68 }
69 let potential_import_name = ctx.token.to_string();
70 if potential_import_name.len() < 2 {
71 return None;
72 }
73 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
74
75 let current_module = ctx.scope.module()?;
76 let anchor = ctx.name_ref_syntax.as_ref()?;
77 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
78
79 let user_input_lowercased = potential_import_name.to_lowercase();
80 let mut all_mod_paths = imports_locator::find_similar_imports(
81 &ctx.sema,
82 ctx.krate?,
83 Some(40),
84 potential_import_name,
85 true,
86 true,
87 )
88 .filter_map(|import_candidate| {
89 Some(match import_candidate {
90 Either::Left(module_def) => {
91 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
92 }
93 Either::Right(macro_def) => {
94 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
95 }
96 })
97 })
98 .filter(|(mod_path, _)| mod_path.len() > 1)
99 .collect::<Vec<_>>();
100
101 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
102 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
103 });
104
105 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
106 render_resolution_with_import(
107 RenderContext::new(ctx),
108 ImportEdit { import_path, import_scope: import_scope.clone() },
109 &definition,
110 )
111 }));
112 Some(())
113}
114
115fn compute_fuzzy_completion_order_key(
116 proposed_mod_path: &ModPath,
117 user_input_lowercased: &str,
118) -> usize {
119 mark::hit!(certain_fuzzy_order_test);
120 let proposed_import_name = match proposed_mod_path.segments.last() {
121 Some(name) => name.to_string().to_lowercase(),
122 None => return usize::MAX,
123 };
124 match proposed_import_name.match_indices(user_input_lowercased).next() {
125 Some((first_matching_index, _)) => first_matching_index,
126 None => usize::MAX,
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use expect_test::{expect, Expect};
133 use test_utils::mark;
134
135 use crate::{
136 item::CompletionKind,
137 test_utils::{check_edit, completion_list},
138 };
139
140 fn check(ra_fixture: &str, expect: Expect) {
141 let actual = completion_list(ra_fixture, CompletionKind::Magic);
142 expect.assert_eq(&actual);
143 }
144
145 #[test]
146 fn function_fuzzy_completion() {
147 check_edit(
148 "stdin",
149 r#"
150//- /lib.rs crate:dep
151pub mod io {
152 pub fn stdin() {}
153};
154
155//- /main.rs crate:main deps:dep
156fn main() {
157 stdi$0
158}
159"#,
160 r#"
161use dep::io::stdin;
162
163fn main() {
164 stdin()$0
165}
166"#,
167 );
168 }
169
170 #[test]
171 fn macro_fuzzy_completion() {
172 check_edit(
173 "macro_with_curlies!",
174 r#"
175//- /lib.rs crate:dep
176/// Please call me as macro_with_curlies! {}
177#[macro_export]
178macro_rules! macro_with_curlies {
179 () => {}
180}
181
182//- /main.rs crate:main deps:dep
183fn main() {
184 curli$0
185}
186"#,
187 r#"
188use dep::macro_with_curlies;
189
190fn main() {
191 macro_with_curlies! {$0}
192}
193"#,
194 );
195 }
196
197 #[test]
198 fn struct_fuzzy_completion() {
199 check_edit(
200 "ThirdStruct",
201 r#"
202//- /lib.rs crate:dep
203pub struct FirstStruct;
204pub mod some_module {
205 pub struct SecondStruct;
206 pub struct ThirdStruct;
207}
208
209//- /main.rs crate:main deps:dep
210use dep::{FirstStruct, some_module::SecondStruct};
211
212fn main() {
213 this$0
214}
215"#,
216 r#"
217use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
218
219fn main() {
220 ThirdStruct
221}
222"#,
223 );
224 }
225
226 #[test]
227 fn fuzzy_completions_come_in_specific_order() {
228 mark::check!(certain_fuzzy_order_test);
229 check(
230 r#"
231//- /lib.rs crate:dep
232pub struct FirstStruct;
233pub mod some_module {
234 // already imported, omitted
235 pub struct SecondStruct;
236 // does not contain all letters from the query, omitted
237 pub struct UnrelatedOne;
238 // contains all letters from the query, but not in sequence, displayed last
239 pub struct ThiiiiiirdStruct;
240 // contains all letters from the query, but not in the beginning, displayed second
241 pub struct AfterThirdStruct;
242 // contains all letters from the query in the begginning, displayed first
243 pub struct ThirdStruct;
244}
245
246//- /main.rs crate:main deps:dep
247use dep::{FirstStruct, some_module::SecondStruct};
248
249fn main() {
250 hir$0
251}
252"#,
253 expect![[r#"
254 st dep::some_module::ThirdStruct
255 st dep::some_module::AfterThirdStruct
256 st dep::some_module::ThiiiiiirdStruct
257 "#]],
258 );
259 }
260
261 #[test]
262 fn does_not_propose_names_in_scope() {
263 check(
264 r#"
265//- /lib.rs crate:dep
266pub mod test_mod {
267 pub trait TestTrait {
268 const SPECIAL_CONST: u8;
269 type HumbleType;
270 fn weird_function();
271 fn random_method(&self);
272 }
273 pub struct TestStruct {}
274 impl TestTrait for TestStruct {
275 const SPECIAL_CONST: u8 = 42;
276 type HumbleType = ();
277 fn weird_function() {}
278 fn random_method(&self) {}
279 }
280}
281
282//- /main.rs crate:main deps:dep
283use dep::test_mod::TestStruct;
284fn main() {
285 TestSt$0
286}
287"#,
288 expect![[r#""#]],
289 );
290 }
291}
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs
index 425a688ff..c1af348dc 100644
--- a/crates/completion/src/completions/keyword.rs
+++ b/crates/completion/src/completions/keyword.rs
@@ -1,6 +1,6 @@
1//! Completes keywords. 1//! Completes keywords.
2 2
3use syntax::{ast, SyntaxKind}; 3use syntax::SyntaxKind;
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
@@ -86,8 +86,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
86 add_keyword(ctx, acc, "match", "match $0 {}"); 86 add_keyword(ctx, acc, "match", "match $0 {}");
87 add_keyword(ctx, acc, "while", "while $0 {}"); 87 add_keyword(ctx, acc, "while", "while $0 {}");
88 add_keyword(ctx, acc, "loop", "loop {$0}"); 88 add_keyword(ctx, acc, "loop", "loop {$0}");
89 add_keyword(ctx, acc, "if", "if "); 89 add_keyword(ctx, acc, "if", "if $0 {}");
90 add_keyword(ctx, acc, "if let", "if let "); 90 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
91 } 91 }
92 92
93 if ctx.if_is_prev || ctx.block_expr_parent { 93 if ctx.if_is_prev || ctx.block_expr_parent {
@@ -143,47 +143,49 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
143 Some(it) => it, 143 Some(it) => it,
144 None => return, 144 None => return,
145 }; 145 };
146 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
147}
148
149fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
150 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
151 .kind(CompletionItemKind::Keyword);
152 146
153 match ctx.config.snippet_cap { 147 add_keyword(
154 Some(cap) => res.insert_snippet(cap, snippet), 148 ctx,
155 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }), 149 acc,
156 } 150 "return",
157 .build() 151 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
152 (true, true) => "return $0;",
153 (true, false) => "return;",
154 (false, true) => "return $0",
155 (false, false) => "return",
156 },
157 )
158} 158}
159 159
160fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { 160fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
161 acc.add(keyword(ctx, kw, snippet)); 161 let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
162} 162 .kind(CompletionItemKind::Keyword);
163 163 let builder = match ctx.config.snippet_cap {
164fn complete_return( 164 Some(cap) => {
165 ctx: &CompletionContext, 165 let tmp;
166 fn_def: &ast::Fn, 166 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
167 can_be_stmt: bool, 167 mark::hit!(let_semi);
168) -> Option<CompletionItem> { 168 tmp = format!("{};", snippet);
169 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { 169 &tmp
170 (true, true) => "return $0;", 170 } else {
171 (true, false) => "return;", 171 snippet
172 (false, true) => "return $0", 172 };
173 (false, false) => "return", 173 builder.insert_snippet(cap, snippet)
174 }
175 None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
174 }; 176 };
175 Some(keyword(ctx, "return", snip)) 177 acc.add(builder.build());
176} 178}
177 179
178#[cfg(test)] 180#[cfg(test)]
179mod tests { 181mod tests {
180 use expect_test::{expect, Expect}; 182 use expect_test::{expect, Expect};
183 use test_utils::mark;
181 184
182 use crate::{ 185 use crate::{
183 test_utils::{check_edit, completion_list}, 186 test_utils::{check_edit, completion_list},
184 CompletionKind, 187 CompletionKind,
185 }; 188 };
186 use test_utils::mark;
187 189
188 fn check(ra_fixture: &str, expect: Expect) { 190 fn check(ra_fixture: &str, expect: Expect) {
189 let actual = completion_list(ra_fixture, CompletionKind::Keyword); 191 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
@@ -609,4 +611,50 @@ fn foo() {
609 "#]], 611 "#]],
610 ); 612 );
611 } 613 }
614
615 #[test]
616 fn let_semi() {
617 mark::check!(let_semi);
618 check_edit(
619 "match",
620 r#"
621fn main() { let x = $0 }
622"#,
623 r#"
624fn main() { let x = match $0 {}; }
625"#,
626 );
627
628 check_edit(
629 "if",
630 r#"
631fn main() {
632 let x = $0
633 let y = 92;
634}
635"#,
636 r#"
637fn main() {
638 let x = if $0 {};
639 let y = 92;
640}
641"#,
642 );
643
644 check_edit(
645 "loop",
646 r#"
647fn main() {
648 let x = $0
649 bar();
650}
651"#,
652 r#"
653fn main() {
654 let x = loop {$0};
655 bar();
656}
657"#,
658 );
659 }
612} 660}
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 53e1391f3..ac5596ca4 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -2,17 +2,11 @@
2 2
3use std::iter; 3use std::iter;
4 4
5use either::Either; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
6use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type};
7use ide_db::helpers::insert_use::ImportScope;
8use ide_db::imports_locator;
9use syntax::AstNode; 6use syntax::AstNode;
10use test_utils::mark; 7use test_utils::mark;
11 8
12use crate::{ 9use crate::{CompletionContext, Completions};
13 render::{render_resolution_with_import, RenderContext},
14 CompletionContext, Completions, ImportEdit,
15};
16 10
17pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 11pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
18 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 12 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -45,10 +39,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
45 } 39 }
46 acc.add_resolution(ctx, name.to_string(), &res) 40 acc.add_resolution(ctx, name.to_string(), &res)
47 }); 41 });
48
49 if ctx.config.enable_autoimport_completions {
50 fuzzy_completion(acc, ctx);
51 }
52} 42}
53 43
54fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { 44fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
@@ -77,124 +67,13 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
77 } 67 }
78} 68}
79 69
80// Feature: Fuzzy Completion and Autoimports
81//
82// When completing names in the current scope, proposes additional imports from other modules or crates,
83// if they can be qualified in the scope and their name contains all symbols from the completion input
84// (case-insensitive, in any order or places).
85//
86// ```
87// fn main() {
88// pda$0
89// }
90// # pub mod std { pub mod marker { pub struct PhantomData { } } }
91// ```
92// ->
93// ```
94// use std::marker::PhantomData;
95//
96// fn main() {
97// PhantomData
98// }
99// # pub mod std { pub mod marker { pub struct PhantomData { } } }
100// ```
101//
102// .Fuzzy search details
103//
104// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
105// (i.e. in `HashMap` in the `std::collections::HashMap` path).
106// For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
107//
108// .Merge Behavior
109//
110// It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
111// Mimics the corresponding behavior of the `Auto Import` feature.
112//
113// .LSP and performance implications
114//
115// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
116// (case sensitive) resolve client capability in its client capabilities.
117// This way the server is able to defer the costly computations, doing them for a selected completion item only.
118// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
119// which might be slow ergo the feature is automatically disabled.
120//
121// .Feature toggle
122//
123// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
124// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
125// capability enabled.
126fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
127 let potential_import_name = ctx.token.to_string();
128 let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone());
129
130 if potential_import_name.len() < 2 {
131 return None;
132 }
133
134 let current_module = ctx.scope.module()?;
135 let anchor = ctx.name_ref_syntax.as_ref()?;
136 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
137
138 let user_input_lowercased = potential_import_name.to_lowercase();
139 let mut all_mod_paths = imports_locator::find_similar_imports(
140 &ctx.sema,
141 ctx.krate?,
142 Some(40),
143 potential_import_name,
144 true,
145 true,
146 )
147 .filter_map(|import_candidate| {
148 Some(match import_candidate {
149 Either::Left(module_def) => {
150 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
151 }
152 Either::Right(macro_def) => {
153 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
154 }
155 })
156 })
157 .filter(|(mod_path, _)| mod_path.len() > 1)
158 .collect::<Vec<_>>();
159
160 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
161 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
162 });
163
164 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
165 render_resolution_with_import(
166 RenderContext::new(ctx),
167 ImportEdit { import_path, import_scope: import_scope.clone() },
168 &definition,
169 )
170 }));
171 Some(())
172}
173
174fn compute_fuzzy_completion_order_key(
175 proposed_mod_path: &ModPath,
176 user_input_lowercased: &str,
177) -> usize {
178 mark::hit!(certain_fuzzy_order_test);
179 let proposed_import_name = match proposed_mod_path.segments.last() {
180 Some(name) => name.to_string().to_lowercase(),
181 None => return usize::MAX,
182 };
183 match proposed_import_name.match_indices(user_input_lowercased).next() {
184 Some((first_matching_index, _)) => first_matching_index,
185 None => usize::MAX,
186 }
187}
188
189#[cfg(test)] 70#[cfg(test)]
190mod tests { 71mod tests {
191 use expect_test::{expect, Expect}; 72 use expect_test::{expect, Expect};
192 use test_utils::mark; 73 use test_utils::mark;
193 74
194 use crate::{ 75 use crate::{
195 test_utils::{ 76 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
196 check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG,
197 },
198 CompletionConfig, CompletionKind, 77 CompletionConfig, CompletionKind,
199 }; 78 };
200 79
@@ -855,128 +734,4 @@ impl My$0
855 "#]], 734 "#]],
856 ) 735 )
857 } 736 }
858
859 #[test]
860 fn function_fuzzy_completion() {
861 check_edit_with_config(
862 TEST_CONFIG,
863 "stdin",
864 r#"
865//- /lib.rs crate:dep
866pub mod io {
867 pub fn stdin() {}
868};
869
870//- /main.rs crate:main deps:dep
871fn main() {
872 stdi$0
873}
874"#,
875 r#"
876use dep::io::stdin;
877
878fn main() {
879 stdin()$0
880}
881"#,
882 );
883 }
884
885 #[test]
886 fn macro_fuzzy_completion() {
887 check_edit_with_config(
888 TEST_CONFIG,
889 "macro_with_curlies!",
890 r#"
891//- /lib.rs crate:dep
892/// Please call me as macro_with_curlies! {}
893#[macro_export]
894macro_rules! macro_with_curlies {
895 () => {}
896}
897
898//- /main.rs crate:main deps:dep
899fn main() {
900 curli$0
901}
902"#,
903 r#"
904use dep::macro_with_curlies;
905
906fn main() {
907 macro_with_curlies! {$0}
908}
909"#,
910 );
911 }
912
913 #[test]
914 fn struct_fuzzy_completion() {
915 check_edit_with_config(
916 TEST_CONFIG,
917 "ThirdStruct",
918 r#"
919//- /lib.rs crate:dep
920pub struct FirstStruct;
921pub mod some_module {
922 pub struct SecondStruct;
923 pub struct ThirdStruct;
924}
925
926//- /main.rs crate:main deps:dep
927use dep::{FirstStruct, some_module::SecondStruct};
928
929fn main() {
930 this$0
931}
932"#,
933 r#"
934use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
935
936fn main() {
937 ThirdStruct
938}
939"#,
940 );
941 }
942
943 #[test]
944 fn fuzzy_completions_come_in_specific_order() {
945 mark::check!(certain_fuzzy_order_test);
946 check_with_config(
947 TEST_CONFIG,
948 r#"
949//- /lib.rs crate:dep
950pub struct FirstStruct;
951pub mod some_module {
952 // already imported, omitted
953 pub struct SecondStruct;
954 // does not contain all letters from the query, omitted
955 pub struct UnrelatedOne;
956 // contains all letters from the query, but not in sequence, displayed last
957 pub struct ThiiiiiirdStruct;
958 // contains all letters from the query, but not in the beginning, displayed second
959 pub struct AfterThirdStruct;
960 // contains all letters from the query in the begginning, displayed first
961 pub struct ThirdStruct;
962}
963
964//- /main.rs crate:main deps:dep
965use dep::{FirstStruct, some_module::SecondStruct};
966
967fn main() {
968 hir$0
969}
970"#,
971 expect![[r#"
972 fn main() fn main()
973 st SecondStruct
974 st FirstStruct
975 md dep
976 st dep::some_module::ThirdStruct
977 st dep::some_module::AfterThirdStruct
978 st dep::some_module::ThiiiiiirdStruct
979 "#]],
980 );
981 }
982} 737}
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index b4439b7d1..58fc700f3 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -4,7 +4,7 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! completions if we are allowed to. 5//! completions if we are allowed to.
6 6
7use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; 7use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct CompletionConfig { 10pub struct CompletionConfig {
@@ -13,5 +13,5 @@ pub struct CompletionConfig {
13 pub add_call_parenthesis: bool, 13 pub add_call_parenthesis: bool,
14 pub add_call_argument_snippets: bool, 14 pub add_call_argument_snippets: bool,
15 pub snippet_cap: Option<SnippetCap>, 15 pub snippet_cap: Option<SnippetCap>,
16 pub merge: Option<MergeBehavior>, 16 pub insert_use: InsertUseConfig,
17} 17}
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs
index ebf28e887..b1e8eba85 100644
--- a/crates/completion/src/context.rs
+++ b/crates/completion/src/context.rs
@@ -4,10 +4,8 @@ use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
4use ide_db::base_db::{FilePosition, SourceDatabase}; 4use ide_db::base_db::{FilePosition, SourceDatabase};
5use ide_db::{call_info::ActiveParameter, RootDatabase}; 5use ide_db::{call_info::ActiveParameter, RootDatabase};
6use syntax::{ 6use syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::find_node_at_offset, ast, match_ast, AstNode, NodeOrToken, SyntaxKind::*, SyntaxNode,
8 ast, match_ast, AstNode, NodeOrToken, 8 SyntaxToken, TextRange, TextSize,
9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 9};
12use test_utils::mark; 10use test_utils::mark;
13use text_edit::Indel; 11use text_edit::Indel;
@@ -92,6 +90,7 @@ pub(crate) struct CompletionContext<'a> {
92 pub(super) has_item_list_or_source_file_parent: bool, 90 pub(super) has_item_list_or_source_file_parent: bool,
93 pub(super) for_is_prev2: bool, 91 pub(super) for_is_prev2: bool,
94 pub(super) fn_is_prev: bool, 92 pub(super) fn_is_prev: bool,
93 pub(super) incomplete_let: bool,
95 pub(super) locals: Vec<(String, Local)>, 94 pub(super) locals: Vec<(String, Local)>,
96} 95}
97 96
@@ -132,9 +131,9 @@ impl<'a> CompletionContext<'a> {
132 scope, 131 scope,
133 db, 132 db,
134 config, 133 config,
134 position,
135 original_token, 135 original_token,
136 token, 136 token,
137 position,
138 krate, 137 krate,
139 expected_type: None, 138 expected_type: None,
140 name_ref_syntax: None, 139 name_ref_syntax: None,
@@ -155,30 +154,31 @@ impl<'a> CompletionContext<'a> {
155 is_expr: false, 154 is_expr: false,
156 is_new_item: false, 155 is_new_item: false,
157 dot_receiver: None, 156 dot_receiver: None,
157 dot_receiver_is_ambiguous_float_literal: false,
158 is_call: false, 158 is_call: false,
159 is_pattern_call: false, 159 is_pattern_call: false,
160 is_macro_call: false, 160 is_macro_call: false,
161 is_path_type: false, 161 is_path_type: false,
162 has_type_args: false, 162 has_type_args: false,
163 dot_receiver_is_ambiguous_float_literal: false,
164 attribute_under_caret: None, 163 attribute_under_caret: None,
165 mod_declaration_under_caret: None, 164 mod_declaration_under_caret: None,
166 unsafe_is_prev: false, 165 unsafe_is_prev: false,
167 in_loop_body: false, 166 if_is_prev: false,
168 ref_pat_parent: false,
169 bind_pat_parent: false,
170 block_expr_parent: false, 167 block_expr_parent: false,
168 bind_pat_parent: false,
169 ref_pat_parent: false,
170 in_loop_body: false,
171 has_trait_parent: false, 171 has_trait_parent: false,
172 has_impl_parent: false, 172 has_impl_parent: false,
173 inside_impl_trait_block: false, 173 inside_impl_trait_block: false,
174 has_field_list_parent: false, 174 has_field_list_parent: false,
175 trait_as_prev_sibling: false, 175 trait_as_prev_sibling: false,
176 impl_as_prev_sibling: false, 176 impl_as_prev_sibling: false,
177 if_is_prev: false,
178 is_match_arm: false, 177 is_match_arm: false,
179 has_item_list_or_source_file_parent: false, 178 has_item_list_or_source_file_parent: false,
180 for_is_prev2: false, 179 for_is_prev2: false,
181 fn_is_prev: false, 180 fn_is_prev: false,
181 incomplete_let: false,
182 locals, 182 locals,
183 }; 183 };
184 184
@@ -270,6 +270,10 @@ impl<'a> CompletionContext<'a> {
270 .filter(|module| module.item_list().is_none()); 270 .filter(|module| module.item_list().is_none());
271 self.for_is_prev2 = for_is_prev2(syntax_element.clone()); 271 self.for_is_prev2 = for_is_prev2(syntax_element.clone());
272 self.fn_is_prev = fn_is_prev(syntax_element.clone()); 272 self.fn_is_prev = fn_is_prev(syntax_element.clone());
273 self.incomplete_let =
274 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
275 it.syntax().text_range().end() == syntax_element.text_range().end()
276 });
273 } 277 }
274 278
275 fn fill( 279 fn fill(
@@ -507,7 +511,7 @@ impl<'a> CompletionContext<'a> {
507} 511}
508 512
509fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { 513fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
510 find_covering_element(syntax, range).ancestors().find_map(N::cast) 514 syntax.covering_element(range).ancestors().find_map(N::cast)
511} 515}
512 516
513fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { 517fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 6cba88a6b..ee1b822e7 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -127,6 +127,7 @@ pub fn completions(
127 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); 127 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
128 completions::trait_impl::complete_trait_impl(&mut acc, &ctx); 128 completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
129 completions::mod_::complete_mod(&mut acc, &ctx); 129 completions::mod_::complete_mod(&mut acc, &ctx);
130 completions::flyimport::import_on_the_fly(&mut acc, &ctx);
130 131
131 Some(acc) 132 Some(acc)
132} 133}
@@ -153,7 +154,9 @@ pub fn resolve_completion_edits(
153 }) 154 })
154 .find(|mod_path| mod_path.to_string() == full_import_path)?; 155 .find(|mod_path| mod_path.to_string() == full_import_path)?;
155 156
156 ImportEdit { import_path, import_scope }.to_text_edit(config.merge).map(|edit| vec![edit]) 157 ImportEdit { import_path, import_scope }
158 .to_text_edit(config.insert_use.merge)
159 .map(|edit| vec![edit])
157} 160}
158 161
159#[cfg(test)] 162#[cfg(test)]
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index e93c59f71..820dd01d1 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -51,11 +51,16 @@ pub(crate) fn render_resolution_with_import<'a>(
51 import_edit: ImportEdit, 51 import_edit: ImportEdit,
52 resolution: &ScopeDef, 52 resolution: &ScopeDef,
53) -> Option<CompletionItem> { 53) -> Option<CompletionItem> {
54 Render::new(ctx).render_resolution( 54 Render::new(ctx)
55 import_edit.import_path.segments.last()?.to_string(), 55 .render_resolution(
56 Some(import_edit), 56 import_edit.import_path.segments.last()?.to_string(),
57 resolution, 57 Some(import_edit),
58 ) 58 resolution,
59 )
60 .map(|mut item| {
61 item.completion_kind = CompletionKind::Magic;
62 item
63 })
59} 64}
60 65
61/// Interface for data and methods required for items rendering. 66/// Interface for data and methods required for items rendering.
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index 3f4b9d4ac..6ea6da989 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -1,9 +1,12 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics; 3use hir::{PrefixKind, Semantics};
4use ide_db::{ 4use ide_db::{
5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, 5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
6 helpers::{insert_use::MergeBehavior, SnippetCap}, 6 helpers::{
7 insert_use::{InsertUseConfig, MergeBehavior},
8 SnippetCap,
9 },
7 RootDatabase, 10 RootDatabase,
8}; 11};
9use itertools::Itertools; 12use itertools::Itertools;
@@ -19,7 +22,10 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
19 add_call_parenthesis: true, 22 add_call_parenthesis: true,
20 add_call_argument_snippets: true, 23 add_call_argument_snippets: true,
21 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
22 merge: Some(MergeBehavior::Full), 25 insert_use: InsertUseConfig {
26 merge: Some(MergeBehavior::Full),
27 prefix_kind: PrefixKind::Plain,
28 },
23}; 29};
24 30
25/// Creates analysis from a multi-file fixture, returns positions marked with $0. 31/// Creates analysis from a multi-file fixture, returns positions marked with $0.
@@ -110,7 +116,7 @@ pub(crate) fn check_edit_with_config(
110 116
111 let mut combined_edit = completion.text_edit().to_owned(); 117 let mut combined_edit = completion.text_edit().to_owned();
112 if let Some(import_text_edit) = 118 if let Some(import_text_edit) =
113 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.merge)) 119 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge))
114 { 120 {
115 combined_edit.union(import_text_edit).expect( 121 combined_edit.union(import_text_edit).expect(
116 "Failed to apply completion resolve changes: change ranges overlap, but should not", 122 "Failed to apply completion resolve changes: change ranges overlap, but should not",
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index cd689c869..ab213e04c 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -750,6 +750,7 @@ to_def_impls![
750 (crate::ConstParam, ast::ConstParam, const_param_to_def), 750 (crate::ConstParam, ast::ConstParam, const_param_to_def),
751 (crate::MacroDef, ast::MacroRules, macro_rules_to_def), 751 (crate::MacroDef, ast::MacroRules, macro_rules_to_def),
752 (crate::Local, ast::IdentPat, bind_pat_to_def), 752 (crate::Local, ast::IdentPat, bind_pat_to_def),
753 (crate::Local, ast::SelfParam, self_param_to_def),
753 (crate::Label, ast::Label, label_to_def), 754 (crate::Label, ast::Label, label_to_def),
754]; 755];
755 756
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 4b9ebff72..9bf60c72a 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -114,6 +114,15 @@ impl SourceToDefCtx<'_, '_> {
114 let pat_id = source_map.node_pat(src.as_ref())?; 114 let pat_id = source_map.node_pat(src.as_ref())?;
115 Some((container, pat_id)) 115 Some((container, pat_id))
116 } 116 }
117 pub(super) fn self_param_to_def(
118 &mut self,
119 src: InFile<ast::SelfParam>,
120 ) -> Option<(DefWithBodyId, PatId)> {
121 let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?;
122 let (_body, source_map) = self.db.body_with_source_map(container);
123 let pat_id = source_map.node_self_param(src.as_ref())?;
124 Some((container, pat_id))
125 }
117 pub(super) fn label_to_def( 126 pub(super) fn label_to_def(
118 &mut self, 127 &mut self,
119 src: InFile<ast::Label>, 128 src: InFile<ast::Label>,
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 27575c537..4ce5e5b72 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -386,6 +386,10 @@ impl ExprCollector<'_> {
386 let expr = e.expr().map(|e| self.collect_expr(e)); 386 let expr = e.expr().map(|e| self.collect_expr(e));
387 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 387 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
388 } 388 }
389 ast::Expr::YieldExpr(e) => {
390 let expr = e.expr().map(|e| self.collect_expr(e));
391 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
392 }
389 ast::Expr::RecordExpr(e) => { 393 ast::Expr::RecordExpr(e) => {
390 let path = e.path().and_then(|path| self.expander.parse_path(path)); 394 let path = e.path().and_then(|path| self.expander.parse_path(path));
391 let mut field_ptrs = Vec::new(); 395 let mut field_ptrs = Vec::new();
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index af01d32dc..a293df9f1 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -99,6 +99,9 @@ pub enum Expr {
99 Return { 99 Return {
100 expr: Option<ExprId>, 100 expr: Option<ExprId>,
101 }, 101 },
102 Yield {
103 expr: Option<ExprId>,
104 },
102 RecordLit { 105 RecordLit {
103 path: Option<Path>, 106 path: Option<Path>,
104 fields: Vec<RecordLitField>, 107 fields: Vec<RecordLitField>,
@@ -294,7 +297,7 @@ impl Expr {
294 } 297 }
295 } 298 }
296 Expr::Continue { .. } => {} 299 Expr::Continue { .. } => {}
297 Expr::Break { expr, .. } | Expr::Return { expr } => { 300 Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
298 if let Some(expr) = expr { 301 if let Some(expr) = expr {
299 f(*expr); 302 f(*expr);
300 } 303 }
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 61059c349..85ddc2c47 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -258,7 +258,7 @@ impl Resolver {
258 ) -> Option<ResolveValueResult> { 258 ) -> Option<ResolveValueResult> {
259 let n_segments = path.segments.len(); 259 let n_segments = path.segments.len();
260 let tmp = name![self]; 260 let tmp = name![self];
261 let first_name = if path.is_self() { &tmp } else { &path.segments.first()? }; 261 let first_name = if path.is_self() { &tmp } else { path.segments.first()? };
262 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 262 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
263 for scope in self.scopes.iter().rev() { 263 for scope in self.scopes.iter().rev() {
264 match scope { 264 match scope {
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs
index f4f6e11fd..2401b0cc5 100644
--- a/crates/hir_expand/src/ast_id_map.rs
+++ b/crates/hir_expand/src/ast_id_map.rs
@@ -72,10 +72,12 @@ impl AstIdMap {
72 // get lower ids then children. That is, adding a new child does not 72 // get lower ids then children. That is, adding a new child does not
73 // change parent's id. This means that, say, adding a new function to a 73 // change parent's id. This means that, say, adding a new function to a
74 // trait does not change ids of top-level items, which helps caching. 74 // trait does not change ids of top-level items, which helps caching.
75 bfs(node, |it| { 75 bdfs(node, |it| match ast::Item::cast(it) {
76 if let Some(module_item) = ast::Item::cast(it) { 76 Some(module_item) => {
77 res.alloc(module_item.syntax()); 77 res.alloc(module_item.syntax());
78 true
78 } 79 }
80 None => false,
79 }); 81 });
80 res 82 res
81 } 83 }
@@ -105,14 +107,30 @@ impl AstIdMap {
105 } 107 }
106} 108}
107 109
108/// Walks the subtree in bfs order, calling `f` for each node. 110/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
109fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { 111/// order? It is a mix of breadth-first and depth first orders. Nodes for which
112/// `f` returns true are visited breadth-first, all the other nodes are explored
113/// depth-first.
114///
115/// In other words, the size of the bfs queue is bound by the number of "true"
116/// nodes.
117fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) {
110 let mut curr_layer = vec![node.clone()]; 118 let mut curr_layer = vec![node.clone()];
111 let mut next_layer = vec![]; 119 let mut next_layer = vec![];
112 while !curr_layer.is_empty() { 120 while !curr_layer.is_empty() {
113 curr_layer.drain(..).for_each(|node| { 121 curr_layer.drain(..).for_each(|node| {
114 next_layer.extend(node.children()); 122 let mut preorder = node.preorder();
115 f(node); 123 while let Some(event) = preorder.next() {
124 match event {
125 syntax::WalkEvent::Enter(node) => {
126 if f(node.clone()) {
127 next_layer.extend(node.children());
128 preorder.skip_subtree();
129 }
130 }
131 syntax::WalkEvent::Leave(_) => {}
132 }
133 }
116 }); 134 });
117 std::mem::swap(&mut curr_layer, &mut next_layer); 135 std::mem::swap(&mut curr_layer, &mut next_layer);
118 } 136 }
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index c62086390..467516eb7 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -118,7 +118,7 @@ pub fn expand_hypothetical(
118 parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1)))).value?; 118 parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1)))).value?;
119 let token_id = macro_def.0.map_id_down(token_id); 119 let token_id = macro_def.0.map_id_down(token_id);
120 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; 120 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?;
121 let token = syntax::algo::find_covering_element(&node.syntax_node(), range).into_token()?; 121 let token = node.syntax_node().covering_element(range).into_token()?;
122 Some((node.syntax_node(), token)) 122 Some((node.syntax_node(), token))
123} 123}
124 124
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 3fa1b1d77..e388ddacc 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -22,7 +22,7 @@ use std::sync::Arc;
22 22
23use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange}; 23use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
24use syntax::{ 24use syntax::{
25 algo::{self, skip_trivia_token}, 25 algo::skip_trivia_token,
26 ast::{self, AstNode}, 26 ast::{self, AstNode},
27 Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, 27 Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
28}; 28};
@@ -335,7 +335,7 @@ impl ExpansionInfo {
335 335
336 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 336 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
337 337
338 let token = algo::find_covering_element(&self.expanded.value, range).into_token()?; 338 let token = self.expanded.value.covering_element(range).into_token()?;
339 339
340 Some(self.expanded.with_value(token)) 340 Some(self.expanded.with_value(token))
341 } 341 }
@@ -360,8 +360,8 @@ impl ExpansionInfo {
360 }; 360 };
361 361
362 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 362 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
363 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) 363 let token =
364 .into_token()?; 364 tt.value.covering_element(range + tt.value.text_range().start()).into_token()?;
365 Some((tt.with_value(token), origin)) 365 Some((tt.with_value(token), origin))
366 } 366 }
367} 367}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index f2fc69b2f..9bf3b51b0 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -367,6 +367,13 @@ impl<'a> InferenceContext<'a> {
367 } 367 }
368 Ty::simple(TypeCtor::Never) 368 Ty::simple(TypeCtor::Never)
369 } 369 }
370 Expr::Yield { expr } => {
371 // FIXME: track yield type for coercion
372 if let Some(expr) = expr {
373 self.infer_expr(*expr, &Expectation::none());
374 }
375 Ty::simple(TypeCtor::Never)
376 }
370 Expr::RecordLit { path, fields, spread } => { 377 Expr::RecordLit { path, fields, spread } => {
371 let (ty, def_id) = self.resolve_variant(path.as_ref()); 378 let (ty, def_id) = self.resolve_variant(path.as_ref());
372 if let Some(variant) = def_id { 379 if let Some(variant) = def_id {
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 2e5395b51..b35bc2bae 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -18,7 +18,7 @@ use itertools::Itertools;
18use rustc_hash::FxHashSet; 18use rustc_hash::FxHashSet;
19use syntax::{ 19use syntax::{
20 ast::{self, AstNode}, 20 ast::{self, AstNode},
21 SyntaxNode, TextRange, T, 21 SyntaxNode, TextRange,
22}; 22};
23use text_edit::TextEdit; 23use text_edit::TextEdit;
24 24
@@ -232,7 +232,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
232 single_use_tree: &ast::UseTree, 232 single_use_tree: &ast::UseTree,
233) -> Option<TextEdit> { 233) -> Option<TextEdit> {
234 let use_tree_list_node = single_use_tree.syntax().parent()?; 234 let use_tree_list_node = single_use_tree.syntax().parent()?;
235 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { 235 if single_use_tree.path()?.segment()?.self_token().is_some() {
236 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); 236 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
237 let end = use_tree_list_node.text_range().end(); 237 let end = use_tree_list_node.text_range().end();
238 return Some(TextEdit::delete(TextRange::new(start, end))); 238 return Some(TextEdit::delete(TextRange::new(start, end)));
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 4eecae697..685052e7f 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -400,24 +400,33 @@ impl TryToNav for hir::GenericParam {
400impl ToNav for hir::Local { 400impl ToNav for hir::Local {
401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
402 let src = self.source(db); 402 let src = self.source(db);
403 let node = match &src.value { 403 let (node, focus_range) = match &src.value {
404 Either::Left(bind_pat) => { 404 Either::Left(bind_pat) => (
405 bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone()) 405 bind_pat.syntax().clone(),
406 } 406 bind_pat
407 Either::Right(it) => it.syntax().clone(), 407 .name()
408 .map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range),
409 ),
410 Either::Right(it) => (it.syntax().clone(), it.self_token().map(|it| it.text_range())),
408 }; 411 };
409 let full_range = src.with_value(&node).original_file_range(db); 412 let full_range = src.with_value(&node).original_file_range(db);
410 let name = match self.name(db) { 413 let name = match self.name(db) {
411 Some(it) => it.to_string().into(), 414 Some(it) => it.to_string().into(),
412 None => "".into(), 415 None => "".into(),
413 }; 416 };
414 let kind = if self.is_param(db) { SymbolKind::ValueParam } else { SymbolKind::Local }; 417 let kind = if self.is_self(db) {
418 SymbolKind::SelfParam
419 } else if self.is_param(db) {
420 SymbolKind::ValueParam
421 } else {
422 SymbolKind::Local
423 };
415 NavigationTarget { 424 NavigationTarget {
416 file_id: full_range.file_id, 425 file_id: full_range.file_id,
417 name, 426 name,
418 kind: Some(kind), 427 kind: Some(kind),
419 full_range: full_range.range, 428 full_range: full_range.range,
420 focus_range: None, 429 focus_range,
421 container_name: None, 430 container_name: None,
422 description: None, 431 description: None,
423 docs: None, 432 docs: None,
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index 56418c960..17a540972 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use syntax::{ 5use syntax::{
6 algo::{self, find_covering_element, skip_trivia_token}, 6 algo::{self, skip_trivia_token},
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken},
8 Direction, NodeOrToken, 8 Direction, NodeOrToken,
9 SyntaxKind::{self, *}, 9 SyntaxKind::{self, *},
@@ -76,7 +76,7 @@ fn try_extend_selection(
76 }; 76 };
77 return Some(leaf_range); 77 return Some(leaf_range);
78 }; 78 };
79 let node = match find_covering_element(root, range) { 79 let node = match root.covering_element(range) {
80 NodeOrToken::Token(token) => { 80 NodeOrToken::Token(token) => {
81 if token.text_range() != range { 81 if token.text_range() != range {
82 return Some(token.text_range()); 82 return Some(token.text_range());
@@ -120,7 +120,7 @@ fn extend_tokens_from_range(
120 macro_call: ast::MacroCall, 120 macro_call: ast::MacroCall,
121 original_range: TextRange, 121 original_range: TextRange,
122) -> Option<TextRange> { 122) -> Option<TextRange> {
123 let src = find_covering_element(&macro_call.syntax(), original_range); 123 let src = macro_call.syntax().covering_element(original_range);
124 let (first_token, last_token) = match src { 124 let (first_token, last_token) = match src {
125 NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?), 125 NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?),
126 NodeOrToken::Token(it) => (it.clone(), it), 126 NodeOrToken::Token(it) => (it.clone(), it),
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index cd4afc804..988a5668f 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,7 +1,6 @@
1use either::Either; 1use either::Either;
2use hir::{HasAttrs, ModuleDef, Semantics}; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 base_db::FileId,
5 defs::{Definition, NameClass, NameRefClass}, 4 defs::{Definition, NameClass, NameRefClass},
6 symbol_index, RootDatabase, 5 symbol_index, RootDatabase,
7}; 6};
@@ -13,7 +12,7 @@ use crate::{
13 display::{ToNav, TryToNav}, 12 display::{ToNav, TryToNav},
14 doc_links::extract_definitions_from_markdown, 13 doc_links::extract_definitions_from_markdown,
15 runnables::doc_owner_to_def, 14 runnables::doc_owner_to_def,
16 FilePosition, NavigationTarget, RangeInfo, SymbolKind, 15 FilePosition, NavigationTarget, RangeInfo,
17}; 16};
18 17
19// Feature: Go to Definition 18// Feature: Go to Definition
@@ -49,19 +48,6 @@ pub(crate) fn goto_definition(
49 let nav = def.try_to_nav(sema.db)?; 48 let nav = def.try_to_nav(sema.db)?;
50 vec![nav] 49 vec![nav]
51 }, 50 },
52 ast::SelfParam(self_param) => {
53 vec![self_to_nav_target(self_param, position.file_id)?]
54 },
55 ast::PathSegment(segment) => {
56 segment.self_token()?;
57 let path = segment.parent_path();
58 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
59 return None;
60 }
61 let func = segment.syntax().ancestors().find_map(ast::Fn::cast)?;
62 let self_param = func.param_list()?.self_param()?;
63 vec![self_to_nav_target(self_param, position.file_id)?]
64 },
65 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { 51 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
66 let def = name_class.referenced_or_defined(sema.db); 52 let def = name_class.referenced_or_defined(sema.db);
67 let nav = def.try_to_nav(sema.db)?; 53 let nav = def.try_to_nav(sema.db)?;
@@ -69,6 +55,11 @@ pub(crate) fn goto_definition(
69 } else { 55 } else {
70 reference_definition(&sema, Either::Left(&lt)).to_vec() 56 reference_definition(&sema, Either::Left(&lt)).to_vec()
71 }, 57 },
58 ast::SelfParam(self_param) => {
59 let def = NameClass::classify_self_param(&sema, &self_param)?.referenced_or_defined(sema.db);
60 let nav = def.try_to_nav(sema.db)?;
61 vec![nav]
62 },
72 _ => return None, 63 _ => return None,
73 } 64 }
74 }; 65 };
@@ -134,20 +125,6 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
134 } 125 }
135} 126}
136 127
137fn self_to_nav_target(self_param: ast::SelfParam, file_id: FileId) -> Option<NavigationTarget> {
138 let self_token = self_param.self_token()?;
139 Some(NavigationTarget {
140 file_id,
141 full_range: self_param.syntax().text_range(),
142 focus_range: Some(self_token.text_range()),
143 name: self_token.text().clone(),
144 kind: Some(SymbolKind::SelfParam),
145 container_name: None,
146 description: None,
147 docs: None,
148 })
149}
150
151#[derive(Debug)] 128#[derive(Debug)]
152pub(crate) enum ReferenceResult { 129pub(crate) enum ReferenceResult {
153 Exact(NavigationTarget), 130 Exact(NavigationTarget),
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 317b6f011..6022bd275 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -98,6 +98,7 @@ pub(crate) fn hover(
98 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 98 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
99 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) 99 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime)
100 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), 100 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)),
101 ast::SelfParam(self_param) => NameClass::classify_self_param(&sema, &self_param).and_then(|d| d.defined(sema.db)),
101 _ => None, 102 _ => None,
102 } 103 }
103 }; 104 };
@@ -134,17 +135,14 @@ pub(crate) fn hover(
134 return None; 135 return None;
135 } 136 }
136 137
137 let node = token.ancestors().find(|n| { 138 let node = token
138 ast::Expr::can_cast(n.kind()) 139 .ancestors()
139 || ast::Pat::can_cast(n.kind()) 140 .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
140 || ast::SelfParam::can_cast(n.kind())
141 })?;
142 141
143 let ty = match_ast! { 142 let ty = match_ast! {
144 match node { 143 match node {
145 ast::Expr(it) => sema.type_of_expr(&it)?, 144 ast::Expr(it) => sema.type_of_expr(&it)?,
146 ast::Pat(it) => sema.type_of_pat(&it)?, 145 ast::Pat(it) => sema.type_of_pat(&it)?,
147 ast::SelfParam(self_param) => sema.type_of_self(&self_param)?,
148 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. 146 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
149 // (e.g expanding a builtin macro). So we give up here. 147 // (e.g expanding a builtin macro). So we give up here.
150 ast::MacroCall(_it) => return None, 148 ast::MacroCall(_it) => return None,
@@ -386,7 +384,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
386 return tokens.max_by_key(priority); 384 return tokens.max_by_key(priority);
387 fn priority(n: &SyntaxToken) -> usize { 385 fn priority(n: &SyntaxToken) -> usize {
388 match n.kind() { 386 match n.kind() {
389 IDENT | INT_NUMBER | LIFETIME_IDENT => 3, 387 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 3,
390 T!['('] | T![')'] => 2, 388 T!['('] | T![')'] => 2,
391 kind if kind.is_trivia() => 0, 389 kind if kind.is_trivia() => 0,
392 _ => 1, 390 _ => 1,
@@ -3130,6 +3128,39 @@ fn foo<T: Foo>(t: T$0){}
3130 } 3128 }
3131 3129
3132 #[test] 3130 #[test]
3131 fn test_hover_self_has_go_to_type() {
3132 check_actions(
3133 r#"
3134struct Foo;
3135impl Foo {
3136 fn foo(&self$0) {}
3137}
3138"#,
3139 expect![[r#"
3140 [
3141 GoToType(
3142 [
3143 HoverGotoTypeData {
3144 mod_path: "test::Foo",
3145 nav: NavigationTarget {
3146 file_id: FileId(
3147 0,
3148 ),
3149 full_range: 0..11,
3150 focus_range: 7..10,
3151 name: "Foo",
3152 kind: Struct,
3153 description: "struct Foo",
3154 },
3155 },
3156 ],
3157 ),
3158 ]
3159 "#]],
3160 );
3161 }
3162
3163 #[test]
3133 fn hover_displays_normalized_crate_names() { 3164 fn hover_displays_normalized_crate_names() {
3134 check( 3165 check(
3135 r#" 3166 r#"
@@ -3193,6 +3224,7 @@ impl Foo {
3193"#, 3224"#,
3194 expect![[r#" 3225 expect![[r#"
3195 *&self* 3226 *&self*
3227
3196 ```rust 3228 ```rust
3197 &Foo 3229 &Foo
3198 ``` 3230 ```
@@ -3212,6 +3244,7 @@ impl Foo {
3212"#, 3244"#,
3213 expect![[r#" 3245 expect![[r#"
3214 *self: Arc<Foo>* 3246 *self: Arc<Foo>*
3247
3215 ```rust 3248 ```rust
3216 Arc<Foo> 3249 Arc<Foo>
3217 ``` 3250 ```
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 05380f2a1..981467c8d 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -1,7 +1,7 @@
1use assists::utils::extract_trivial_expression; 1use assists::utils::extract_trivial_expression;
2use itertools::Itertools; 2use itertools::Itertools;
3use syntax::{ 3use syntax::{
4 algo::{find_covering_element, non_trivia_sibling}, 4 algo::non_trivia_sibling,
5 ast::{self, AstNode, AstToken}, 5 ast::{self, AstNode, AstToken},
6 Direction, NodeOrToken, SourceFile, 6 Direction, NodeOrToken, SourceFile,
7 SyntaxKind::{self, USE_TREE, WHITESPACE}, 7 SyntaxKind::{self, USE_TREE, WHITESPACE},
@@ -31,7 +31,7 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
31 range 31 range
32 }; 32 };
33 33
34 let node = match find_covering_element(file.syntax(), range) { 34 let node = match file.syntax().covering_element(range) {
35 NodeOrToken::Node(node) => node, 35 NodeOrToken::Node(node) => node,
36 NodeOrToken::Token(token) => token.parent(), 36 NodeOrToken::Token(token) => token.parent(),
37 }; 37 };
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index afd552008..f8d69382e 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -80,7 +80,7 @@ pub use crate::{
80 HlRange, 80 HlRange,
81 }, 81 },
82}; 82};
83pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; 83pub use assists::{Assist, AssistConfig, AssistId, AssistKind};
84pub use completion::{ 84pub use completion::{
85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, 85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit,
86 InsertTextFormat, 86 InsertTextFormat,
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 7d4757e02..51a2f4327 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -11,6 +11,7 @@
11 11
12pub(crate) mod rename; 12pub(crate) mod rename;
13 13
14use either::Either;
14use hir::Semantics; 15use hir::Semantics;
15use ide_db::{ 16use ide_db::{
16 base_db::FileId, 17 base_db::FileId,
@@ -21,10 +22,10 @@ use ide_db::{
21use syntax::{ 22use syntax::{
22 algo::find_node_at_offset, 23 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 24 ast::{self, NameOwner},
24 match_ast, AstNode, SyntaxNode, TextRange, TokenAtOffset, T, 25 AstNode, SyntaxNode, TextRange, TokenAtOffset, T,
25}; 26};
26 27
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; 28use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
28 29
29#[derive(Debug, Clone)] 30#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 31pub struct ReferenceSearchResult {
@@ -90,10 +91,6 @@ pub(crate) fn find_all_refs(
90 let _p = profile::span("find_all_refs"); 91 let _p = profile::span("find_all_refs");
91 let syntax = sema.parse(position.file_id).syntax().clone(); 92 let syntax = sema.parse(position.file_id).syntax().clone();
92 93
93 if let Some(res) = try_find_self_references(&syntax, position) {
94 return Some(res);
95 }
96
97 let (opt_name, search_kind) = if let Some(name) = 94 let (opt_name, search_kind) = if let Some(name) =
98 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) 95 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
99 { 96 {
@@ -122,13 +119,16 @@ pub(crate) fn find_all_refs(
122 119
123 let mut kind = ReferenceKind::Other; 120 let mut kind = ReferenceKind::Other;
124 if let Definition::Local(local) = def { 121 if let Definition::Local(local) = def {
125 if let either::Either::Left(pat) = local.source(sema.db).value { 122 match local.source(sema.db).value {
126 if matches!( 123 Either::Left(pat) => {
127 pat.syntax().parent().and_then(ast::RecordPatField::cast), 124 if matches!(
128 Some(pat_field) if pat_field.name_ref().is_none() 125 pat.syntax().parent().and_then(ast::RecordPatField::cast),
129 ) { 126 Some(pat_field) if pat_field.name_ref().is_none()
130 kind = ReferenceKind::FieldShorthandForLocal; 127 ) {
128 kind = ReferenceKind::FieldShorthandForLocal;
129 }
131 } 130 }
131 Either::Right(_) => kind = ReferenceKind::SelfParam,
132 } 132 }
133 } else if matches!( 133 } else if matches!(
134 def, 134 def,
@@ -251,79 +251,6 @@ fn get_enum_def_name_for_struct_literal_search(
251 None 251 None
252} 252}
253 253
254fn try_find_self_references(
255 syntax: &SyntaxNode,
256 position: FilePosition,
257) -> Option<RangeInfo<ReferenceSearchResult>> {
258 let FilePosition { file_id, offset } = position;
259 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
260 let parent = self_token.parent();
261 match_ast! {
262 match parent {
263 ast::SelfParam(it) => (),
264 ast::PathSegment(segment) => {
265 segment.self_token()?;
266 let path = segment.parent_path();
267 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
268 return None;
269 }
270 },
271 _ => return None,
272 }
273 };
274 let function = parent.ancestors().find_map(ast::Fn::cast)?;
275 let self_param = function.param_list()?.self_param()?;
276 let param_self_token = self_param.self_token()?;
277
278 let declaration = Declaration {
279 nav: NavigationTarget {
280 file_id,
281 full_range: self_param.syntax().text_range(),
282 focus_range: Some(param_self_token.text_range()),
283 name: param_self_token.text().clone(),
284 kind: Some(SymbolKind::SelfParam),
285 container_name: None,
286 description: None,
287 docs: None,
288 },
289 kind: ReferenceKind::SelfKw,
290 access: Some(if self_param.mut_token().is_some() {
291 ReferenceAccess::Write
292 } else {
293 ReferenceAccess::Read
294 }),
295 };
296 let refs = function
297 .body()
298 .map(|body| {
299 body.syntax()
300 .descendants()
301 .filter_map(ast::PathExpr::cast)
302 .filter_map(|expr| {
303 let path = expr.path()?;
304 if path.qualifier().is_none() {
305 path.segment()?.self_token()
306 } else {
307 None
308 }
309 })
310 .map(|token| FileReference {
311 range: token.text_range(),
312 kind: ReferenceKind::SelfKw,
313 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
314 })
315 .collect()
316 })
317 .unwrap_or_default();
318 let mut references = UsageSearchResult::default();
319 references.references.insert(file_id, refs);
320
321 Some(RangeInfo::new(
322 param_self_token.text_range(),
323 ReferenceSearchResult { declaration, references },
324 ))
325}
326
327#[cfg(test)] 254#[cfg(test)]
328mod tests { 255mod tests {
329 use expect_test::{expect, Expect}; 256 use expect_test::{expect, Expect};
@@ -512,7 +439,7 @@ fn main() {
512 i = 5; 439 i = 5;
513}"#, 440}"#,
514 expect![[r#" 441 expect![[r#"
515 i Local FileId(0) 24..25 Other Write 442 i Local FileId(0) 20..25 24..25 Other Write
516 443
517 FileId(0) 50..51 Other Write 444 FileId(0) 50..51 Other Write
518 FileId(0) 54..55 Other Read 445 FileId(0) 54..55 Other Read
@@ -536,7 +463,7 @@ fn bar() {
536} 463}
537"#, 464"#,
538 expect![[r#" 465 expect![[r#"
539 spam Local FileId(0) 19..23 Other 466 spam Local FileId(0) 19..23 19..23 Other
540 467
541 FileId(0) 34..38 Other Read 468 FileId(0) 34..38 Other Read
542 FileId(0) 41..45 Other Read 469 FileId(0) 41..45 Other Read
@@ -551,7 +478,7 @@ fn bar() {
551fn foo(i : u32) -> u32 { i$0 } 478fn foo(i : u32) -> u32 { i$0 }
552"#, 479"#,
553 expect![[r#" 480 expect![[r#"
554 i ValueParam FileId(0) 7..8 Other 481 i ValueParam FileId(0) 7..8 7..8 Other
555 482
556 FileId(0) 25..26 Other Read 483 FileId(0) 25..26 Other Read
557 "#]], 484 "#]],
@@ -565,7 +492,7 @@ fn foo(i : u32) -> u32 { i$0 }
565fn foo(i$0 : u32) -> u32 { i } 492fn foo(i$0 : u32) -> u32 { i }
566"#, 493"#,
567 expect![[r#" 494 expect![[r#"
568 i ValueParam FileId(0) 7..8 Other 495 i ValueParam FileId(0) 7..8 7..8 Other
569 496
570 FileId(0) 25..26 Other Read 497 FileId(0) 25..26 Other Read
571 "#]], 498 "#]],
@@ -813,7 +740,7 @@ fn foo() {
813} 740}
814"#, 741"#,
815 expect![[r#" 742 expect![[r#"
816 i Local FileId(0) 23..24 Other Write 743 i Local FileId(0) 19..24 23..24 Other Write
817 744
818 FileId(0) 34..35 Other Write 745 FileId(0) 34..35 Other Write
819 FileId(0) 38..39 Other Read 746 FileId(0) 38..39 Other Read
@@ -853,7 +780,7 @@ fn foo() {
853} 780}
854"#, 781"#,
855 expect![[r#" 782 expect![[r#"
856 i Local FileId(0) 19..20 Other 783 i Local FileId(0) 19..20 19..20 Other
857 784
858 FileId(0) 26..27 Other Write 785 FileId(0) 26..27 Other Write
859 "#]], 786 "#]],
@@ -995,10 +922,10 @@ impl Foo {
995} 922}
996"#, 923"#,
997 expect![[r#" 924 expect![[r#"
998 self SelfParam FileId(0) 47..51 47..51 SelfKw Read 925 self SelfParam FileId(0) 47..51 47..51 SelfParam
999 926
1000 FileId(0) 71..75 SelfKw Read 927 FileId(0) 71..75 Other Read
1001 FileId(0) 152..156 SelfKw Read 928 FileId(0) 152..156 Other Read
1002 "#]], 929 "#]],
1003 ); 930 );
1004 } 931 }
@@ -1105,7 +1032,7 @@ fn main() {
1105} 1032}
1106"#, 1033"#,
1107 expect![[r#" 1034 expect![[r#"
1108 a Local FileId(0) 59..60 Other 1035 a Local FileId(0) 59..60 59..60 Other
1109 1036
1110 FileId(0) 80..81 Other Read 1037 FileId(0) 80..81 Other Read
1111 "#]], 1038 "#]],
@@ -1123,7 +1050,7 @@ fn main() {
1123} 1050}
1124"#, 1051"#,
1125 expect![[r#" 1052 expect![[r#"
1126 a Local FileId(0) 59..60 Other 1053 a Local FileId(0) 59..60 59..60 Other
1127 1054
1128 FileId(0) 80..81 Other Read 1055 FileId(0) 80..81 Other Read
1129 "#]], 1056 "#]],
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 039efb26f..9ac4af026 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -444,7 +444,7 @@ fn rename_reference(
444 mark::hit!(rename_not_an_ident_ref); 444 mark::hit!(rename_not_an_ident_ref);
445 bail!("Invalid name `{}`: not an identifier", new_name) 445 bail!("Invalid name `{}`: not an identifier", new_name)
446 } 446 }
447 (IdentifierKind::ToSelf, ReferenceKind::SelfKw) => { 447 (IdentifierKind::ToSelf, ReferenceKind::SelfParam) => {
448 unreachable!("rename_self_to_param should've been called instead") 448 unreachable!("rename_self_to_param should've been called instead")
449 } 449 }
450 (IdentifierKind::ToSelf, _) => { 450 (IdentifierKind::ToSelf, _) => {
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 34bae49a8..87578e70a 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -226,35 +226,16 @@ pub(super) fn element(
226 T![unsafe] => h | HlMod::Unsafe, 226 T![unsafe] => h | HlMod::Unsafe,
227 T![true] | T![false] => HlTag::BoolLiteral.into(), 227 T![true] | T![false] => HlTag::BoolLiteral.into(),
228 T![self] => { 228 T![self] => {
229 let self_param_is_mut = element 229 let self_param = element.parent().and_then(ast::SelfParam::cast);
230 .parent() 230 if let Some(NameClass::Definition(def)) = self_param
231 .and_then(ast::SelfParam::cast) 231 .and_then(|self_param| NameClass::classify_self_param(sema, &self_param))
232 .and_then(|p| p.mut_token())
233 .is_some();
234 let self_path = &element
235 .parent()
236 .as_ref()
237 .and_then(SyntaxNode::parent)
238 .and_then(ast::Path::cast)
239 .and_then(|p| sema.resolve_path(&p));
240 let mut h = HlTag::Symbol(SymbolKind::SelfParam).into();
241 if self_param_is_mut
242 || matches!(self_path,
243 Some(hir::PathResolution::Local(local))
244 if local.is_self(db)
245 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
246 )
247 { 232 {
248 h |= HlMod::Mutable 233 highlight_def(db, def) | HlMod::Definition
249 } 234 } else if element.ancestors().any(|it| it.kind() == USE_TREE) {
250 235 HlTag::Symbol(SymbolKind::SelfParam).into()
251 if let Some(hir::PathResolution::Local(local)) = self_path { 236 } else {
252 if is_consumed_lvalue(element, &local, db) { 237 return None;
253 h |= HlMod::Consuming;
254 }
255 } 238 }
256
257 h
258 } 239 }
259 T![ref] => element 240 T![ref] => element
260 .parent() 241 .parent()
@@ -345,7 +326,9 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
345 hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), 326 hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam),
346 }, 327 },
347 Definition::Local(local) => { 328 Definition::Local(local) => {
348 let tag = if local.is_param(db) { 329 let tag = if local.is_self(db) {
330 HlTag::Symbol(SymbolKind::SelfParam)
331 } else if local.is_param(db) {
349 HlTag::Symbol(SymbolKind::ValueParam) 332 HlTag::Symbol(SymbolKind::ValueParam)
350 } else { 333 } else {
351 HlTag::Symbol(SymbolKind::Local) 334 HlTag::Symbol(SymbolKind::Local)
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index e36e6fc3f..d421a7803 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -42,16 +42,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42 42
43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span> 43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span>
44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
46<span class="brace">}</span> 46<span class="brace">}</span>
47 47
48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> 48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51<span class="brace">}</span> 51<span class="brace">}</span>
52 52
53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> 53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56<span class="brace">}</span> 56<span class="brace">}</span>
57 </code></pre> \ No newline at end of file 57 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 6dadda1c1..5e877df88 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -93,7 +93,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
93 <span class="comment documentation">/// ```sh</span> 93 <span class="comment documentation">/// ```sh</span>
94 <span class="comment documentation">/// echo 1</span> 94 <span class="comment documentation">/// echo 1</span>
95 <span class="comment documentation">/// ```</span> 95 <span class="comment documentation">/// ```</span>
96 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span> 96 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
97 <span class="bool_literal">true</span> 97 <span class="bool_literal">true</span>
98 <span class="brace">}</span> 98 <span class="brace">}</span>
99<span class="brace">}</span> 99<span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 9d4d6d4a0..036cb6c11 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span> 46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span>
47 47
48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span> 48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span>
49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50<span class="brace">}</span> 50<span class="brace">}</span>
51 51
52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span> 52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span>
@@ -61,11 +61,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
61<span class="brace">}</span> 61<span class="brace">}</span>
62 62
63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
65<span class="brace">}</span> 65<span class="brace">}</span>
66 66
67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> 67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
69<span class="brace">}</span> 69<span class="brace">}</span>
70 70
71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 6b7447c46..237149566 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -66,25 +66,25 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
66<span class="brace">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> 68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span> 69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
70<span class="brace">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> 72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
75 <span class="brace">}</span> 75 <span class="brace">}</span>
76<span class="brace">}</span> 76<span class="brace">}</span>
77 77
78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> 78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span> 80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span>
81 <span class="brace">}</span> 81 <span class="brace">}</span>
82 82
83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> 83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> 84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
85 <span class="brace">}</span> 85 <span class="brace">}</span>
86 86
87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
89 <span class="brace">}</span> 89 <span class="brace">}</span>
90<span class="brace">}</span> 90<span class="brace">}</span>
@@ -95,15 +95,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
95<span class="brace">}</span> 95<span class="brace">}</span>
96 96
97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span> 97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span>
98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span> 98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span> 99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
100 <span class="brace">}</span> 100 <span class="brace">}</span>
101 101
102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> 102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> 103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
104 <span class="brace">}</span> 104 <span class="brace">}</span>
105 105
106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span> 106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
108 <span class="brace">}</span> 108 <span class="brace">}</span>
109<span class="brace">}</span> 109<span class="brace">}</span>
@@ -213,7 +213,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> 213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
214 214
215<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span> 215<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span> 216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span> 217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span>
218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> 218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span> 219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 1f26f8043..1d4bac7ad 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -1,7 +1,7 @@
1use ide_db::base_db::{FileId, SourceDatabase}; 1use ide_db::base_db::{FileId, SourceDatabase};
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::{ 3use syntax::{
4 algo, AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, 4 AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
5}; 5};
6 6
7// Feature: Show Syntax Tree 7// Feature: Show Syntax Tree
@@ -21,7 +21,7 @@ pub(crate) fn syntax_tree(
21) -> String { 21) -> String {
22 let parse = db.parse(file_id); 22 let parse = db.parse(file_id);
23 if let Some(text_range) = text_range { 23 if let Some(text_range) = text_range {
24 let node = match algo::find_covering_element(parse.tree().syntax(), text_range) { 24 let node = match parse.tree().syntax().covering_element(text_range) {
25 NodeOrToken::Node(node) => node, 25 NodeOrToken::Node(node) => node,
26 NodeOrToken::Token(token) => { 26 NodeOrToken::Token(token) => {
27 if let Some(tree) = syntax_tree_for_string(&token, text_range) { 27 if let Some(tree) = syntax_tree_for_string(&token, text_range) {
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d68fe42b0..231e886a9 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -10,7 +10,7 @@ use hir::{
10 Module, ModuleDef, Name, PathResolution, Semantics, Visibility, 10 Module, ModuleDef, Name, PathResolution, Semantics, Visibility,
11}; 11};
12use syntax::{ 12use syntax::{
13 ast::{self, AstNode}, 13 ast::{self, AstNode, PathSegmentKind},
14 match_ast, SyntaxKind, SyntaxNode, 14 match_ast, SyntaxKind, SyntaxNode,
15}; 15};
16 16
@@ -117,6 +117,13 @@ impl NameClass {
117 } 117 }
118 } 118 }
119 119
120 pub fn classify_self_param(
121 sema: &Semantics<RootDatabase>,
122 self_param: &ast::SelfParam,
123 ) -> Option<NameClass> {
124 sema.to_def(self_param).map(Definition::Local).map(NameClass::Definition)
125 }
126
120 pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { 127 pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
121 let _p = profile::span("classify_name"); 128 let _p = profile::span("classify_name");
122 129
@@ -135,24 +142,26 @@ impl NameClass {
135 let path = use_tree.path()?; 142 let path = use_tree.path()?;
136 let path_segment = path.segment()?; 143 let path_segment = path.segment()?;
137 let name_ref_class = path_segment 144 let name_ref_class = path_segment
138 .name_ref() 145 .kind()
139 // The rename might be from a `self` token, so fallback to the name higher 146 .and_then(|kind| {
140 // in the use tree. 147 match kind {
141 .or_else(||{ 148 // The rename might be from a `self` token, so fallback to the name higher
142 if path_segment.self_token().is_none() { 149 // in the use tree.
143 return None; 150 PathSegmentKind::SelfKw => {
151 let use_tree = use_tree
152 .syntax()
153 .parent()
154 .as_ref()
155 // Skip over UseTreeList
156 .and_then(SyntaxNode::parent)
157 .and_then(ast::UseTree::cast)?;
158 let path = use_tree.path()?;
159 let path_segment = path.segment()?;
160 path_segment.name_ref()
161 },
162 PathSegmentKind::Name(name_ref) => Some(name_ref),
163 _ => return None,
144 } 164 }
145
146 let use_tree = use_tree
147 .syntax()
148 .parent()
149 .as_ref()
150 // Skip over UseTreeList
151 .and_then(SyntaxNode::parent)
152 .and_then(ast::UseTree::cast)?;
153 let path = use_tree.path()?;
154 let path_segment = path.segment()?;
155 path_segment.name_ref()
156 }) 165 })
157 .and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?; 166 .and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?;
158 167
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index c6763ae36..0dcc4dd29 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -1,5 +1,6 @@
1//! A module with ide helpers for high-level ide features. 1//! A module with ide helpers for high-level ide features.
2pub mod insert_use; 2pub mod insert_use;
3pub mod import_assets;
3 4
4use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; 5use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
5use syntax::ast::{self, make}; 6use syntax::ast::{self, make};
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 4ce82c1ba..edc3da318 100644
--- a/crates/assists/src/utils/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -1,19 +1,17 @@
1//! Look up accessible paths for items. 1//! Look up accessible paths for items.
2use either::Either; 2use either::Either;
3use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; 3use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics};
4use ide_db::{imports_locator, RootDatabase};
5use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
6use syntax::{ast, AstNode, SyntaxNode}; 5use syntax::{ast, AstNode, SyntaxNode};
7 6
8use crate::assist_config::InsertUseConfig; 7use crate::{imports_locator, RootDatabase};
8
9use super::insert_use::InsertUseConfig;
9 10
10#[derive(Debug)] 11#[derive(Debug)]
11pub(crate) enum ImportCandidate { 12pub enum ImportCandidate {
12 /// Simple name like 'HashMap' 13 // A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
13 UnqualifiedName(PathImportCandidate), 14 Path(PathImportCandidate),
14 /// First part of the qualified name.
15 /// For 'std::collections::HashMap', that will be 'std'.
16 QualifierStart(PathImportCandidate),
17 /// A trait associated function (with no self parameter) or associated constant. 15 /// A trait associated function (with no self parameter) or associated constant.
18 /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type 16 /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type
19 /// and `name` is the `test_function` 17 /// and `name` is the `test_function`
@@ -25,25 +23,26 @@ pub(crate) enum ImportCandidate {
25} 23}
26 24
27#[derive(Debug)] 25#[derive(Debug)]
28pub(crate) struct TraitImportCandidate { 26pub struct TraitImportCandidate {
29 pub(crate) ty: hir::Type, 27 pub ty: hir::Type,
30 pub(crate) name: ast::NameRef, 28 pub name: ast::NameRef,
31} 29}
32 30
33#[derive(Debug)] 31#[derive(Debug)]
34pub(crate) struct PathImportCandidate { 32pub struct PathImportCandidate {
35 pub(crate) name: ast::NameRef, 33 pub qualifier: Option<ast::Path>,
34 pub name: ast::NameRef,
36} 35}
37 36
38#[derive(Debug)] 37#[derive(Debug)]
39pub(crate) struct ImportAssets { 38pub struct ImportAssets {
40 import_candidate: ImportCandidate, 39 import_candidate: ImportCandidate,
41 module_with_name_to_import: hir::Module, 40 module_with_name_to_import: hir::Module,
42 syntax_under_caret: SyntaxNode, 41 syntax_under_caret: SyntaxNode,
43} 42}
44 43
45impl ImportAssets { 44impl ImportAssets {
46 pub(crate) fn for_method_call( 45 pub fn for_method_call(
47 method_call: ast::MethodCallExpr, 46 method_call: ast::MethodCallExpr,
48 sema: &Semantics<RootDatabase>, 47 sema: &Semantics<RootDatabase>,
49 ) -> Option<Self> { 48 ) -> Option<Self> {
@@ -56,7 +55,7 @@ impl ImportAssets {
56 }) 55 })
57 } 56 }
58 57
59 pub(crate) fn for_regular_path( 58 pub fn for_regular_path(
60 path_under_caret: ast::Path, 59 path_under_caret: ast::Path,
61 sema: &Semantics<RootDatabase>, 60 sema: &Semantics<RootDatabase>,
62 ) -> Option<Self> { 61 ) -> Option<Self> {
@@ -73,24 +72,23 @@ impl ImportAssets {
73 }) 72 })
74 } 73 }
75 74
76 pub(crate) fn syntax_under_caret(&self) -> &SyntaxNode { 75 pub fn syntax_under_caret(&self) -> &SyntaxNode {
77 &self.syntax_under_caret 76 &self.syntax_under_caret
78 } 77 }
79 78
80 pub(crate) fn import_candidate(&self) -> &ImportCandidate { 79 pub fn import_candidate(&self) -> &ImportCandidate {
81 &self.import_candidate 80 &self.import_candidate
82 } 81 }
83 82
84 fn get_search_query(&self) -> &str { 83 fn get_search_query(&self) -> &str {
85 match &self.import_candidate { 84 match &self.import_candidate {
86 ImportCandidate::UnqualifiedName(candidate) 85 ImportCandidate::Path(candidate) => candidate.name.text(),
87 | ImportCandidate::QualifierStart(candidate) => candidate.name.text(),
88 ImportCandidate::TraitAssocItem(candidate) 86 ImportCandidate::TraitAssocItem(candidate)
89 | ImportCandidate::TraitMethod(candidate) => candidate.name.text(), 87 | ImportCandidate::TraitMethod(candidate) => candidate.name.text(),
90 } 88 }
91 } 89 }
92 90
93 pub(crate) fn search_for_imports( 91 pub fn search_for_imports(
94 &self, 92 &self,
95 sema: &Semantics<RootDatabase>, 93 sema: &Semantics<RootDatabase>,
96 config: &InsertUseConfig, 94 config: &InsertUseConfig,
@@ -101,7 +99,7 @@ impl ImportAssets {
101 99
102 /// This may return non-absolute paths if a part of the returned path is already imported into scope. 100 /// This may return non-absolute paths if a part of the returned path is already imported into scope.
103 #[allow(dead_code)] 101 #[allow(dead_code)]
104 pub(crate) fn search_for_relative_paths( 102 pub fn search_for_relative_paths(
105 &self, 103 &self,
106 sema: &Semantics<RootDatabase>, 104 sema: &Semantics<RootDatabase>,
107 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 105 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
@@ -253,10 +251,14 @@ impl ImportCandidate {
253 _ => return None, 251 _ => return None,
254 } 252 }
255 } else { 253 } else {
256 ImportCandidate::QualifierStart(PathImportCandidate { name: qualifier_start }) 254 ImportCandidate::Path(PathImportCandidate {
255 qualifier: Some(qualifier),
256 name: qualifier_start,
257 })
257 } 258 }
258 } else { 259 } else {
259 ImportCandidate::UnqualifiedName(PathImportCandidate { 260 ImportCandidate::Path(PathImportCandidate {
261 qualifier: None,
260 name: segment.syntax().descendants().find_map(ast::NameRef::cast)?, 262 name: segment.syntax().descendants().find_map(ast::NameRef::cast)?,
261 }) 263 })
262 }; 264 };
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index d6b498be3..877d4f1c7 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -15,6 +15,12 @@ use syntax::{
15}; 15};
16use test_utils::mark; 16use test_utils::mark;
17 17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct InsertUseConfig {
20 pub merge: Option<MergeBehavior>,
21 pub prefix_kind: hir::PrefixKind,
22}
23
18#[derive(Debug, Clone)] 24#[derive(Debug, Clone)]
19pub enum ImportScope { 25pub enum ImportScope {
20 File(ast::SourceFile), 26 File(ast::SourceFile),
@@ -97,7 +103,7 @@ pub fn insert_use<'a>(
97) -> SyntaxRewriter<'a> { 103) -> SyntaxRewriter<'a> {
98 let _p = profile::span("insert_use"); 104 let _p = profile::span("insert_use");
99 let mut rewriter = SyntaxRewriter::default(); 105 let mut rewriter = SyntaxRewriter::default();
100 let use_item = make::use_(make::use_tree(path.clone(), None, None, false)); 106 let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false));
101 // merge into existing imports if possible 107 // merge into existing imports if possible
102 if let Some(mb) = merge { 108 if let Some(mb) = merge {
103 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 109 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
@@ -444,8 +450,14 @@ fn use_tree_path_cmp(a: &ast::Path, a_has_tl: bool, b: &ast::Path, b_has_tl: boo
444} 450}
445 451
446fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { 452fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
447 let a = a.name_ref(); 453 let a = a.kind().and_then(|kind| match kind {
448 let b = b.name_ref(); 454 PathSegmentKind::Name(name_ref) => Some(name_ref),
455 _ => None,
456 });
457 let b = b.kind().and_then(|kind| match kind {
458 PathSegmentKind::Name(name_ref) => Some(name_ref),
459 _ => None,
460 });
449 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text)) 461 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text))
450} 462}
451 463
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index e9f23adf8..d111fba92 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -12,6 +12,8 @@ use crate::{
12use either::Either; 12use either::Either;
13use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
14 14
15const QUERY_SEARCH_LIMIT: usize = 40;
16
15pub fn find_exact_imports<'a>( 17pub fn find_exact_imports<'a>(
16 sema: &Semantics<'a, RootDatabase>, 18 sema: &Semantics<'a, RootDatabase>,
17 krate: Crate, 19 krate: Crate,
@@ -24,11 +26,11 @@ pub fn find_exact_imports<'a>(
24 { 26 {
25 let mut local_query = symbol_index::Query::new(name_to_import.clone()); 27 let mut local_query = symbol_index::Query::new(name_to_import.clone());
26 local_query.exact(); 28 local_query.exact();
27 local_query.limit(40); 29 local_query.limit(QUERY_SEARCH_LIMIT);
28 local_query 30 local_query
29 }, 31 },
30 import_map::Query::new(name_to_import) 32 import_map::Query::new(name_to_import)
31 .limit(40) 33 .limit(QUERY_SEARCH_LIMIT)
32 .name_only() 34 .name_only()
33 .search_mode(import_map::SearchMode::Equals) 35 .search_mode(import_map::SearchMode::Equals)
34 .case_sensitive(), 36 .case_sensitive(),
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index b5fa46642..0ecb13a64 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -65,7 +65,7 @@ pub enum ReferenceKind {
65 FieldShorthandForLocal, 65 FieldShorthandForLocal,
66 StructLiteral, 66 StructLiteral,
67 RecordFieldExprOrPat, 67 RecordFieldExprOrPat,
68 SelfKw, 68 SelfParam,
69 EnumLiteral, 69 EnumLiteral,
70 Lifetime, 70 Lifetime,
71 Other, 71 Other,
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index d61950b96..093a9890d 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -50,6 +50,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
50 T![match], 50 T![match],
51 T![unsafe], 51 T![unsafe],
52 T![return], 52 T![return],
53 T![yield],
53 T![break], 54 T![break],
54 T![continue], 55 T![continue],
55 T![async], 56 T![async],
@@ -142,6 +143,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
142 block_expr_unchecked(p) 143 block_expr_unchecked(p)
143 } 144 }
144 T![return] => return_expr(p), 145 T![return] => return_expr(p),
146 T![yield] => yield_expr(p),
145 T![continue] => continue_expr(p), 147 T![continue] => continue_expr(p),
146 T![break] => break_expr(p, r), 148 T![break] => break_expr(p, r),
147 _ => { 149 _ => {
@@ -508,6 +510,20 @@ fn return_expr(p: &mut Parser) -> CompletedMarker {
508 } 510 }
509 m.complete(p, RETURN_EXPR) 511 m.complete(p, RETURN_EXPR)
510} 512}
513// test yield_expr
514// fn foo() {
515// yield;
516// yield 1;
517// }
518fn yield_expr(p: &mut Parser) -> CompletedMarker {
519 assert!(p.at(T![yield]));
520 let m = p.start();
521 p.bump(T![yield]);
522 if p.at_ts(EXPR_FIRST) {
523 expr(p);
524 }
525 m.complete(p, YIELD_EXPR)
526}
511 527
512// test continue_expr 528// test continue_expr
513// fn foo() { 529// fn foo() {
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index 5d297e2d6..b10f48fe1 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -82,7 +82,11 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
82 } 82 }
83 // test crate_path 83 // test crate_path
84 // use crate::foo; 84 // use crate::foo;
85 T![self] | T![super] | T![crate] => p.bump_any(), 85 T![self] | T![super] | T![crate] => {
86 let m = p.start();
87 p.bump_any();
88 m.complete(p, NAME_REF);
89 }
86 _ => { 90 _ => {
87 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); 91 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
88 if empty { 92 if empty {
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index f69e71bdb..7d53cc4cd 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -101,6 +101,7 @@ pub enum SyntaxKind {
101 USE_KW, 101 USE_KW,
102 WHERE_KW, 102 WHERE_KW,
103 WHILE_KW, 103 WHILE_KW,
104 YIELD_KW,
104 AUTO_KW, 105 AUTO_KW,
105 DEFAULT_KW, 106 DEFAULT_KW,
106 EXISTENTIAL_KW, 107 EXISTENTIAL_KW,
@@ -186,6 +187,7 @@ pub enum SyntaxKind {
186 LABEL, 187 LABEL,
187 BLOCK_EXPR, 188 BLOCK_EXPR,
188 RETURN_EXPR, 189 RETURN_EXPR,
190 YIELD_EXPR,
189 MATCH_EXPR, 191 MATCH_EXPR,
190 MATCH_ARM_LIST, 192 MATCH_ARM_LIST,
191 MATCH_ARM, 193 MATCH_ARM,
@@ -263,7 +265,8 @@ impl SyntaxKind {
263 | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW 265 | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
264 | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW 266 | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
265 | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW 267 | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
266 | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW | MACRO_RULES_KW => true, 268 | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW
269 | MACRO_RULES_KW => true,
267 _ => false, 270 _ => false,
268 } 271 }
269 } 272 }
@@ -326,6 +329,7 @@ impl SyntaxKind {
326 "use" => USE_KW, 329 "use" => USE_KW,
327 "where" => WHERE_KW, 330 "where" => WHERE_KW,
328 "while" => WHILE_KW, 331 "while" => WHILE_KW,
332 "yield" => YIELD_KW,
329 _ => return None, 333 _ => return None,
330 }; 334 };
331 Some(kw) 335 Some(kw)
@@ -366,4 +370,4 @@ impl SyntaxKind {
366 } 370 }
367} 371}
368#[macro_export] 372#[macro_export]
369macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } 373macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 7d3fda7a8..a02c8327f 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -3,6 +3,7 @@
3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; 3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
4 4
5use anyhow::{bail, format_err, Result}; 5use anyhow::{bail, format_err, Result};
6use hir::PrefixKind;
6use ide::{ 7use ide::{
7 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, 8 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
8}; 9};
@@ -11,7 +12,7 @@ use ide_db::{
11 salsa::{Database, Durability}, 12 salsa::{Database, Durability},
12 FileId, 13 FileId,
13 }, 14 },
14 helpers::SnippetCap, 15 helpers::{insert_use::InsertUseConfig, SnippetCap},
15}; 16};
16use vfs::AbsPathBuf; 17use vfs::AbsPathBuf;