diff options
Diffstat (limited to 'crates')
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 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | use crate::AssistKind; | 9 | use 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)] | ||
19 | pub 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 | ||
3 | use std::mem; | 3 | use std::mem; |
4 | 4 | ||
5 | use algo::find_covering_element; | ||
6 | use hir::Semantics; | 5 | use hir::Semantics; |
7 | use ide_db::{ | 6 | use 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 @@ | |||
1 | use ide_db::helpers::{ | 1 | use 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 | }; |
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{ | 8 | use 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 | ||
122 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | 120 | fn 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 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::AsName; |
4 | use ide_db::helpers::mod_path_to_ast; | 4 | use ide_db::helpers::{ |
5 | import_assets::{ImportAssets, ImportCandidate}, | ||
6 | mod_path_to_ast, | ||
7 | }; | ||
5 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
6 | use syntax::{ | 9 | use syntax::{ |
7 | ast, | 10 | ast, |
@@ -12,7 +15,6 @@ use test_utils::mark; | |||
12 | 15 | ||
13 | use crate::{ | 16 | use 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 | ||
187 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { | 190 | fn 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 | ||
195 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | 198 | fn 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 @@ | |||
1 | use syntax::{ | ||
2 | algo::SyntaxRewriter, | ||
3 | ast::{self, edit::AstNodeEdit, VisibilityOwner}, | ||
4 | AstNode, SyntaxKind, | ||
5 | }; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use 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 | // ``` | ||
25 | pub(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 | |||
69 | fn 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)] | ||
85 | mod 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" | ||
96 | use std::fmt::Debug$0; | ||
97 | ", | ||
98 | ); | ||
99 | check_assist_not_applicable( | ||
100 | unmerge_use, | ||
101 | r" | ||
102 | use std::fmt::{Debug$0}; | ||
103 | ", | ||
104 | ); | ||
105 | check_assist_not_applicable( | ||
106 | unmerge_use, | ||
107 | r" | ||
108 | use 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" | ||
118 | use std::fmt::*$0; | ||
119 | ", | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn unmerge_use_item() { | ||
125 | check_assist( | ||
126 | unmerge_use, | ||
127 | r" | ||
128 | use std::fmt::{Debug, Display$0}; | ||
129 | ", | ||
130 | r" | ||
131 | use std::fmt::{Debug}; | ||
132 | use std::fmt::Display; | ||
133 | ", | ||
134 | ); | ||
135 | |||
136 | check_assist( | ||
137 | unmerge_use, | ||
138 | r" | ||
139 | use std::fmt::{Debug, format$0, Display}; | ||
140 | ", | ||
141 | r" | ||
142 | use std::fmt::{Debug, Display}; | ||
143 | use std::fmt::format; | ||
144 | ", | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn unmerge_glob_import() { | ||
150 | check_assist( | ||
151 | unmerge_use, | ||
152 | r" | ||
153 | use std::fmt::{*$0, Display}; | ||
154 | ", | ||
155 | r" | ||
156 | use std::fmt::{Display}; | ||
157 | use std::fmt::*; | ||
158 | ", | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | #[test] | ||
163 | fn unmerge_renamed_use_item() { | ||
164 | check_assist( | ||
165 | unmerge_use, | ||
166 | r" | ||
167 | use std::fmt::{Debug, Display as Disp$0}; | ||
168 | ", | ||
169 | r" | ||
170 | use std::fmt::{Debug}; | ||
171 | use 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" | ||
181 | mod format { | ||
182 | use std::fmt::{Debug, Display$0 as Disp, format}; | ||
183 | } | ||
184 | ", | ||
185 | r" | ||
186 | mod 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" | ||
199 | use foo::bar::{baz::{qux$0, foobar}, barbaz}; | ||
200 | ", | ||
201 | r" | ||
202 | use foo::bar::{baz::{foobar}, barbaz}; | ||
203 | use foo::bar::baz::qux; | ||
204 | ", | ||
205 | ); | ||
206 | check_assist( | ||
207 | unmerge_use, | ||
208 | r" | ||
209 | use foo::bar::{baz$0::{qux, foobar}, barbaz}; | ||
210 | ", | ||
211 | r" | ||
212 | use foo::bar::{barbaz}; | ||
213 | use 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" | ||
223 | pub use std::fmt::{Debug, Display$0}; | ||
224 | ", | ||
225 | r" | ||
226 | pub use std::fmt::{Debug}; | ||
227 | pub 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 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 26 | ||
27 | pub use assist_config::{AssistConfig, InsertUseConfig}; | 27 | pub use assist_config::AssistConfig; |
28 | 28 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
30 | pub enum AssistKind { | 30 | pub 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; | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::{ | 4 | use 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 | }; |
10 | use syntax::TextRange; | 13 | use syntax::TextRange; |
11 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 14 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists}; |
14 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig, | ||
15 | }; | ||
16 | use stdx::{format_to, trim_indent}; | 17 | use stdx::{format_to, trim_indent}; |
17 | 18 | ||
18 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | 19 | pub(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] |
1141 | fn doctest_unmerge_use() { | ||
1142 | check_doc_test( | ||
1143 | "unmerge_use", | ||
1144 | r#####" | ||
1145 | use std::fmt::{Debug, Display$0}; | ||
1146 | "#####, | ||
1147 | r#####" | ||
1148 | use std::fmt::{Debug}; | ||
1149 | use std::fmt::Display; | ||
1150 | "#####, | ||
1151 | ) | ||
1152 | } | ||
1153 | |||
1154 | #[test] | ||
1141 | fn doctest_unwrap_block() { | 1155 | fn 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. |
2 | pub(crate) mod import_assets; | ||
3 | 2 | ||
4 | use std::ops; | 3 | use 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; | |||
13 | pub(crate) mod macro_in_item_position; | 13 | pub(crate) mod macro_in_item_position; |
14 | pub(crate) mod trait_impl; | 14 | pub(crate) mod trait_impl; |
15 | pub(crate) mod mod_; | 15 | pub(crate) mod mod_; |
16 | pub(crate) mod flyimport; | ||
16 | 17 | ||
17 | use hir::{ModPath, ScopeDef, Type}; | 18 | use 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 | |||
48 | use either::Either; | ||
49 | use hir::{ModPath, ScopeDef}; | ||
50 | use ide_db::{helpers::insert_use::ImportScope, imports_locator}; | ||
51 | use syntax::AstNode; | ||
52 | use test_utils::mark; | ||
53 | |||
54 | use crate::{ | ||
55 | context::CompletionContext, | ||
56 | render::{render_resolution_with_import, RenderContext}, | ||
57 | ImportEdit, | ||
58 | }; | ||
59 | |||
60 | use super::Completions; | ||
61 | |||
62 | pub(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 | |||
115 | fn 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)] | ||
131 | mod 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 | ||
151 | pub mod io { | ||
152 | pub fn stdin() {} | ||
153 | }; | ||
154 | |||
155 | //- /main.rs crate:main deps:dep | ||
156 | fn main() { | ||
157 | stdi$0 | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | use dep::io::stdin; | ||
162 | |||
163 | fn 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] | ||
178 | macro_rules! macro_with_curlies { | ||
179 | () => {} | ||
180 | } | ||
181 | |||
182 | //- /main.rs crate:main deps:dep | ||
183 | fn main() { | ||
184 | curli$0 | ||
185 | } | ||
186 | "#, | ||
187 | r#" | ||
188 | use dep::macro_with_curlies; | ||
189 | |||
190 | fn 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 | ||
203 | pub struct FirstStruct; | ||
204 | pub mod some_module { | ||
205 | pub struct SecondStruct; | ||
206 | pub struct ThirdStruct; | ||
207 | } | ||
208 | |||
209 | //- /main.rs crate:main deps:dep | ||
210 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
211 | |||
212 | fn main() { | ||
213 | this$0 | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
218 | |||
219 | fn 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 | ||
232 | pub struct FirstStruct; | ||
233 | pub 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 | ||
247 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
248 | |||
249 | fn 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 | ||
266 | pub 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 | ||
283 | use dep::test_mod::TestStruct; | ||
284 | fn 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 | ||
3 | use syntax::{ast, SyntaxKind}; | 3 | use syntax::SyntaxKind; |
4 | use test_utils::mark; | 4 | use test_utils::mark; |
5 | 5 | ||
6 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 6 | use 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 | |||
149 | fn 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 | ||
160 | fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { | 160 | fn 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 { | |
164 | fn 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)] |
179 | mod tests { | 181 | mod 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#" | ||
621 | fn main() { let x = $0 } | ||
622 | "#, | ||
623 | r#" | ||
624 | fn main() { let x = match $0 {}; } | ||
625 | "#, | ||
626 | ); | ||
627 | |||
628 | check_edit( | ||
629 | "if", | ||
630 | r#" | ||
631 | fn main() { | ||
632 | let x = $0 | ||
633 | let y = 92; | ||
634 | } | ||
635 | "#, | ||
636 | r#" | ||
637 | fn main() { | ||
638 | let x = if $0 {}; | ||
639 | let y = 92; | ||
640 | } | ||
641 | "#, | ||
642 | ); | ||
643 | |||
644 | check_edit( | ||
645 | "loop", | ||
646 | r#" | ||
647 | fn main() { | ||
648 | let x = $0 | ||
649 | bar(); | ||
650 | } | ||
651 | "#, | ||
652 | r#" | ||
653 | fn 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 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use either::Either; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; | ||
7 | use ide_db::helpers::insert_use::ImportScope; | ||
8 | use ide_db::imports_locator; | ||
9 | use syntax::AstNode; | 6 | use syntax::AstNode; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{ | 9 | use crate::{CompletionContext, Completions}; |
13 | render::{render_resolution_with_import, RenderContext}, | ||
14 | CompletionContext, Completions, ImportEdit, | ||
15 | }; | ||
16 | 10 | ||
17 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 11 | pub(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 | ||
54 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 44 | fn 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. | ||
126 | fn 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 | |||
174 | fn 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)] |
190 | mod tests { | 71 | mod 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 | ||
866 | pub mod io { | ||
867 | pub fn stdin() {} | ||
868 | }; | ||
869 | |||
870 | //- /main.rs crate:main deps:dep | ||
871 | fn main() { | ||
872 | stdi$0 | ||
873 | } | ||
874 | "#, | ||
875 | r#" | ||
876 | use dep::io::stdin; | ||
877 | |||
878 | fn 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] | ||
894 | macro_rules! macro_with_curlies { | ||
895 | () => {} | ||
896 | } | ||
897 | |||
898 | //- /main.rs crate:main deps:dep | ||
899 | fn main() { | ||
900 | curli$0 | ||
901 | } | ||
902 | "#, | ||
903 | r#" | ||
904 | use dep::macro_with_curlies; | ||
905 | |||
906 | fn 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 | ||
920 | pub struct FirstStruct; | ||
921 | pub mod some_module { | ||
922 | pub struct SecondStruct; | ||
923 | pub struct ThirdStruct; | ||
924 | } | ||
925 | |||
926 | //- /main.rs crate:main deps:dep | ||
927 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
928 | |||
929 | fn main() { | ||
930 | this$0 | ||
931 | } | ||
932 | "#, | ||
933 | r#" | ||
934 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
935 | |||
936 | fn 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 | ||
950 | pub struct FirstStruct; | ||
951 | pub 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 | ||
965 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
966 | |||
967 | fn 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 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub 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}; | |||
4 | use ide_db::base_db::{FilePosition, SourceDatabase}; | 4 | use ide_db::base_db::{FilePosition, SourceDatabase}; |
5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; | 5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; |
6 | use syntax::{ | 6 | use 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 | }; |
12 | use test_utils::mark; | 10 | use test_utils::mark; |
13 | use text_edit::Indel; | 11 | use 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 | ||
509 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { | 513 | fn 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 | ||
513 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | 517 | fn 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 | ||
3 | use hir::Semantics; | 3 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 4 | use 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 | }; |
9 | use itertools::Itertools; | 12 | use 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 |
109 | fn 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. | ||
117 | fn 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 | ||
23 | use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange}; | 23 | use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange}; |
24 | use syntax::{ | 24 | use 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; | |||
18 | use rustc_hash::FxHashSet; | 18 | use rustc_hash::FxHashSet; |
19 | use syntax::{ | 19 | use syntax::{ |
20 | ast::{self, AstNode}, | 20 | ast::{self, AstNode}, |
21 | SyntaxNode, TextRange, T, | 21 | SyntaxNode, TextRange, |
22 | }; | 22 | }; |
23 | use text_edit::TextEdit; | 23 | use 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 { | |||
400 | impl ToNav for hir::Local { | 400 | impl 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; | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::RootDatabase; | 4 | use ide_db::RootDatabase; |
5 | use syntax::{ | 5 | use 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(¯o_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 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{HasAttrs, ModuleDef, Semantics}; | 2 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 3 | use 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, <) { | 51 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { |
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(<)).to_vec() | 56 | reference_definition(&sema, Either::Left(<)).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 | ||
137 | fn 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)] |
152 | pub(crate) enum ReferenceResult { | 129 | pub(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#" | ||
3134 | struct Foo; | ||
3135 | impl 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 @@ | |||
1 | use assists::utils::extract_trivial_expression; | 1 | use assists::utils::extract_trivial_expression; |
2 | use itertools::Itertools; | 2 | use itertools::Itertools; |
3 | use syntax::{ | 3 | use 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 | }; |
83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; | 83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; |
84 | pub use completion::{ | 84 | pub 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 | ||
12 | pub(crate) mod rename; | 12 | pub(crate) mod rename; |
13 | 13 | ||
14 | use either::Either; | ||
14 | use hir::Semantics; | 15 | use hir::Semantics; |
15 | use ide_db::{ | 16 | use ide_db::{ |
16 | base_db::FileId, | 17 | base_db::FileId, |
@@ -21,10 +22,10 @@ use ide_db::{ | |||
21 | use syntax::{ | 22 | use 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 | ||
27 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; | 28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
28 | 29 | ||
29 | #[derive(Debug, Clone)] | 30 | #[derive(Debug, Clone)] |
30 | pub struct ReferenceSearchResult { | 31 | pub 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 | ||
254 | fn 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)] |
328 | mod tests { | 255 | mod 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() { | |||
551 | fn foo(i : u32) -> u32 { i$0 } | 478 | fn 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 } | |||
565 | fn foo(i$0 : u32) -> u32 { i } | 492 | fn 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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">T</span><span class="angle">></span> <span class="brace">{</span> | 215 | <span class="keyword">impl</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">T</span><span class="angle">></span> <span class="brace">{</span> |
216 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle"><</span><span class="type_param declaration">U</span><span class="angle">></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"><</span><span class="type_param">U</span><span class="angle">></span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="angle"><</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">></span> <span class="brace">{</span> | 216 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle"><</span><span class="type_param declaration">U</span><span class="angle">></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"><</span><span class="type_param">U</span><span class="angle">></span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="angle"><</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">></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">=></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">=></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">=></span> <span class="variable">Nope</span><span class="comma">,</span> | 219 | <span class="variable declaration">Nope</span> <span class="operator">=></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 @@ | |||
1 | use ide_db::base_db::{FileId, SourceDatabase}; | 1 | use ide_db::base_db::{FileId, SourceDatabase}; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::{ | 3 | use 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 | }; |
12 | use syntax::{ | 12 | use 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. |
2 | pub mod insert_use; | 2 | pub mod insert_use; |
3 | pub mod import_assets; | ||
3 | 4 | ||
4 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 5 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; |
5 | use syntax::ast::{self, make}; | 6 | use 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. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; | 3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; |
4 | use ide_db::{imports_locator, RootDatabase}; | ||
5 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
6 | use syntax::{ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, AstNode, SyntaxNode}; |
7 | 6 | ||
8 | use crate::assist_config::InsertUseConfig; | 7 | use crate::{imports_locator, RootDatabase}; |
8 | |||
9 | use super::insert_use::InsertUseConfig; | ||
9 | 10 | ||
10 | #[derive(Debug)] | 11 | #[derive(Debug)] |
11 | pub(crate) enum ImportCandidate { | 12 | pub 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)] |
28 | pub(crate) struct TraitImportCandidate { | 26 | pub 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)] |
34 | pub(crate) struct PathImportCandidate { | 32 | pub 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)] |
39 | pub(crate) struct ImportAssets { | 38 | pub 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 | ||
45 | impl ImportAssets { | 44 | impl 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 | }; |
16 | use test_utils::mark; | 16 | use test_utils::mark; |
17 | 17 | ||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct InsertUseConfig { | ||
20 | pub merge: Option<MergeBehavior>, | ||
21 | pub prefix_kind: hir::PrefixKind, | ||
22 | } | ||
23 | |||
18 | #[derive(Debug, Clone)] | 24 | #[derive(Debug, Clone)] |
19 | pub enum ImportScope { | 25 | pub 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 | ||
446 | fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { | 452 | fn 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::{ | |||
12 | use either::Either; | 12 | use either::Either; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | const QUERY_SEARCH_LIMIT: usize = 40; | ||
16 | |||
15 | pub fn find_exact_imports<'a>( | 17 | pub 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 | // } | ||
518 | fn 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] |
369 | macro_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 } ; } | 373 | macro_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 @@ | |||
3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; | 3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; |
4 | 4 | ||
5 | use anyhow::{bail, format_err, Result}; | 5 | use anyhow::{bail, format_err, Result}; |
6 | use hir::PrefixKind; | ||
6 | use ide::{ | 7 | use 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 | }; |
16 | use vfs::AbsPathBuf; | 17 | use vfs::AbsPathBuf; |
17 | 18 | ||
@@ -96,7 +97,7 @@ impl BenchCmd { | |||
96 | add_call_parenthesis: true, | 97 | add_call_parenthesis: true, |
97 | add_call_argument_snippets: true, | 98 | add_call_argument_snippets: true, |
98 | snippet_cap: SnippetCap::new(true), | 99 | snippet_cap: SnippetCap::new(true), |
99 | merge: None, | 100 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
100 | }; | 101 | }; |
101 | let res = do_work(&mut host, file_id, |analysis| { | 102 | let res = do_work(&mut host, file_id, |analysis| { |
102 | analysis.completions(&options, file_position) | 103 | analysis.completions(&options, file_position) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 27b92a5a9..ce9655818 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -11,11 +11,11 @@ use std::{convert::TryFrom, ffi::OsString, iter, path::PathBuf}; | |||
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
14 | use ide::{ | 14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; |
15 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, | 15 | use ide_db::helpers::{ |
16 | InsertUseConfig, | 16 | insert_use::{InsertUseConfig, MergeBehavior}, |
17 | SnippetCap, | ||
17 | }; | 18 | }; |
18 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | ||
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use lsp_types::{ClientCapabilities, MarkupKind}; | 20 | use lsp_types::{ClientCapabilities, MarkupKind}; |
21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
@@ -542,11 +542,18 @@ impl Config { | |||
542 | max_length: self.data.inlayHints_maxLength, | 542 | max_length: self.data.inlayHints_maxLength, |
543 | } | 543 | } |
544 | } | 544 | } |
545 | fn merge_behavior(&self) -> Option<MergeBehavior> { | 545 | fn insert_use_config(&self) -> InsertUseConfig { |
546 | match self.data.assist_importMergeBehavior { | 546 | InsertUseConfig { |
547 | MergeBehaviorDef::None => None, | 547 | merge: match self.data.assist_importMergeBehavior { |
548 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | 548 | MergeBehaviorDef::None => None, |
549 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | 549 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), |
550 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
551 | }, | ||
552 | prefix_kind: match self.data.assist_importPrefix { | ||
553 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
554 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
555 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
556 | }, | ||
550 | } | 557 | } |
551 | } | 558 | } |
552 | pub fn completion(&self) -> CompletionConfig { | 559 | pub fn completion(&self) -> CompletionConfig { |
@@ -556,7 +563,7 @@ impl Config { | |||
556 | && completion_item_edit_resolve(&self.caps), | 563 | && completion_item_edit_resolve(&self.caps), |
557 | add_call_parenthesis: self.data.completion_addCallParenthesis, | 564 | add_call_parenthesis: self.data.completion_addCallParenthesis, |
558 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, | 565 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, |
559 | merge: self.merge_behavior(), | 566 | insert_use: self.insert_use_config(), |
560 | snippet_cap: SnippetCap::new(try_or!( | 567 | snippet_cap: SnippetCap::new(try_or!( |
561 | self.caps | 568 | self.caps |
562 | .text_document | 569 | .text_document |
@@ -575,7 +582,11 @@ impl Config { | |||
575 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), | 582 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), |
576 | allowed: None, | 583 | allowed: None, |
577 | insert_use: InsertUseConfig { | 584 | insert_use: InsertUseConfig { |
578 | merge: self.merge_behavior(), | 585 | merge: match self.data.assist_importMergeBehavior { |
586 | MergeBehaviorDef::None => None, | ||
587 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
588 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
589 | }, | ||
579 | prefix_kind: match self.data.assist_importPrefix { | 590 | prefix_kind: match self.data.assist_importPrefix { |
580 | ImportPrefixDef::Plain => PrefixKind::Plain, | 591 | ImportPrefixDef::Plain => PrefixKind::Plain, |
581 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | 592 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index 23d42b4d0..5c282fe67 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -66,52 +66,7 @@ | |||
66 | ), | 66 | ), |
67 | data: None, | 67 | data: None, |
68 | }, | 68 | }, |
69 | fixes: [ | 69 | fixes: [], |
70 | CodeAction { | ||
71 | title: "consider prefixing with an underscore", | ||
72 | group: None, | ||
73 | kind: Some( | ||
74 | CodeActionKind( | ||
75 | "quickfix", | ||
76 | ), | ||
77 | ), | ||
78 | edit: Some( | ||
79 | SnippetWorkspaceEdit { | ||
80 | changes: Some( | ||
81 | { | ||
82 | Url { | ||
83 | scheme: "file", | ||
84 | host: None, | ||
85 | port: None, | ||
86 | path: "/test/driver/subcommand/repl.rs", | ||
87 | query: None, | ||
88 | fragment: None, | ||
89 | }: [ | ||
90 | TextEdit { | ||
91 | range: Range { | ||
92 | start: Position { | ||
93 | line: 290, | ||
94 | character: 8, | ||
95 | }, | ||
96 | end: Position { | ||
97 | line: 290, | ||
98 | character: 11, | ||
99 | }, | ||
100 | }, | ||
101 | new_text: "_foo", | ||
102 | }, | ||
103 | ], | ||
104 | }, | ||
105 | ), | ||
106 | document_changes: None, | ||
107 | }, | ||
108 | ), | ||
109 | is_preferred: Some( | ||
110 | true, | ||
111 | ), | ||
112 | data: None, | ||
113 | }, | ||
114 | ], | ||
115 | }, | 70 | }, |
116 | MappedRustDiagnostic { | 71 | MappedRustDiagnostic { |
117 | url: Url { | 72 | url: Url { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index 4e428bedc..d36d7693d 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -66,52 +66,7 @@ | |||
66 | ), | 66 | ), |
67 | data: None, | 67 | data: None, |
68 | }, | 68 | }, |
69 | fixes: [ | 69 | fixes: [], |
70 | CodeAction { | ||
71 | title: "consider prefixing with an underscore", | ||
72 | group: None, | ||
73 | kind: Some( | ||
74 | CodeActionKind( | ||
75 | "quickfix", | ||
76 | ), | ||
77 | ), | ||
78 | edit: Some( | ||
79 | SnippetWorkspaceEdit { | ||
80 | changes: Some( | ||
81 | { | ||
82 | Url { | ||
83 | scheme: "file", | ||
84 | host: None, | ||
85 | port: None, | ||
86 | path: "/test/driver/subcommand/repl.rs", | ||
87 | query: None, | ||
88 | fragment: None, | ||
89 | }: [ | ||
90 | TextEdit { | ||
91 | range: Range { | ||
92 | start: Position { | ||
93 | line: 290, | ||
94 | character: 8, | ||
95 | }, | ||
96 | end: Position { | ||
97 | line: 290, | ||
98 | character: 11, | ||
99 | }, | ||
100 | }, | ||
101 | new_text: "_foo", | ||
102 | }, | ||
103 | ], | ||
104 | }, | ||
105 | ), | ||
106 | document_changes: None, | ||
107 | }, | ||
108 | ), | ||
109 | is_preferred: Some( | ||
110 | true, | ||
111 | ), | ||
112 | data: None, | ||
113 | }, | ||
114 | ], | ||
115 | }, | 70 | }, |
116 | MappedRustDiagnostic { | 71 | MappedRustDiagnostic { |
117 | url: Url { | 72 | url: Url { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index 4ddd7efae..17845b711 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -66,52 +66,7 @@ | |||
66 | ), | 66 | ), |
67 | data: None, | 67 | data: None, |
68 | }, | 68 | }, |
69 | fixes: [ | 69 | fixes: [], |
70 | CodeAction { | ||
71 | title: "consider prefixing with an underscore", | ||
72 | group: None, | ||
73 | kind: Some( | ||
74 | CodeActionKind( | ||
75 | "quickfix", | ||
76 | ), | ||
77 | ), | ||
78 | edit: Some( | ||
79 | SnippetWorkspaceEdit { | ||
80 | changes: Some( | ||
81 | { | ||
82 | Url { | ||
83 | scheme: "file", | ||
84 | host: None, | ||
85 | port: None, | ||
86 | path: "/test/driver/subcommand/repl.rs", | ||
87 | query: None, | ||
88 | fragment: None, | ||
89 | }: [ | ||
90 | TextEdit { | ||
91 | range: Range { | ||
92 | start: Position { | ||
93 | line: 290, | ||
94 | character: 8, | ||
95 | }, | ||
96 | end: Position { | ||
97 | line: 290, | ||
98 | character: 11, | ||
99 | }, | ||
100 | }, | ||
101 | new_text: "_foo", | ||
102 | }, | ||
103 | ], | ||
104 | }, | ||
105 | ), | ||
106 | document_changes: None, | ||
107 | }, | ||
108 | ), | ||
109 | is_preferred: Some( | ||
110 | true, | ||
111 | ), | ||
112 | data: None, | ||
113 | }, | ||
114 | ], | ||
115 | }, | 70 | }, |
116 | MappedRustDiagnostic { | 71 | MappedRustDiagnostic { |
117 | url: Url { | 72 | url: Url { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index 4cbdb3b92..a19962167 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -102,65 +102,7 @@ | |||
102 | tags: None, | 102 | tags: None, |
103 | data: None, | 103 | data: None, |
104 | }, | 104 | }, |
105 | fixes: [ | 105 | fixes: [], |
106 | CodeAction { | ||
107 | title: "return the expression directly", | ||
108 | group: None, | ||
109 | kind: Some( | ||
110 | CodeActionKind( | ||
111 | "quickfix", | ||
112 | ), | ||
113 | ), | ||
114 | edit: Some( | ||
115 | SnippetWorkspaceEdit { | ||
116 | changes: Some( | ||
117 | { | ||
118 | Url { | ||
119 | scheme: "file", | ||
120 | host: None, | ||
121 | port: None, | ||
122 | path: "/test/src/main.rs", | ||
123 | query: None, | ||
124 | fragment: None, | ||
125 | }: [ | ||
126 | TextEdit { | ||
127 | range: Range { | ||
128 | start: Position { | ||
129 | line: 2, | ||
130 | character: 4, | ||
131 | }, | ||
132 | end: Position { | ||
133 | line: 2, | ||
134 | character: 30, | ||
135 | }, | ||
136 | }, | ||
137 | new_text: "", | ||
138 | }, | ||
139 | TextEdit { | ||
140 | range: Range { | ||
141 | start: Position { | ||
142 | line: 3, | ||
143 | character: 4, | ||
144 | }, | ||
145 | end: Position { | ||
146 | line: 3, | ||
147 | character: 5, | ||
148 | }, | ||
149 | }, | ||
150 | new_text: "(0..10).collect()", | ||
151 | }, | ||
152 | ], | ||
153 | }, | ||
154 | ), | ||
155 | document_changes: None, | ||
156 | }, | ||
157 | ), | ||
158 | is_preferred: Some( | ||
159 | true, | ||
160 | ), | ||
161 | data: None, | ||
162 | }, | ||
163 | ], | ||
164 | }, | 106 | }, |
165 | MappedRustDiagnostic { | 107 | MappedRustDiagnostic { |
166 | url: Url { | 108 | url: Url { |
@@ -242,65 +184,7 @@ | |||
242 | tags: None, | 184 | tags: None, |
243 | data: None, | 185 | data: None, |
244 | }, | 186 | }, |
245 | fixes: [ | 187 | fixes: [], |
246 | CodeAction { | ||
247 | title: "return the expression directly", | ||
248 | group: None, | ||
249 | kind: Some( | ||
250 | CodeActionKind( | ||
251 | "quickfix", | ||
252 | ), | ||
253 | ), | ||
254 | edit: Some( | ||
255 | SnippetWorkspaceEdit { | ||
256 | changes: Some( | ||
257 | { | ||
258 | Url { | ||
259 | scheme: "file", | ||
260 | host: None, | ||
261 | port: None, | ||
262 | path: "/test/src/main.rs", | ||
263 | query: None, | ||
264 | fragment: None, | ||
265 | }: [ | ||
266 | TextEdit { | ||
267 | range: Range { | ||
268 | start: Position { | ||
269 | line: 2, | ||
270 | character: 4, | ||
271 | }, | ||
272 | end: Position { | ||
273 | line: 2, | ||
274 | character: 30, | ||
275 | }, | ||
276 | }, | ||
277 | new_text: "", | ||
278 | }, | ||
279 | TextEdit { | ||
280 | range: Range { | ||
281 | start: Position { | ||
282 | line: 3, | ||
283 | character: 4, | ||
284 | }, | ||
285 | end: Position { | ||
286 | line: 3, | ||
287 | character: 5, | ||
288 | }, | ||
289 | }, | ||
290 | new_text: "(0..10).collect()", | ||
291 | }, | ||
292 | ], | ||
293 | }, | ||
294 | ), | ||
295 | document_changes: None, | ||
296 | }, | ||
297 | ), | ||
298 | is_preferred: Some( | ||
299 | true, | ||
300 | ), | ||
301 | data: None, | ||
302 | }, | ||
303 | ], | ||
304 | }, | 188 | }, |
305 | MappedRustDiagnostic { | 189 | MappedRustDiagnostic { |
306 | url: Url { | 190 | url: Url { |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 540759198..757899484 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -74,11 +74,13 @@ fn diagnostic_related_information( | |||
74 | Some(lsp_types::DiagnosticRelatedInformation { location, message }) | 74 | Some(lsp_types::DiagnosticRelatedInformation { location, message }) |
75 | } | 75 | } |
76 | 76 | ||
77 | struct SubDiagnostic { | ||
78 | related: lsp_types::DiagnosticRelatedInformation, | ||
79 | suggested_fix: Option<lsp_ext::CodeAction>, | ||
80 | } | ||
81 | |||
77 | enum MappedRustChildDiagnostic { | 82 | enum MappedRustChildDiagnostic { |
78 | Related { | 83 | SubDiagnostic(SubDiagnostic), |
79 | related: lsp_types::DiagnosticRelatedInformation, | ||
80 | suggested_fix: Option<lsp_ext::CodeAction>, | ||
81 | }, | ||
82 | MessageLine(String), | 84 | MessageLine(String), |
83 | } | 85 | } |
84 | 86 | ||
@@ -105,15 +107,15 @@ fn map_rust_child_diagnostic( | |||
105 | } | 107 | } |
106 | 108 | ||
107 | if edit_map.is_empty() { | 109 | if edit_map.is_empty() { |
108 | MappedRustChildDiagnostic::Related { | 110 | MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { |
109 | related: lsp_types::DiagnosticRelatedInformation { | 111 | related: lsp_types::DiagnosticRelatedInformation { |
110 | location: location(workspace_root, spans[0]), | 112 | location: location(workspace_root, spans[0]), |
111 | message: rd.message.clone(), | 113 | message: rd.message.clone(), |
112 | }, | 114 | }, |
113 | suggested_fix: None, | 115 | suggested_fix: None, |
114 | } | 116 | }) |
115 | } else { | 117 | } else { |
116 | MappedRustChildDiagnostic::Related { | 118 | MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { |
117 | related: lsp_types::DiagnosticRelatedInformation { | 119 | related: lsp_types::DiagnosticRelatedInformation { |
118 | location: location(workspace_root, spans[0]), | 120 | location: location(workspace_root, spans[0]), |
119 | message: rd.message.clone(), | 121 | message: rd.message.clone(), |
@@ -130,7 +132,7 @@ fn map_rust_child_diagnostic( | |||
130 | is_preferred: Some(true), | 132 | is_preferred: Some(true), |
131 | data: None, | 133 | data: None, |
132 | }), | 134 | }), |
133 | } | 135 | }) |
134 | } | 136 | } |
135 | } | 137 | } |
136 | 138 | ||
@@ -175,26 +177,22 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
175 | } | 177 | } |
176 | 178 | ||
177 | let mut needs_primary_span_label = true; | 179 | let mut needs_primary_span_label = true; |
178 | let mut related_information = Vec::new(); | 180 | let mut subdiagnostics = Vec::new(); |
179 | let mut tags = Vec::new(); | 181 | let mut tags = Vec::new(); |
180 | 182 | ||
181 | for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { | 183 | for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { |
182 | let related = diagnostic_related_information(workspace_root, secondary_span); | 184 | let related = diagnostic_related_information(workspace_root, secondary_span); |
183 | if let Some(related) = related { | 185 | if let Some(related) = related { |
184 | related_information.push(related); | 186 | subdiagnostics.push(SubDiagnostic { related, suggested_fix: None }); |
185 | } | 187 | } |
186 | } | 188 | } |
187 | 189 | ||
188 | let mut fixes = Vec::new(); | ||
189 | let mut message = rd.message.clone(); | 190 | let mut message = rd.message.clone(); |
190 | for child in &rd.children { | 191 | for child in &rd.children { |
191 | let child = map_rust_child_diagnostic(workspace_root, &child); | 192 | let child = map_rust_child_diagnostic(workspace_root, &child); |
192 | match child { | 193 | match child { |
193 | MappedRustChildDiagnostic::Related { related, suggested_fix } => { | 194 | MappedRustChildDiagnostic::SubDiagnostic(sub) => { |
194 | related_information.push(related); | 195 | subdiagnostics.push(sub); |
195 | if let Some(code_action) = suggested_fix { | ||
196 | fixes.push(code_action); | ||
197 | } | ||
198 | } | 196 | } |
199 | MappedRustChildDiagnostic::MessageLine(message_line) => { | 197 | MappedRustChildDiagnostic::MessageLine(message_line) => { |
200 | format_to!(message, "\n{}", message_line); | 198 | format_to!(message, "\n{}", message_line); |
@@ -284,7 +282,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
284 | diagnostics.push(MappedRustDiagnostic { | 282 | diagnostics.push(MappedRustDiagnostic { |
285 | url: in_macro_location.uri, | 283 | url: in_macro_location.uri, |
286 | diagnostic, | 284 | diagnostic, |
287 | fixes: fixes.clone(), | 285 | fixes: Vec::new(), |
288 | }); | 286 | }); |
289 | } | 287 | } |
290 | 288 | ||
@@ -298,17 +296,20 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
298 | code_description: code_description.clone(), | 296 | code_description: code_description.clone(), |
299 | source: Some(source.clone()), | 297 | source: Some(source.clone()), |
300 | message, | 298 | message, |
301 | related_information: if related_information.is_empty() { | 299 | related_information: if subdiagnostics.is_empty() { |
302 | None | 300 | None |
303 | } else { | 301 | } else { |
304 | let mut related = related_information.clone(); | 302 | let mut related = subdiagnostics |
303 | .iter() | ||
304 | .map(|sub| sub.related.clone()) | ||
305 | .collect::<Vec<_>>(); | ||
305 | related.extend(related_macro_info); | 306 | related.extend(related_macro_info); |
306 | Some(related) | 307 | Some(related) |
307 | }, | 308 | }, |
308 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | 309 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, |
309 | data: None, | 310 | data: None, |
310 | }, | 311 | }, |
311 | fixes: fixes.clone(), | 312 | fixes: Vec::new(), |
312 | }); | 313 | }); |
313 | 314 | ||
314 | // Emit hint-level diagnostics for all `related_information` entries such as "help"s. | 315 | // Emit hint-level diagnostics for all `related_information` entries such as "help"s. |
@@ -318,21 +319,21 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
318 | location, | 319 | location, |
319 | message: "original diagnostic".to_string(), | 320 | message: "original diagnostic".to_string(), |
320 | }; | 321 | }; |
321 | for info in &related_information { | 322 | for sub in &subdiagnostics { |
322 | // Filter out empty/non-existent messages, as they greatly confuse VS Code. | 323 | // Filter out empty/non-existent messages, as they greatly confuse VS Code. |
323 | if info.message.is_empty() { | 324 | if sub.related.message.is_empty() { |
324 | continue; | 325 | continue; |
325 | } | 326 | } |
326 | diagnostics.push(MappedRustDiagnostic { | 327 | diagnostics.push(MappedRustDiagnostic { |
327 | url: info.location.uri.clone(), | 328 | url: sub.related.location.uri.clone(), |
328 | fixes: fixes.clone(), // share fixes to make them easier to apply | 329 | fixes: sub.suggested_fix.iter().cloned().collect(), |
329 | diagnostic: lsp_types::Diagnostic { | 330 | diagnostic: lsp_types::Diagnostic { |
330 | range: info.location.range, | 331 | range: sub.related.location.range, |
331 | severity: Some(lsp_types::DiagnosticSeverity::Hint), | 332 | severity: Some(lsp_types::DiagnosticSeverity::Hint), |
332 | code: code.clone().map(lsp_types::NumberOrString::String), | 333 | code: code.clone().map(lsp_types::NumberOrString::String), |
333 | code_description: code_description.clone(), | 334 | code_description: code_description.clone(), |
334 | source: Some(source.clone()), | 335 | source: Some(source.clone()), |
335 | message: info.message.clone(), | 336 | message: sub.related.message.clone(), |
336 | related_information: Some(vec![back_ref.clone()]), | 337 | related_information: Some(vec![back_ref.clone()]), |
337 | tags: None, // don't apply modifiers again | 338 | tags: None, // don't apply modifiers again |
338 | data: None, | 339 | data: None, |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index dc67d19a7..1ff2d3fea 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -861,8 +861,9 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | |||
861 | 861 | ||
862 | #[cfg(test)] | 862 | #[cfg(test)] |
863 | mod tests { | 863 | mod tests { |
864 | use hir::PrefixKind; | ||
864 | use ide::Analysis; | 865 | use ide::Analysis; |
865 | use ide_db::helpers::SnippetCap; | 866 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
866 | 867 | ||
867 | use super::*; | 868 | use super::*; |
868 | 869 | ||
@@ -887,7 +888,7 @@ mod tests { | |||
887 | add_call_parenthesis: true, | 888 | add_call_parenthesis: true, |
888 | add_call_argument_snippets: true, | 889 | add_call_argument_snippets: true, |
889 | snippet_cap: SnippetCap::new(true), | 890 | snippet_cap: SnippetCap::new(true), |
890 | merge: None, | 891 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
891 | }, | 892 | }, |
892 | ide_db::base_db::FilePosition { file_id, offset }, | 893 | ide_db::base_db::FilePosition { file_id, offset }, |
893 | ) | 894 | ) |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index cfeaed9e6..52394b337 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.3" |
16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 384d031e7..827ae78f9 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -45,7 +45,7 @@ pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextSize) -> | |||
45 | } | 45 | } |
46 | 46 | ||
47 | pub fn find_node_at_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { | 47 | pub fn find_node_at_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { |
48 | find_covering_element(syntax, range).ancestors().find_map(N::cast) | 48 | syntax.covering_element(range).ancestors().find_map(N::cast) |
49 | } | 49 | } |
50 | 50 | ||
51 | /// Skip to next non `trivia` token | 51 | /// Skip to next non `trivia` token |
@@ -74,10 +74,6 @@ pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Optio | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { | ||
78 | root.covering_element(range) | ||
79 | } | ||
80 | |||
81 | pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNode> { | 77 | pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNode> { |
82 | if u == v { | 78 | if u == v { |
83 | return Some(u.clone()); | 79 | return Some(u.clone()); |
@@ -883,7 +879,7 @@ use crate::AstNode; | |||
883 | 879 | ||
884 | replacements: | 880 | replacements: |
885 | 881 | ||
886 | Line 2: Node(NAME_REF@5..14) -> crate | 882 | Line 2: Token(IDENT@5..14 "text_edit") -> crate |
887 | Line 2: Token([email protected] "TextEdit") -> AstNode | 883 | Line 2: Token([email protected] "TextEdit") -> AstNode |
888 | Line 2: Token([email protected] "\n\n") -> "\n" | 884 | Line 2: Token([email protected] "\n\n") -> "\n" |
889 | 885 | ||
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 92ed2ee9d..1d722db3c 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs | |||
@@ -18,6 +18,9 @@ pub struct NameRef { | |||
18 | } | 18 | } |
19 | impl NameRef { | 19 | impl NameRef { |
20 | pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) } | 20 | pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) } |
21 | pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) } | ||
22 | pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) } | ||
23 | pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } | ||
21 | } | 24 | } |
22 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
23 | pub struct Lifetime { | 26 | pub struct Lifetime { |
@@ -42,9 +45,6 @@ pub struct PathSegment { | |||
42 | pub(crate) syntax: SyntaxNode, | 45 | pub(crate) syntax: SyntaxNode, |
43 | } | 46 | } |
44 | impl PathSegment { | 47 | impl PathSegment { |
45 | pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } | ||
46 | pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) } | ||
47 | pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) } | ||
48 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } | 48 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } |
49 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } | 49 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } |
50 | pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } | 50 | pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } |
@@ -931,6 +931,15 @@ impl WhileExpr { | |||
931 | pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) } | 931 | pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) } |
932 | } | 932 | } |
933 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 933 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
934 | pub struct YieldExpr { | ||
935 | pub(crate) syntax: SyntaxNode, | ||
936 | } | ||
937 | impl ast::AttrsOwner for YieldExpr {} | ||
938 | impl YieldExpr { | ||
939 | pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) } | ||
940 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } | ||
941 | } | ||
942 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
934 | pub struct Label { | 943 | pub struct Label { |
935 | pub(crate) syntax: SyntaxNode, | 944 | pub(crate) syntax: SyntaxNode, |
936 | } | 945 | } |
@@ -1334,6 +1343,7 @@ pub enum Expr { | |||
1334 | TryExpr(TryExpr), | 1343 | TryExpr(TryExpr), |
1335 | TupleExpr(TupleExpr), | 1344 | TupleExpr(TupleExpr), |
1336 | WhileExpr(WhileExpr), | 1345 | WhileExpr(WhileExpr), |
1346 | YieldExpr(YieldExpr), | ||
1337 | } | 1347 | } |
1338 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 1348 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
1339 | pub enum Item { | 1349 | pub enum Item { |
@@ -2386,6 +2396,17 @@ impl AstNode for WhileExpr { | |||
2386 | } | 2396 | } |
2387 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 2397 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
2388 | } | 2398 | } |
2399 | impl AstNode for YieldExpr { | ||
2400 | fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR } | ||
2401 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
2402 | if Self::can_cast(syntax.kind()) { | ||
2403 | Some(Self { syntax }) | ||
2404 | } else { | ||
2405 | None | ||
2406 | } | ||
2407 | } | ||
2408 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
2409 | } | ||
2389 | impl AstNode for Label { | 2410 | impl AstNode for Label { |
2390 | fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL } | 2411 | fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL } |
2391 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 2412 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
@@ -3028,6 +3049,9 @@ impl From<TupleExpr> for Expr { | |||
3028 | impl From<WhileExpr> for Expr { | 3049 | impl From<WhileExpr> for Expr { |
3029 | fn from(node: WhileExpr) -> Expr { Expr::WhileExpr(node) } | 3050 | fn from(node: WhileExpr) -> Expr { Expr::WhileExpr(node) } |
3030 | } | 3051 | } |
3052 | impl From<YieldExpr> for Expr { | ||
3053 | fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) } | ||
3054 | } | ||
3031 | impl AstNode for Expr { | 3055 | impl AstNode for Expr { |
3032 | fn can_cast(kind: SyntaxKind) -> bool { | 3056 | fn can_cast(kind: SyntaxKind) -> bool { |
3033 | match kind { | 3057 | match kind { |
@@ -3035,7 +3059,8 @@ impl AstNode for Expr { | |||
3035 | | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR | 3059 | | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR |
3036 | | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR | 3060 | | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR |
3037 | | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR | 3061 | | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR |
3038 | | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR => true, | 3062 | | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR |
3063 | | YIELD_EXPR => true, | ||
3039 | _ => false, | 3064 | _ => false, |
3040 | } | 3065 | } |
3041 | } | 3066 | } |
@@ -3071,6 +3096,7 @@ impl AstNode for Expr { | |||
3071 | TRY_EXPR => Expr::TryExpr(TryExpr { syntax }), | 3096 | TRY_EXPR => Expr::TryExpr(TryExpr { syntax }), |
3072 | TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }), | 3097 | TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }), |
3073 | WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }), | 3098 | WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }), |
3099 | YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }), | ||
3074 | _ => return None, | 3100 | _ => return None, |
3075 | }; | 3101 | }; |
3076 | Some(res) | 3102 | Some(res) |
@@ -3107,6 +3133,7 @@ impl AstNode for Expr { | |||
3107 | Expr::TryExpr(it) => &it.syntax, | 3133 | Expr::TryExpr(it) => &it.syntax, |
3108 | Expr::TupleExpr(it) => &it.syntax, | 3134 | Expr::TupleExpr(it) => &it.syntax, |
3109 | Expr::WhileExpr(it) => &it.syntax, | 3135 | Expr::WhileExpr(it) => &it.syntax, |
3136 | Expr::YieldExpr(it) => &it.syntax, | ||
3110 | } | 3137 | } |
3111 | } | 3138 | } |
3112 | } | 3139 | } |
@@ -3983,6 +4010,11 @@ impl std::fmt::Display for WhileExpr { | |||
3983 | std::fmt::Display::fmt(self.syntax(), f) | 4010 | std::fmt::Display::fmt(self.syntax(), f) |
3984 | } | 4011 | } |
3985 | } | 4012 | } |
4013 | impl std::fmt::Display for YieldExpr { | ||
4014 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
4015 | std::fmt::Display::fmt(self.syntax(), f) | ||
4016 | } | ||
4017 | } | ||
3986 | impl std::fmt::Display for Label { | 4018 | impl std::fmt::Display for Label { |
3987 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 4019 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
3988 | std::fmt::Display::fmt(self.syntax(), f) | 4020 | std::fmt::Display::fmt(self.syntax(), f) |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 1ed8a96e5..9ffc3ae11 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -108,8 +108,12 @@ pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast:: | |||
108 | ast_from_text(&format!("use {{{}}};", use_trees)) | 108 | ast_from_text(&format!("use {{{}}};", use_trees)) |
109 | } | 109 | } |
110 | 110 | ||
111 | pub fn use_(use_tree: ast::UseTree) -> ast::Use { | 111 | pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use { |
112 | ast_from_text(&format!("use {};", use_tree)) | 112 | let visibility = match visibility { |
113 | None => String::new(), | ||
114 | Some(it) => format!("{} ", it), | ||
115 | }; | ||
116 | ast_from_text(&format!("{}use {};", visibility, use_tree)) | ||
113 | } | 117 | } |
114 | 118 | ||
115 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { | 119 | pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 27381ba80..b8ce71d27 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -156,14 +156,28 @@ impl ast::PathSegment { | |||
156 | .expect("segments are always nested in paths") | 156 | .expect("segments are always nested in paths") |
157 | } | 157 | } |
158 | 158 | ||
159 | pub fn crate_token(&self) -> Option<SyntaxToken> { | ||
160 | self.name_ref().and_then(|it| it.crate_token()) | ||
161 | } | ||
162 | |||
163 | pub fn self_token(&self) -> Option<SyntaxToken> { | ||
164 | self.name_ref().and_then(|it| it.self_token()) | ||
165 | } | ||
166 | |||
167 | pub fn super_token(&self) -> Option<SyntaxToken> { | ||
168 | self.name_ref().and_then(|it| it.super_token()) | ||
169 | } | ||
170 | |||
159 | pub fn kind(&self) -> Option<PathSegmentKind> { | 171 | pub fn kind(&self) -> Option<PathSegmentKind> { |
160 | let res = if let Some(name_ref) = self.name_ref() { | 172 | let res = if let Some(name_ref) = self.name_ref() { |
161 | PathSegmentKind::Name(name_ref) | 173 | match name_ref.syntax().first_token().map(|it| it.kind()) { |
174 | Some(T![self]) => PathSegmentKind::SelfKw, | ||
175 | Some(T![super]) => PathSegmentKind::SuperKw, | ||
176 | Some(T![crate]) => PathSegmentKind::CrateKw, | ||
177 | _ => PathSegmentKind::Name(name_ref), | ||
178 | } | ||
162 | } else { | 179 | } else { |
163 | match self.syntax().first_child_or_token()?.kind() { | 180 | match self.syntax().first_child_or_token()?.kind() { |
164 | T![self] => PathSegmentKind::SelfKw, | ||
165 | T![super] => PathSegmentKind::SuperKw, | ||
166 | T![crate] => PathSegmentKind::CrateKw, | ||
167 | T![<] => { | 181 | T![<] => { |
168 | // <T> or <T as Trait> | 182 | // <T> or <T as Trait> |
169 | // T is any TypeRef, Trait has to be a PathType | 183 | // T is any TypeRef, Trait has to be a PathType |
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index 78eaf3410..76f01084c 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs | |||
@@ -10,7 +10,6 @@ use parser::Reparser; | |||
10 | use text_edit::Indel; | 10 | use text_edit::Indel; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | algo, | ||
14 | parsing::{ | 13 | parsing::{ |
15 | lexer::{lex_single_syntax_kind, tokenize, Token}, | 14 | lexer::{lex_single_syntax_kind, tokenize, Token}, |
16 | text_token_source::TextTokenSource, | 15 | text_token_source::TextTokenSource, |
@@ -41,7 +40,7 @@ fn reparse_token<'node>( | |||
41 | root: &'node SyntaxNode, | 40 | root: &'node SyntaxNode, |
42 | edit: &Indel, | 41 | edit: &Indel, |
43 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { | 42 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
44 | let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); | 43 | let prev_token = root.covering_element(edit.delete).as_token()?.clone(); |
45 | let prev_token_kind = prev_token.kind(); | 44 | let prev_token_kind = prev_token.kind(); |
46 | match prev_token_kind { | 45 | match prev_token_kind { |
47 | WHITESPACE | COMMENT | IDENT | STRING => { | 46 | WHITESPACE | COMMENT | IDENT | STRING => { |
@@ -124,7 +123,7 @@ fn is_contextual_kw(text: &str) -> bool { | |||
124 | } | 123 | } |
125 | 124 | ||
126 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { | 125 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { |
127 | let node = algo::find_covering_element(node, range); | 126 | let node = node.covering_element(range); |
128 | 127 | ||
129 | let mut ancestors = match node { | 128 | let mut ancestors = match node { |
130 | NodeOrToken::Token(it) => it.parent().ancestors(), | 129 | NodeOrToken::Token(it) => it.parent().ancestors(), |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index bfa2dc4ba..7901580ee 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -256,7 +256,7 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro | |||
256 | )); | 256 | )); |
257 | } | 257 | } |
258 | } else if let Some(token) = segment.super_token() { | 258 | } else if let Some(token) = segment.super_token() { |
259 | if !all_supers(&path) { | 259 | if segment.coloncolon_token().is_some() || !all_supers(&path) { |
260 | errors.push(SyntaxError::new( | 260 | errors.push(SyntaxError::new( |
261 | "The `super` keyword may only be preceded by other `super`s", | 261 | "The `super` keyword may only be preceded by other `super`s", |
262 | token.text_range(), | 262 | token.text_range(), |
diff --git a/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast b/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast index 72939fc98..060f47dc4 100644 --- a/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast +++ b/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast | |||
@@ -49,7 +49,8 @@ [email protected] | |||
49 | [email protected] | 49 | [email protected] |
50 | [email protected] | 50 | [email protected] |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] "self" | 52 | [email protected] |
53 | [email protected] "self" | ||
53 | [email protected] "." | 54 | [email protected] "." |
54 | [email protected] | 55 | [email protected] |
55 | [email protected] "scopes" | 56 | [email protected] "scopes" |
@@ -66,7 +67,8 @@ [email protected] | |||
66 | [email protected] | 67 | [email protected] |
67 | [email protected] | 68 | [email protected] |
68 | [email protected] | 69 | [email protected] |
69 | [email protected] "self" | 70 | [email protected] |
71 | [email protected] "self" | ||
70 | [email protected] "." | 72 | [email protected] "." |
71 | [email protected] | 73 | [email protected] |
72 | [email protected] "scopes" | 74 | [email protected] "scopes" |
diff --git a/crates/syntax/test_data/parser/err/0035_use_recover.rast b/crates/syntax/test_data/parser/err/0035_use_recover.rast index 2f03709eb..a95151bc5 100644 --- a/crates/syntax/test_data/parser/err/0035_use_recover.rast +++ b/crates/syntax/test_data/parser/err/0035_use_recover.rast | |||
@@ -24,7 +24,8 @@ [email protected] | |||
24 | [email protected] | 24 | [email protected] |
25 | [email protected] | 25 | [email protected] |
26 | [email protected] | 26 | [email protected] |
27 | [email protected] "crate" | 27 | [email protected] |
28 | [email protected] "crate" | ||
28 | [email protected] "::" | 29 | [email protected] "::" |
29 | [email protected] | 30 | [email protected] |
30 | [email protected] | 31 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast index 284c8715b..7449b5ddf 100644 --- a/crates/syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast +++ b/crates/syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "::" | 8 | [email protected] "::" |
9 | [email protected] "crate" | 9 | [email protected] |
10 | [email protected] "crate" | ||
10 | [email protected] ";" | 11 | [email protected] ";" |
11 | [email protected] "\n" | 12 | [email protected] "\n" |
12 | [email protected] | 13 | [email protected] |
@@ -18,7 +19,8 @@ [email protected] | |||
18 | [email protected] | 19 | [email protected] |
19 | [email protected] | 20 | [email protected] |
20 | [email protected] | 21 | [email protected] |
21 | [email protected] "crate" | 22 | [email protected] |
23 | [email protected] "crate" | ||
22 | [email protected] "," | 24 | [email protected] "," |
23 | [email protected] " " | 25 | [email protected] " " |
24 | [email protected] | 26 | [email protected] |
@@ -35,7 +37,8 @@ [email protected] | |||
35 | [email protected] | 37 | [email protected] |
36 | [email protected] | 38 | [email protected] |
37 | [email protected] | 39 | [email protected] |
38 | [email protected] "crate" | 40 | [email protected] |
41 | [email protected] "crate" | ||
39 | [email protected] "::" | 42 | [email protected] "::" |
40 | [email protected] | 43 | [email protected] |
41 | [email protected] | 44 | [email protected] |
@@ -63,7 +66,8 @@ [email protected] | |||
63 | [email protected] "hello" | 66 | [email protected] "hello" |
64 | [email protected] "::" | 67 | [email protected] "::" |
65 | [email protected] | 68 | [email protected] |
66 | [email protected] "crate" | 69 | [email protected] |
70 | [email protected] "crate" | ||
67 | [email protected] ";" | 71 | [email protected] ";" |
68 | [email protected] "\n" | 72 | [email protected] "\n" |
69 | [email protected] | 73 | [email protected] |
@@ -78,7 +82,8 @@ [email protected] | |||
78 | [email protected] "hello" | 82 | [email protected] "hello" |
79 | [email protected] "::" | 83 | [email protected] "::" |
80 | [email protected] | 84 | [email protected] |
81 | [email protected] "crate" | 85 | [email protected] |
86 | [email protected] "crate" | ||
82 | [email protected] "::" | 87 | [email protected] "::" |
83 | [email protected] | 88 | [email protected] |
84 | [email protected] | 89 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast b/crates/syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast index 2049a9d72..271f8d780 100644 --- a/crates/syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast +++ b/crates/syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "::" | 8 | [email protected] "::" |
9 | [email protected] "super" | 9 | [email protected] |
10 | [email protected] "super" | ||
10 | [email protected] ";" | 11 | [email protected] ";" |
11 | [email protected] "\n" | 12 | [email protected] "\n" |
12 | [email protected] | 13 | [email protected] |
@@ -20,7 +21,8 @@ [email protected] | |||
20 | [email protected] "a" | 21 | [email protected] "a" |
21 | [email protected] "::" | 22 | [email protected] "::" |
22 | [email protected] | 23 | [email protected] |
23 | [email protected] "super" | 24 | [email protected] |
25 | [email protected] "super" | ||
24 | [email protected] ";" | 26 | [email protected] ";" |
25 | [email protected] "\n" | 27 | [email protected] "\n" |
26 | [email protected] | 28 | [email protected] |
@@ -31,14 +33,16 @@ [email protected] | |||
31 | [email protected] | 33 | [email protected] |
32 | [email protected] | 34 | [email protected] |
33 | [email protected] | 35 | [email protected] |
34 | [email protected] "super" | 36 | [email protected] |
37 | [email protected] "super" | ||
35 | [email protected] "::" | 38 | [email protected] "::" |
36 | [email protected] | 39 | [email protected] |
37 | [email protected] | 40 | [email protected] |
38 | [email protected] "a" | 41 | [email protected] "a" |
39 | [email protected] "::" | 42 | [email protected] "::" |
40 | [email protected] | 43 | [email protected] |
41 | [email protected] "super" | 44 | [email protected] |
45 | [email protected] "super" | ||
42 | [email protected] ";" | 46 | [email protected] ";" |
43 | [email protected] "\n" | 47 | [email protected] "\n" |
44 | [email protected] | 48 | [email protected] |
@@ -56,7 +60,8 @@ [email protected] | |||
56 | [email protected] | 60 | [email protected] |
57 | [email protected] | 61 | [email protected] |
58 | [email protected] | 62 | [email protected] |
59 | [email protected] "super" | 63 | [email protected] |
64 | [email protected] "super" | ||
60 | [email protected] "::" | 65 | [email protected] "::" |
61 | [email protected] | 66 | [email protected] |
62 | [email protected] | 67 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast b/crates/syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast index deadf56b4..01f601091 100644 --- a/crates/syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast +++ b/crates/syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "::" | 8 | [email protected] "::" |
9 | [email protected] "self" | 9 | [email protected] |
10 | [email protected] "self" | ||
10 | [email protected] ";" | 11 | [email protected] ";" |
11 | [email protected] "\n" | 12 | [email protected] "\n" |
12 | [email protected] | 13 | [email protected] |
@@ -20,7 +21,8 @@ [email protected] | |||
20 | [email protected] "a" | 21 | [email protected] "a" |
21 | [email protected] "::" | 22 | [email protected] "::" |
22 | [email protected] | 23 | [email protected] |
23 | [email protected] "self" | 24 | [email protected] |
25 | [email protected] "self" | ||
24 | [email protected] ";" | 26 | [email protected] ";" |
25 | [email protected] "\n" | 27 | [email protected] "\n" |
26 | error 6..10: The `self` keyword is only allowed as the first segment of a path | 28 | error 6..10: The `self` keyword is only allowed as the first segment of a path |
diff --git a/crates/syntax/test_data/parser/inline/err/0015_empty_segment.rast b/crates/syntax/test_data/parser/inline/err/0015_empty_segment.rast index e872526d9..d3c5dde58 100644 --- a/crates/syntax/test_data/parser/inline/err/0015_empty_segment.rast +++ b/crates/syntax/test_data/parser/inline/err/0015_empty_segment.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "crate" | 9 | [email protected] |
10 | [email protected] "crate" | ||
10 | [email protected] "::" | 11 | [email protected] "::" |
11 | [email protected] ";" | 12 | [email protected] ";" |
12 | [email protected] "\n" | 13 | [email protected] "\n" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast index f40500e38..970826739 100644 --- a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast +++ b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast | |||
@@ -11,7 +11,8 @@ [email protected] | |||
11 | [email protected] | 11 | [email protected] |
12 | [email protected] | 12 | [email protected] |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] "crate" | 14 | [email protected] |
15 | [email protected] "crate" | ||
15 | [email protected] "::" | 16 | [email protected] "::" |
16 | [email protected] | 17 | [email protected] |
17 | [email protected] | 18 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0052_path_type.rast b/crates/syntax/test_data/parser/inline/ok/0052_path_type.rast index 9bc36bea7..46a103d5b 100644 --- a/crates/syntax/test_data/parser/inline/ok/0052_path_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0052_path_type.rast | |||
@@ -42,7 +42,8 @@ [email protected] | |||
42 | [email protected] | 42 | [email protected] |
43 | [email protected] | 43 | [email protected] |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] "self" | 45 | [email protected] |
46 | [email protected] "self" | ||
46 | [email protected] "::" | 47 | [email protected] "::" |
47 | [email protected] | 48 | [email protected] |
48 | [email protected] | 49 | [email protected] |
@@ -61,7 +62,8 @@ [email protected] | |||
61 | [email protected] | 62 | [email protected] |
62 | [email protected] | 63 | [email protected] |
63 | [email protected] | 64 | [email protected] |
64 | [email protected] "super" | 65 | [email protected] |
66 | [email protected] "super" | ||
65 | [email protected] "::" | 67 | [email protected] "::" |
66 | [email protected] | 68 | [email protected] |
67 | [email protected] | 69 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast b/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast index e4fb32de1..583dcac7e 100644 --- a/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast +++ b/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast | |||
@@ -43,7 +43,8 @@ [email protected] | |||
43 | [email protected] | 43 | [email protected] |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] "super" | 46 | [email protected] |
47 | [email protected] "super" | ||
47 | [email protected] "::" | 48 | [email protected] "::" |
48 | [email protected] | 49 | [email protected] |
49 | [email protected] | 50 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0067_crate_path.rast b/crates/syntax/test_data/parser/inline/ok/0067_crate_path.rast index 702f2e0b0..87c0c48dc 100644 --- a/crates/syntax/test_data/parser/inline/ok/0067_crate_path.rast +++ b/crates/syntax/test_data/parser/inline/ok/0067_crate_path.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "crate" | 9 | [email protected] |
10 | [email protected] "crate" | ||
10 | [email protected] "::" | 11 | [email protected] "::" |
11 | [email protected] | 12 | [email protected] |
12 | [email protected] | 13 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast b/crates/syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast index c4c5bc51e..192a9cca6 100644 --- a/crates/syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast +++ b/crates/syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast | |||
@@ -5,7 +5,8 @@ [email protected] | |||
5 | [email protected] | 5 | [email protected] |
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "crate" | 8 | [email protected] |
9 | [email protected] "crate" | ||
9 | [email protected] "::" | 10 | [email protected] "::" |
10 | [email protected] | 11 | [email protected] |
11 | [email protected] "{" | 12 | [email protected] "{" |
@@ -23,7 +24,8 @@ [email protected] | |||
23 | [email protected] | 24 | [email protected] |
24 | [email protected] | 25 | [email protected] |
25 | [email protected] | 26 | [email protected] |
26 | [email protected] "self" | 27 | [email protected] |
28 | [email protected] "self" | ||
27 | [email protected] "::" | 29 | [email protected] "::" |
28 | [email protected] | 30 | [email protected] |
29 | [email protected] "{" | 31 | [email protected] "{" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast index f3d4ad72c..3016a6574 100644 --- a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast | |||
@@ -30,7 +30,8 @@ [email protected] | |||
30 | [email protected] | 30 | [email protected] |
31 | [email protected] | 31 | [email protected] |
32 | [email protected] | 32 | [email protected] |
33 | [email protected] "crate" | 33 | [email protected] |
34 | [email protected] "crate" | ||
34 | [email protected] "::" | 35 | [email protected] "::" |
35 | [email protected] | 36 | [email protected] |
36 | [email protected] | 37 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast b/crates/syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast index aa4d7a784..0fed2d311 100644 --- a/crates/syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast +++ b/crates/syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast | |||
@@ -17,7 +17,8 @@ [email protected] | |||
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "crate" | 20 | [email protected] |
21 | [email protected] "crate" | ||
21 | [email protected] "::" | 22 | [email protected] "::" |
22 | [email protected] | 23 | [email protected] |
23 | [email protected] | 24 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast index c204f0e2d..a5ee07499 100644 --- a/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast +++ b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast | |||
@@ -16,7 +16,8 @@ [email protected] | |||
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] "super" | 19 | [email protected] |
20 | [email protected] "super" | ||
20 | [email protected] "::" | 21 | [email protected] "::" |
21 | [email protected] | 22 | [email protected] |
22 | [email protected] | 23 | [email protected] |
@@ -42,7 +43,8 @@ [email protected] | |||
42 | [email protected] | 43 | [email protected] |
43 | [email protected] | 44 | [email protected] |
44 | [email protected] | 45 | [email protected] |
45 | [email protected] "crate" | 46 | [email protected] |
47 | [email protected] "crate" | ||
46 | [email protected] "::" | 48 | [email protected] "::" |
47 | [email protected] | 49 | [email protected] |
48 | [email protected] | 50 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rast b/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rast new file mode 100644 index 000000000..05fc90743 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rast | |||
@@ -0,0 +1,28 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "foo" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] "\n " | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] "yield" | ||
17 | [email protected] ";" | ||
18 | [email protected] "\n " | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "yield" | ||
22 | [email protected] " " | ||
23 | [email protected] | ||
24 | [email protected] "1" | ||
25 | [email protected] ";" | ||
26 | [email protected] "\n" | ||
27 | [email protected] "}" | ||
28 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rs b/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rs new file mode 100644 index 000000000..596e221f7 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0159_yield_expr.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn foo() { | ||
2 | yield; | ||
3 | yield 1; | ||
4 | } | ||
diff --git a/crates/syntax/test_data/parser/ok/0013_use_path_self_super.rast b/crates/syntax/test_data/parser/ok/0013_use_path_self_super.rast index 66ab13660..dba74e222 100644 --- a/crates/syntax/test_data/parser/ok/0013_use_path_self_super.rast +++ b/crates/syntax/test_data/parser/ok/0013_use_path_self_super.rast | |||
@@ -6,7 +6,8 @@ [email protected] | |||
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "self" | 9 | [email protected] |
10 | [email protected] "self" | ||
10 | [email protected] "::" | 11 | [email protected] "::" |
11 | [email protected] | 12 | [email protected] |
12 | [email protected] | 13 | [email protected] |
@@ -21,10 +22,12 @@ [email protected] | |||
21 | [email protected] | 22 | [email protected] |
22 | [email protected] | 23 | [email protected] |
23 | [email protected] | 24 | [email protected] |
24 | [email protected] "super" | 25 | [email protected] |
26 | [email protected] "super" | ||
25 | [email protected] "::" | 27 | [email protected] "::" |
26 | [email protected] | 28 | [email protected] |
27 | [email protected] "super" | 29 | [email protected] |
30 | [email protected] "super" | ||
28 | [email protected] "::" | 31 | [email protected] "::" |
29 | [email protected] | 32 | [email protected] |
30 | [email protected] | 33 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast index 0612a71de..21c564a20 100644 --- a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast +++ b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast | |||
@@ -187,7 +187,8 @@ [email protected] | |||
187 | [email protected] | 187 | [email protected] |
188 | [email protected] | 188 | [email protected] |
189 | [email protected] | 189 | [email protected] |
190 | [email protected] "self" | 190 | [email protected] |
191 | [email protected] "self" | ||
191 | [email protected] "::" | 192 | [email protected] "::" |
192 | [email protected] | 193 | [email protected] |
193 | [email protected] | 194 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0034_crate_path_in_call.rast b/crates/syntax/test_data/parser/ok/0034_crate_path_in_call.rast index 5ad8c570d..a0a5ca7f5 100644 --- a/crates/syntax/test_data/parser/ok/0034_crate_path_in_call.rast +++ b/crates/syntax/test_data/parser/ok/0034_crate_path_in_call.rast | |||
@@ -25,7 +25,8 @@ [email protected] | |||
25 | [email protected] | 25 | [email protected] |
26 | [email protected] | 26 | [email protected] |
27 | [email protected] | 27 | [email protected] |
28 | [email protected] "crate" | 28 | [email protected] |
29 | [email protected] "crate" | ||
29 | [email protected] "::" | 30 | [email protected] "::" |
30 | [email protected] | 31 | [email protected] |
31 | [email protected] | 32 | [email protected] |