diff options
Diffstat (limited to 'crates')
109 files changed, 1894 insertions, 595 deletions
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml index 3fd8327d6..ed8ad666f 100644 --- a/crates/assists/Cargo.toml +++ b/crates/assists/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | rustc-hash = "1.1.0" | 13 | rustc-hash = "1.1.0" |
14 | itertools = "0.9.0" | 14 | itertools = "0.10.0" |
15 | either = "1.6.1" | 15 | either = "1.6.1" |
16 | 16 | ||
17 | stdx = { path = "../stdx", version = "0.0.0" } | 17 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index da94e9987..4a3ed7783 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs | |||
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { | |||
204 | } | 204 | } |
205 | PathResolution::Local(_) | 205 | PathResolution::Local(_) |
206 | | PathResolution::TypeParam(_) | 206 | | PathResolution::TypeParam(_) |
207 | | PathResolution::SelfType(_) => None, | 207 | | PathResolution::SelfType(_) |
208 | | PathResolution::ConstParam(_) => None, | ||
208 | PathResolution::Macro(_) => None, | 209 | PathResolution::Macro(_) => None, |
209 | PathResolution::AssocItem(_) => None, | 210 | PathResolution::AssocItem(_) => None, |
210 | } | 211 | } |
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs new file mode 100644 index 000000000..281cf5d24 --- /dev/null +++ b/crates/assists/src/handlers/extract_assignment.rs | |||
@@ -0,0 +1,325 @@ | |||
1 | use hir::AsName; | ||
2 | use syntax::{ | ||
3 | ast::{self, edit::AstNodeEdit, make}, | ||
4 | AstNode, | ||
5 | }; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{ | ||
9 | assist_context::{AssistContext, Assists}, | ||
10 | AssistId, AssistKind, | ||
11 | }; | ||
12 | |||
13 | // Assist: extract_assignment | ||
14 | // | ||
15 | // Extracts variable assigment to outside an if or match statement. | ||
16 | // | ||
17 | // ``` | ||
18 | // fn main() { | ||
19 | // let mut foo = 6; | ||
20 | // | ||
21 | // if true { | ||
22 | // <|>foo = 5; | ||
23 | // } else { | ||
24 | // foo = 4; | ||
25 | // } | ||
26 | // } | ||
27 | // ``` | ||
28 | // -> | ||
29 | // ``` | ||
30 | // fn main() { | ||
31 | // let mut foo = 6; | ||
32 | // | ||
33 | // foo = if true { | ||
34 | // 5 | ||
35 | // } else { | ||
36 | // 4 | ||
37 | // }; | ||
38 | // } | ||
39 | // ``` | ||
40 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
41 | let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name(); | ||
42 | |||
43 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | ||
44 | ( | ||
45 | ast::Expr::cast(if_expr.syntax().to_owned())?, | ||
46 | exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()), | ||
47 | ) | ||
48 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | ||
49 | (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?) | ||
50 | } else { | ||
51 | return None; | ||
52 | }; | ||
53 | |||
54 | let expr_stmt = make::expr_stmt(new_stmt); | ||
55 | |||
56 | acc.add( | ||
57 | AssistId("extract_assignment", AssistKind::RefactorExtract), | ||
58 | "Extract assignment", | ||
59 | old_stmt.syntax().text_range(), | ||
60 | move |edit| { | ||
61 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt)); | ||
62 | }, | ||
63 | ) | ||
64 | } | ||
65 | |||
66 | fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> { | ||
67 | let new_arm_list = match_expr | ||
68 | .match_arm_list()? | ||
69 | .arms() | ||
70 | .map(|arm| { | ||
71 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | ||
72 | let new_block = exprify_block(&block, name)?.indent(block.indent_level()); | ||
73 | Some(arm.replace_descendant(block, new_block)) | ||
74 | } else { | ||
75 | None | ||
76 | } | ||
77 | }) | ||
78 | .collect::<Option<Vec<_>>>()?; | ||
79 | let new_arm_list = match_expr | ||
80 | .match_arm_list()? | ||
81 | .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list)); | ||
82 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | ||
83 | } | ||
84 | |||
85 | fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> { | ||
86 | let then_branch = exprify_block(&statement.then_branch()?, name)?; | ||
87 | let else_branch = match statement.else_branch()? { | ||
88 | ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?), | ||
89 | ast::ElseBranch::IfExpr(expr) => { | ||
90 | mark::hit!(test_extract_assigment_chained_if); | ||
91 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | ||
92 | exprify_if(&expr, name)?.syntax().to_owned(), | ||
93 | )?) | ||
94 | } | ||
95 | }; | ||
96 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | ||
97 | } | ||
98 | |||
99 | fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> { | ||
100 | if block.expr().is_some() { | ||
101 | return None; | ||
102 | } | ||
103 | |||
104 | let mut stmts: Vec<_> = block.statements().collect(); | ||
105 | let stmt = stmts.pop()?; | ||
106 | |||
107 | if let ast::Stmt::ExprStmt(stmt) = stmt { | ||
108 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | ||
109 | if expr.op_kind()? == ast::BinOp::Assignment | ||
110 | && &expr.lhs()?.name_ref()?.as_name() == name | ||
111 | { | ||
112 | // The last statement in the block is an assignment to the name we want | ||
113 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | None | ||
118 | } | ||
119 | |||
120 | #[cfg(test)] | ||
121 | mod tests { | ||
122 | use super::*; | ||
123 | |||
124 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
125 | |||
126 | #[test] | ||
127 | fn test_extract_assignment_if() { | ||
128 | check_assist( | ||
129 | extract_assigment, | ||
130 | r#" | ||
131 | fn foo() { | ||
132 | let mut a = 1; | ||
133 | |||
134 | if true { | ||
135 | <|>a = 2; | ||
136 | } else { | ||
137 | a = 3; | ||
138 | } | ||
139 | }"#, | ||
140 | r#" | ||
141 | fn foo() { | ||
142 | let mut a = 1; | ||
143 | |||
144 | a = if true { | ||
145 | 2 | ||
146 | } else { | ||
147 | 3 | ||
148 | }; | ||
149 | }"#, | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn test_extract_assignment_match() { | ||
155 | check_assist( | ||
156 | extract_assigment, | ||
157 | r#" | ||
158 | fn foo() { | ||
159 | let mut a = 1; | ||
160 | |||
161 | match 1 { | ||
162 | 1 => { | ||
163 | <|>a = 2; | ||
164 | }, | ||
165 | 2 => { | ||
166 | a = 3; | ||
167 | }, | ||
168 | 3 => { | ||
169 | a = 4; | ||
170 | } | ||
171 | } | ||
172 | }"#, | ||
173 | r#" | ||
174 | fn foo() { | ||
175 | let mut a = 1; | ||
176 | |||
177 | a = match 1 { | ||
178 | 1 => { | ||
179 | 2 | ||
180 | }, | ||
181 | 2 => { | ||
182 | 3 | ||
183 | }, | ||
184 | 3 => { | ||
185 | 4 | ||
186 | } | ||
187 | }; | ||
188 | }"#, | ||
189 | ); | ||
190 | } | ||
191 | |||
192 | #[test] | ||
193 | fn test_extract_assignment_not_last_not_applicable() { | ||
194 | check_assist_not_applicable( | ||
195 | extract_assigment, | ||
196 | r#" | ||
197 | fn foo() { | ||
198 | let mut a = 1; | ||
199 | |||
200 | if true { | ||
201 | <|>a = 2; | ||
202 | b = a; | ||
203 | } else { | ||
204 | a = 3; | ||
205 | } | ||
206 | }"#, | ||
207 | ) | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn test_extract_assignment_chained_if() { | ||
212 | mark::check!(test_extract_assigment_chained_if); | ||
213 | check_assist( | ||
214 | extract_assigment, | ||
215 | r#" | ||
216 | fn foo() { | ||
217 | let mut a = 1; | ||
218 | |||
219 | if true { | ||
220 | <|>a = 2; | ||
221 | } else if false { | ||
222 | a = 3; | ||
223 | } else { | ||
224 | a = 4; | ||
225 | } | ||
226 | }"#, | ||
227 | r#" | ||
228 | fn foo() { | ||
229 | let mut a = 1; | ||
230 | |||
231 | a = if true { | ||
232 | 2 | ||
233 | } else if false { | ||
234 | 3 | ||
235 | } else { | ||
236 | 4 | ||
237 | }; | ||
238 | }"#, | ||
239 | ); | ||
240 | } | ||
241 | |||
242 | #[test] | ||
243 | fn test_extract_assigment_retains_stmts() { | ||
244 | check_assist( | ||
245 | extract_assigment, | ||
246 | r#" | ||
247 | fn foo() { | ||
248 | let mut a = 1; | ||
249 | |||
250 | if true { | ||
251 | let b = 2; | ||
252 | <|>a = 2; | ||
253 | } else { | ||
254 | let b = 3; | ||
255 | a = 3; | ||
256 | } | ||
257 | }"#, | ||
258 | r#" | ||
259 | fn foo() { | ||
260 | let mut a = 1; | ||
261 | |||
262 | a = if true { | ||
263 | let b = 2; | ||
264 | 2 | ||
265 | } else { | ||
266 | let b = 3; | ||
267 | 3 | ||
268 | }; | ||
269 | }"#, | ||
270 | ) | ||
271 | } | ||
272 | |||
273 | #[test] | ||
274 | fn extract_assignment_let_stmt_not_applicable() { | ||
275 | check_assist_not_applicable( | ||
276 | extract_assigment, | ||
277 | r#" | ||
278 | fn foo() { | ||
279 | let mut a = 1; | ||
280 | |||
281 | let b = if true { | ||
282 | <|>a = 2 | ||
283 | } else { | ||
284 | a = 3 | ||
285 | }; | ||
286 | }"#, | ||
287 | ) | ||
288 | } | ||
289 | |||
290 | #[test] | ||
291 | fn extract_assignment_if_missing_assigment_not_applicable() { | ||
292 | check_assist_not_applicable( | ||
293 | extract_assigment, | ||
294 | r#" | ||
295 | fn foo() { | ||
296 | let mut a = 1; | ||
297 | |||
298 | if true { | ||
299 | <|>a = 2; | ||
300 | } else {} | ||
301 | }"#, | ||
302 | ) | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn extract_assignment_match_missing_assigment_not_applicable() { | ||
307 | check_assist_not_applicable( | ||
308 | extract_assigment, | ||
309 | r#" | ||
310 | fn foo() { | ||
311 | let mut a = 1; | ||
312 | |||
313 | match 1 { | ||
314 | 1 => { | ||
315 | <|>a = 2; | ||
316 | }, | ||
317 | 2 => { | ||
318 | a = 3; | ||
319 | }, | ||
320 | 3 => {}, | ||
321 | } | ||
322 | }"#, | ||
323 | ) | ||
324 | } | ||
325 | } | ||
diff --git a/crates/assists/src/handlers/extract_variable.rs b/crates/assists/src/handlers/extract_variable.rs index d2ae137cd..9957012fe 100644 --- a/crates/assists/src/handlers/extract_variable.rs +++ b/crates/assists/src/handlers/extract_variable.rs | |||
@@ -91,7 +91,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
91 | // extra newlines in the indent block | 91 | // extra newlines in the indent block |
92 | let text = indent.text(); | 92 | let text = indent.text(); |
93 | if text.starts_with('\n') { | 93 | if text.starts_with('\n') { |
94 | buf.push_str("\n"); | 94 | buf.push('\n'); |
95 | buf.push_str(text.trim_start_matches('\n')); | 95 | buf.push_str(text.trim_start_matches('\n')); |
96 | } else { | 96 | } else { |
97 | buf.push_str(text); | 97 | buf.push_str(text); |
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs index cb60a3128..f9a62b9fa 100644 --- a/crates/assists/src/handlers/fill_match_arms.rs +++ b/crates/assists/src/handlers/fill_match_arms.rs | |||
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio | |||
196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); | 196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); |
197 | 197 | ||
198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
199 | let pat: ast::Pat = match var.source(db).value.kind() { | 199 | let pat: ast::Pat = match var.source(db)?.value.kind() { |
200 | ast::StructKind::Tuple(field_list) => { | 200 | ast::StructKind::Tuple(field_list) => { |
201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); | 201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); |
202 | make::tuple_struct_pat(path, pats).into() | 202 | make::tuple_struct_pat(path, pats).into() |
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs index 8558a8ff0..de1e8f0bf 100644 --- a/crates/assists/src/handlers/fix_visibility.rs +++ b/crates/assists/src/handlers/fix_visibility.rs | |||
@@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
97 | let parent_name = parent.name(ctx.db()); | 97 | let parent_name = parent.name(ctx.db()); |
98 | let target_module = parent.module(ctx.db()); | 98 | let target_module = parent.module(ctx.db()); |
99 | 99 | ||
100 | let in_file_source = record_field_def.source(ctx.db()); | 100 | #[allow(deprecated)] |
101 | let in_file_source = record_field_def.source(ctx.db())?; | ||
101 | let (offset, current_visibility, target) = match in_file_source.value { | 102 | let (offset, current_visibility, target) = match in_file_source.value { |
102 | hir::FieldSource::Named(it) => { | 103 | hir::FieldSource::Named(it) => { |
103 | let s = it.syntax(); | 104 | let s = it.syntax(); |
@@ -145,53 +146,53 @@ fn target_data_for_def( | |||
145 | fn offset_target_and_file_id<S, Ast>( | 146 | fn offset_target_and_file_id<S, Ast>( |
146 | db: &dyn HirDatabase, | 147 | db: &dyn HirDatabase, |
147 | x: S, | 148 | x: S, |
148 | ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) | 149 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)> |
149 | where | 150 | where |
150 | S: HasSource<Ast = Ast>, | 151 | S: HasSource<Ast = Ast>, |
151 | Ast: AstNode + ast::VisibilityOwner, | 152 | Ast: AstNode + ast::VisibilityOwner, |
152 | { | 153 | { |
153 | let source = x.source(db); | 154 | let source = x.source(db)?; |
154 | let in_file_syntax = source.syntax(); | 155 | let in_file_syntax = source.syntax(); |
155 | let file_id = in_file_syntax.file_id; | 156 | let file_id = in_file_syntax.file_id; |
156 | let syntax = in_file_syntax.value; | 157 | let syntax = in_file_syntax.value; |
157 | let current_visibility = source.value.visibility(); | 158 | let current_visibility = source.value.visibility(); |
158 | ( | 159 | Some(( |
159 | vis_offset(syntax), | 160 | vis_offset(syntax), |
160 | current_visibility, | 161 | current_visibility, |
161 | syntax.text_range(), | 162 | syntax.text_range(), |
162 | file_id.original_file(db.upcast()), | 163 | file_id.original_file(db.upcast()), |
163 | ) | 164 | )) |
164 | } | 165 | } |
165 | 166 | ||
166 | let target_name; | 167 | let target_name; |
167 | let (offset, current_visibility, target, target_file) = match def { | 168 | let (offset, current_visibility, target, target_file) = match def { |
168 | hir::ModuleDef::Function(f) => { | 169 | hir::ModuleDef::Function(f) => { |
169 | target_name = Some(f.name(db)); | 170 | target_name = Some(f.name(db)); |
170 | offset_target_and_file_id(db, f) | 171 | offset_target_and_file_id(db, f)? |
171 | } | 172 | } |
172 | hir::ModuleDef::Adt(adt) => { | 173 | hir::ModuleDef::Adt(adt) => { |
173 | target_name = Some(adt.name(db)); | 174 | target_name = Some(adt.name(db)); |
174 | match adt { | 175 | match adt { |
175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | 176 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?, |
176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | 177 | hir::Adt::Union(u) => offset_target_and_file_id(db, u)?, |
177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | 178 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?, |
178 | } | 179 | } |
179 | } | 180 | } |
180 | hir::ModuleDef::Const(c) => { | 181 | hir::ModuleDef::Const(c) => { |
181 | target_name = c.name(db); | 182 | target_name = c.name(db); |
182 | offset_target_and_file_id(db, c) | 183 | offset_target_and_file_id(db, c)? |
183 | } | 184 | } |
184 | hir::ModuleDef::Static(s) => { | 185 | hir::ModuleDef::Static(s) => { |
185 | target_name = s.name(db); | 186 | target_name = s.name(db); |
186 | offset_target_and_file_id(db, s) | 187 | offset_target_and_file_id(db, s)? |
187 | } | 188 | } |
188 | hir::ModuleDef::Trait(t) => { | 189 | hir::ModuleDef::Trait(t) => { |
189 | target_name = Some(t.name(db)); | 190 | target_name = Some(t.name(db)); |
190 | offset_target_and_file_id(db, t) | 191 | offset_target_and_file_id(db, t)? |
191 | } | 192 | } |
192 | hir::ModuleDef::TypeAlias(t) => { | 193 | hir::ModuleDef::TypeAlias(t) => { |
193 | target_name = Some(t.name(db)); | 194 | target_name = Some(t.name(db)); |
194 | offset_target_and_file_id(db, t) | 195 | offset_target_and_file_id(db, t)? |
195 | } | 196 | } |
196 | hir::ModuleDef::Module(m) => { | 197 | hir::ModuleDef::Module(m) => { |
197 | target_name = m.name(db); | 198 | target_name = m.name(db); |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 4d6a1956b..cb7a5c104 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -62,21 +62,22 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
63 | let current_crate = current_module.krate(); | 63 | let current_crate = current_module.krate(); |
64 | 64 | ||
65 | let found_traits = | 65 | let found_traits = imports_locator::find_exact_imports( |
66 | imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text()) | 66 | &ctx.sema, |
67 | .filter_map( | 67 | current_crate, |
68 | |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { | 68 | trait_token.text().to_string(), |
69 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), | 69 | ) |
70 | _ => None, | 70 | .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { |
71 | }, | 71 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), |
72 | ) | 72 | _ => None, |
73 | .flat_map(|trait_| { | 73 | }) |
74 | current_module | 74 | .flat_map(|trait_| { |
75 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) | 75 | current_module |
76 | .as_ref() | 76 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) |
77 | .map(mod_path_to_ast) | 77 | .as_ref() |
78 | .zip(Some(trait_)) | 78 | .map(mod_path_to_ast) |
79 | }); | 79 | .zip(Some(trait_)) |
80 | }); | ||
80 | 81 | ||
81 | let mut no_traits_found = true; | 82 | let mut no_traits_found = true; |
82 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 83 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index fdec886e9..212464f85 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -116,6 +116,7 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_assignment; | ||
119 | mod extract_module_to_file; | 120 | mod extract_module_to_file; |
120 | mod extract_struct_from_enum_variant; | 121 | mod extract_struct_from_enum_variant; |
121 | mod extract_variable; | 122 | mod extract_variable; |
@@ -167,6 +168,7 @@ mod handlers { | |||
167 | convert_integer_literal::convert_integer_literal, | 168 | convert_integer_literal::convert_integer_literal, |
168 | early_return::convert_to_guarded_return, | 169 | early_return::convert_to_guarded_return, |
169 | expand_glob_import::expand_glob_import, | 170 | expand_glob_import::expand_glob_import, |
171 | extract_assignment::extract_assigment, | ||
170 | extract_module_to_file::extract_module_to_file, | 172 | extract_module_to_file::extract_module_to_file, |
171 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
172 | extract_variable::extract_variable, | 174 | extract_variable::extract_variable, |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index d3dfe24e7..b91a816e8 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -238,6 +238,35 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn main() { | ||
257 | let mut foo = 6; | ||
258 | |||
259 | foo = if true { | ||
260 | 5 | ||
261 | } else { | ||
262 | 4 | ||
263 | }; | ||
264 | } | ||
265 | "#####, | ||
266 | ) | ||
267 | } | ||
268 | |||
269 | #[test] | ||
241 | fn doctest_extract_module_to_file() { | 270 | fn doctest_extract_module_to_file() { |
242 | check_doc_test( | 271 | check_doc_test( |
243 | "extract_module_to_file", | 272 | "extract_module_to_file", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d41084b59..b05596446 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -94,14 +94,18 @@ pub fn filter_assoc_items( | |||
94 | ast::AssocItem::MacroCall(_) => None, | 94 | ast::AssocItem::MacroCall(_) => None, |
95 | } | 95 | } |
96 | .is_some() | 96 | .is_some() |
97 | }; | 97 | } |
98 | 98 | ||
99 | items | 99 | items |
100 | .iter() | 100 | .iter() |
101 | .map(|i| match i { | 101 | // Note: This throws away items with no source. |
102 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), | 102 | .filter_map(|i| { |
103 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), | 103 | let item = match i { |
104 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), | 104 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value), |
105 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value), | ||
106 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value), | ||
107 | }; | ||
108 | Some(item) | ||
105 | }) | 109 | }) |
106 | .filter(has_def_name) | 110 | .filter(has_def_name) |
107 | .filter(|it| match it { | 111 | .filter(|it| match it { |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs index ff5c0e78e..4ce82c1ba 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/assists/src/utils/import_assets.rs | |||
@@ -179,25 +179,24 @@ impl ImportAssets { | |||
179 | } | 179 | } |
180 | }; | 180 | }; |
181 | 181 | ||
182 | let mut res = | 182 | let mut res = imports_locator::find_exact_imports( |
183 | imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query()) | 183 | sema, |
184 | .filter_map(filter) | 184 | current_crate, |
185 | .filter_map(|candidate| { | 185 | self.get_search_query().to_string(), |
186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); | 186 | ) |
187 | if let Some(prefix_kind) = prefixed { | 187 | .filter_map(filter) |
188 | self.module_with_name_to_import.find_use_path_prefixed( | 188 | .filter_map(|candidate| { |
189 | db, | 189 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); |
190 | item, | 190 | if let Some(prefix_kind) = prefixed { |
191 | prefix_kind, | 191 | self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind) |
192 | ) | 192 | } else { |
193 | } else { | 193 | self.module_with_name_to_import.find_use_path(db, item) |
194 | self.module_with_name_to_import.find_use_path(db, item) | 194 | } |
195 | } | 195 | .map(|path| (path, item)) |
196 | .map(|path| (path, item)) | 196 | }) |
197 | }) | 197 | .filter(|(use_path, _)| use_path.len() > 1) |
198 | .filter(|(use_path, _)| use_path.len() > 1) | 198 | .take(20) |
199 | .take(20) | 199 | .collect::<Vec<_>>(); |
200 | .collect::<Vec<_>>(); | ||
201 | res.sort_by_key(|(path, _)| path.clone()); | 200 | res.sort_by_key(|(path, _)| path.clone()); |
202 | res | 201 | res |
203 | } | 202 | } |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 9567bcc42..2dd8fbe67 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -190,10 +190,11 @@ pub struct CrateData { | |||
190 | pub proc_macro: Vec<ProcMacro>, | 190 | pub proc_macro: Vec<ProcMacro>, |
191 | } | 191 | } |
192 | 192 | ||
193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
194 | pub enum Edition { | 194 | pub enum Edition { |
195 | Edition2018, | ||
196 | Edition2015, | 195 | Edition2015, |
196 | Edition2018, | ||
197 | Edition2021, | ||
197 | } | 198 | } |
198 | 199 | ||
199 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 200 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
@@ -393,6 +394,7 @@ impl FromStr for Edition { | |||
393 | let res = match s { | 394 | let res = match s { |
394 | "2015" => Edition::Edition2015, | 395 | "2015" => Edition::Edition2015, |
395 | "2018" => Edition::Edition2018, | 396 | "2018" => Edition::Edition2018, |
397 | "2021" => Edition::Edition2021, | ||
396 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), | 398 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), |
397 | }; | 399 | }; |
398 | Ok(res) | 400 | Ok(res) |
@@ -404,6 +406,7 @@ impl fmt::Display for Edition { | |||
404 | f.write_str(match self { | 406 | f.write_str(match self { |
405 | Edition::Edition2015 => "2015", | 407 | Edition::Edition2015 => "2015", |
406 | Edition::Edition2018 => "2018", | 408 | Edition::Edition2018 => "2018", |
409 | Edition::Edition2021 => "2021", | ||
407 | }) | 410 | }) |
408 | } | 411 | } |
409 | } | 412 | } |
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 35e169a28..78e93e78e 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | itertools = "0.9.0" | 13 | itertools = "0.10.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | either = "1.6.1" | 16 | either = "1.6.1" |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d9fe13485..00c9e76f0 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -106,8 +106,9 @@ impl Completions { | |||
106 | func: hir::Function, | 106 | func: hir::Function, |
107 | local_name: Option<String>, | 107 | local_name: Option<String>, |
108 | ) { | 108 | ) { |
109 | let item = render_fn(RenderContext::new(ctx), None, local_name, func); | 109 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { |
110 | self.add(item) | 110 | self.add(item) |
111 | } | ||
111 | } | 112 | } |
112 | 113 | ||
113 | pub(crate) fn add_variant_pat( | 114 | pub(crate) fn add_variant_pat( |
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs index 19ce2482f..8695eed39 100644 --- a/crates/completion/src/completions/attribute.rs +++ b/crates/completion/src/completions/attribute.rs | |||
@@ -234,7 +234,7 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin | |||
234 | current_derive = String::new(); | 234 | current_derive = String::new(); |
235 | } | 235 | } |
236 | } else { | 236 | } else { |
237 | current_derive.push_str(token.to_string().trim()); | 237 | current_derive.push_str(token.text().trim()); |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs index d6db82a93..3883d6d21 100644 --- a/crates/completion/src/completions/postfix.rs +++ b/crates/completion/src/completions/postfix.rs | |||
@@ -502,7 +502,7 @@ fn main() { | |||
502 | #[test] | 502 | #[test] |
503 | fn postfix_completion_for_format_like_strings() { | 503 | fn postfix_completion_for_format_like_strings() { |
504 | check_edit( | 504 | check_edit( |
505 | "fmt", | 505 | "format", |
506 | r#"fn main() { "{some_var:?}".<|> }"#, | 506 | r#"fn main() { "{some_var:?}".<|> }"#, |
507 | r#"fn main() { format!("{:?}", some_var) }"#, | 507 | r#"fn main() { format!("{:?}", some_var) }"#, |
508 | ); | 508 | ); |
diff --git a/crates/completion/src/completions/postfix/format_like.rs b/crates/completion/src/completions/postfix/format_like.rs index 88ba86acb..def4b13fb 100644 --- a/crates/completion/src/completions/postfix/format_like.rs +++ b/crates/completion/src/completions/postfix/format_like.rs | |||
@@ -22,7 +22,7 @@ use syntax::ast::{self, AstToken}; | |||
22 | 22 | ||
23 | /// Mapping ("postfix completion item" => "macro to use") | 23 | /// Mapping ("postfix completion item" => "macro to use") |
24 | static KINDS: &[(&str, &str)] = &[ | 24 | static KINDS: &[(&str, &str)] = &[ |
25 | ("fmt", "format!"), | 25 | ("format", "format!"), |
26 | ("panic", "panic!"), | 26 | ("panic", "panic!"), |
27 | ("println", "println!"), | 27 | ("println", "println!"), |
28 | ("eprintln", "eprintln!"), | 28 | ("eprintln", "eprintln!"), |
@@ -108,7 +108,8 @@ impl FormatStrParser { | |||
108 | // "{MyStruct { val_a: 0, val_b: 1 }}". | 108 | // "{MyStruct { val_a: 0, val_b: 1 }}". |
109 | let mut inexpr_open_count = 0; | 109 | let mut inexpr_open_count = 0; |
110 | 110 | ||
111 | for chr in self.input.chars() { | 111 | let mut chars = self.input.chars().peekable(); |
112 | while let Some(chr) = chars.next() { | ||
112 | match (self.state, chr) { | 113 | match (self.state, chr) { |
113 | (State::NotExpr, '{') => { | 114 | (State::NotExpr, '{') => { |
114 | self.output.push(chr); | 115 | self.output.push(chr); |
@@ -157,6 +158,11 @@ impl FormatStrParser { | |||
157 | inexpr_open_count -= 1; | 158 | inexpr_open_count -= 1; |
158 | } | 159 | } |
159 | } | 160 | } |
161 | (State::Expr, ':') if chars.peek().copied() == Some(':') => { | ||
162 | // path seperator | ||
163 | current_expr.push_str("::"); | ||
164 | chars.next(); | ||
165 | } | ||
160 | (State::Expr, ':') => { | 166 | (State::Expr, ':') => { |
161 | if inexpr_open_count == 0 { | 167 | if inexpr_open_count == 0 { |
162 | // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" | 168 | // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" |
@@ -249,6 +255,9 @@ mod tests { | |||
249 | expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], | 255 | expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], |
250 | ), | 256 | ), |
251 | ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), | 257 | ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), |
258 | ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]), | ||
259 | ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]), | ||
260 | ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]), | ||
252 | ]; | 261 | ]; |
253 | 262 | ||
254 | for (input, output) in test_vector { | 263 | for (input, output) in test_vector { |
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs index 91bf4a8ad..e58b9a274 100644 --- a/crates/completion/src/completions/record.rs +++ b/crates/completion/src/completions/record.rs | |||
@@ -20,13 +20,17 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
20 | 20 | ||
21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); | 21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); |
22 | if impl_default_trait && !missing_fields.is_empty() { | 22 | if impl_default_trait && !missing_fields.is_empty() { |
23 | let completion_text = "..Default::default()"; | ||
24 | let completion_text = completion_text | ||
25 | .strip_prefix(ctx.token.to_string().as_str()) | ||
26 | .unwrap_or(completion_text); | ||
23 | acc.add( | 27 | acc.add( |
24 | CompletionItem::new( | 28 | CompletionItem::new( |
25 | CompletionKind::Snippet, | 29 | CompletionKind::Snippet, |
26 | ctx.source_range(), | 30 | ctx.source_range(), |
27 | "..Default::default()", | 31 | "..Default::default()", |
28 | ) | 32 | ) |
29 | .insert_text("..Default::default()") | 33 | .insert_text(completion_text) |
30 | .kind(CompletionItemKind::Field) | 34 | .kind(CompletionItemKind::Field) |
31 | .build(), | 35 | .build(), |
32 | ); | 36 | ); |
@@ -48,7 +52,10 @@ mod tests { | |||
48 | use expect_test::{expect, Expect}; | 52 | use expect_test::{expect, Expect}; |
49 | use ide_db::helpers::FamousDefs; | 53 | use ide_db::helpers::FamousDefs; |
50 | 54 | ||
51 | use crate::{test_utils::completion_list, CompletionKind}; | 55 | use crate::{ |
56 | test_utils::{self, completion_list}, | ||
57 | CompletionKind, | ||
58 | }; | ||
52 | 59 | ||
53 | fn check(ra_fixture: &str, expect: Expect) { | 60 | fn check(ra_fixture: &str, expect: Expect) { |
54 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 61 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
@@ -63,6 +70,18 @@ mod tests { | |||
63 | expect.assert_eq(&actual); | 70 | expect.assert_eq(&actual); |
64 | } | 71 | } |
65 | 72 | ||
73 | fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
74 | test_utils::check_edit( | ||
75 | what, | ||
76 | &format!( | ||
77 | "//- /main.rs crate:main deps:core{}\n{}", | ||
78 | ra_fixture_before, | ||
79 | FamousDefs::FIXTURE, | ||
80 | ), | ||
81 | &(ra_fixture_after.to_owned() + "\n"), | ||
82 | ); | ||
83 | } | ||
84 | |||
66 | #[test] | 85 | #[test] |
67 | fn test_record_literal_field_default() { | 86 | fn test_record_literal_field_default() { |
68 | let test_code = r#" | 87 | let test_code = r#" |
@@ -102,6 +121,51 @@ fn process(f: S) { | |||
102 | } | 121 | } |
103 | 122 | ||
104 | #[test] | 123 | #[test] |
124 | fn test_record_literal_field_default_completion() { | ||
125 | check_edit( | ||
126 | "..Default::default()", | ||
127 | r#" | ||
128 | struct S { foo: u32, bar: usize } | ||
129 | |||
130 | impl core::default::Default for S { | ||
131 | fn default() -> Self { | ||
132 | S { | ||
133 | foo: 0, | ||
134 | bar: 0, | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | fn process(f: S) { | ||
140 | let other = S { | ||
141 | foo: 5, | ||
142 | .<|> | ||
143 | }; | ||
144 | } | ||
145 | "#, | ||
146 | r#" | ||
147 | struct S { foo: u32, bar: usize } | ||
148 | |||
149 | impl core::default::Default for S { | ||
150 | fn default() -> Self { | ||
151 | S { | ||
152 | foo: 0, | ||
153 | bar: 0, | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | fn process(f: S) { | ||
159 | let other = S { | ||
160 | foo: 5, | ||
161 | ..Default::default() | ||
162 | }; | ||
163 | } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
105 | fn test_record_literal_field_without_default() { | 169 | fn test_record_literal_field_without_default() { |
106 | let test_code = r#" | 170 | let test_code = r#" |
107 | struct S { foo: u32, bar: usize } | 171 | struct S { foo: u32, bar: usize } |
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs index c4e0d0669..54bb897e9 100644 --- a/crates/completion/src/completions/trait_impl.rs +++ b/crates/completion/src/completions/trait_impl.rs | |||
@@ -156,19 +156,21 @@ fn add_function_impl( | |||
156 | }; | 156 | }; |
157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
158 | 158 | ||
159 | let function_decl = function_declaration(&func.source(ctx.db).value); | 159 | if let Some(src) = func.source(ctx.db) { |
160 | match ctx.config.snippet_cap { | 160 | let function_decl = function_declaration(&src.value); |
161 | Some(cap) => { | 161 | match ctx.config.snippet_cap { |
162 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 162 | Some(cap) => { |
163 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 163 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
164 | } | 164 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
165 | None => { | 165 | } |
166 | let header = format!("{} {{", function_decl); | 166 | None => { |
167 | builder.text_edit(TextEdit::replace(range, header)) | 167 | let header = format!("{} {{", function_decl); |
168 | builder.text_edit(TextEdit::replace(range, header)) | ||
169 | } | ||
168 | } | 170 | } |
171 | .kind(completion_kind) | ||
172 | .add_to(acc); | ||
169 | } | 173 | } |
170 | .kind(completion_kind) | ||
171 | .add_to(acc); | ||
172 | } | 174 | } |
173 | 175 | ||
174 | fn add_type_alias_impl( | 176 | fn add_type_alias_impl( |
@@ -200,16 +202,19 @@ fn add_const_impl( | |||
200 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 202 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
201 | 203 | ||
202 | if let Some(const_name) = const_name { | 204 | if let Some(const_name) = const_name { |
203 | let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); | 205 | if let Some(source) = const_.source(ctx.db) { |
204 | 206 | let snippet = make_const_compl_syntax(&source.value); | |
205 | let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | 207 | |
206 | 208 | let range = | |
207 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) | 209 | TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); |
208 | .text_edit(TextEdit::replace(range, snippet)) | 210 | |
209 | .lookup_by(const_name) | 211 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) |
210 | .kind(CompletionItemKind::Const) | 212 | .text_edit(TextEdit::replace(range, snippet)) |
211 | .set_documentation(const_.docs(ctx.db)) | 213 | .lookup_by(const_name) |
212 | .add_to(acc); | 214 | .kind(CompletionItemKind::Const) |
215 | .set_documentation(const_.docs(ctx.db)) | ||
216 | .add_to(acc); | ||
217 | } | ||
213 | } | 218 | } |
214 | } | 219 | } |
215 | 220 | ||
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index d09849752..81a6d00e2 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -101,8 +101,9 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
101 | // | 101 | // |
102 | // .Fuzzy search details | 102 | // .Fuzzy search details |
103 | // | 103 | // |
104 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only | 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), also not in the module indentifiers. | 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. | ||
106 | // | 107 | // |
107 | // .Merge Behavior | 108 | // .Merge Behavior |
108 | // | 109 | // |
@@ -126,15 +127,20 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
126 | let _p = profile::span("fuzzy_completion"); | 127 | let _p = profile::span("fuzzy_completion"); |
127 | let potential_import_name = ctx.token.to_string(); | 128 | let potential_import_name = ctx.token.to_string(); |
128 | 129 | ||
130 | if potential_import_name.len() < 2 { | ||
131 | return None; | ||
132 | } | ||
133 | |||
129 | let current_module = ctx.scope.module()?; | 134 | let current_module = ctx.scope.module()?; |
130 | let anchor = ctx.name_ref_syntax.as_ref()?; | 135 | let anchor = ctx.name_ref_syntax.as_ref()?; |
131 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | 136 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; |
132 | 137 | ||
138 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
133 | let mut all_mod_paths = imports_locator::find_similar_imports( | 139 | let mut all_mod_paths = imports_locator::find_similar_imports( |
134 | &ctx.sema, | 140 | &ctx.sema, |
135 | ctx.krate?, | 141 | ctx.krate?, |
136 | Some(100), | 142 | Some(40), |
137 | &potential_import_name, | 143 | potential_import_name, |
138 | true, | 144 | true, |
139 | ) | 145 | ) |
140 | .filter_map(|import_candidate| { | 146 | .filter_map(|import_candidate| { |
@@ -150,7 +156,6 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
150 | .filter(|(mod_path, _)| mod_path.len() > 1) | 156 | .filter(|(mod_path, _)| mod_path.len() > 1) |
151 | .collect::<Vec<_>>(); | 157 | .collect::<Vec<_>>(); |
152 | 158 | ||
153 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
154 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | 159 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { |
155 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | 160 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) |
156 | }); | 161 | }); |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 8e27bb153..c57d05bbe 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -137,7 +137,7 @@ pub fn resolve_completion_edits( | |||
137 | config: &CompletionConfig, | 137 | config: &CompletionConfig, |
138 | position: FilePosition, | 138 | position: FilePosition, |
139 | full_import_path: &str, | 139 | full_import_path: &str, |
140 | imported_name: &str, | 140 | imported_name: String, |
141 | ) -> Option<Vec<TextEdit>> { | 141 | ) -> Option<Vec<TextEdit>> { |
142 | let ctx = CompletionContext::new(db, position, config)?; | 142 | let ctx = CompletionContext::new(db, position, config)?; |
143 | let anchor = ctx.name_ref_syntax.as_ref()?; | 143 | let anchor = ctx.name_ref_syntax.as_ref()?; |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1ba7201a1..ac0b2a513 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -157,8 +157,7 @@ impl<'a> Render<'a> { | |||
157 | 157 | ||
158 | let kind = match resolution { | 158 | let kind = match resolution { |
159 | ScopeDef::ModuleDef(Function(func)) => { | 159 | ScopeDef::ModuleDef(Function(func)) => { |
160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); |
161 | return Some(item); | ||
162 | } | 161 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | 162 | ScopeDef::ModuleDef(Variant(_)) |
164 | if self.ctx.completion.is_pat_binding_or_const | 163 | if self.ctx.completion.is_pat_binding_or_const |
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs index 039bdabc0..ce924f309 100644 --- a/crates/completion/src/render/const_.rs +++ b/crates/completion/src/render/const_.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | const_: hir::Const, | 16 | const_: hir::Const, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | ConstRender::new(ctx, const_).render() | 18 | ConstRender::new(ctx, const_)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct ConstRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> ConstRender<'a> { | 28 | impl<'a> ConstRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> { |
30 | let ast_node = const_.source(ctx.db()).value; | 30 | let ast_node = const_.source(ctx.db())?.value; |
31 | ConstRender { ctx, const_, ast_node } | 31 | Some(ConstRender { ctx, const_, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 316e05b52..081be14f4 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>( | |||
14 | import_to_add: Option<ImportEdit>, | 14 | import_to_add: Option<ImportEdit>, |
15 | local_name: Option<String>, | 15 | local_name: Option<String>, |
16 | fn_: hir::Function, | 16 | fn_: hir::Function, |
17 | ) -> CompletionItem { | 17 | ) -> Option<CompletionItem> { |
18 | let _p = profile::span("render_fn"); | 18 | let _p = profile::span("render_fn"); |
19 | FunctionRender::new(ctx, local_name, fn_).render(import_to_add) | 19 | Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add)) |
20 | } | 20 | } |
21 | 21 | ||
22 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> { | |||
32 | ctx: RenderContext<'a>, | 32 | ctx: RenderContext<'a>, |
33 | local_name: Option<String>, | 33 | local_name: Option<String>, |
34 | fn_: hir::Function, | 34 | fn_: hir::Function, |
35 | ) -> FunctionRender<'a> { | 35 | ) -> Option<FunctionRender<'a>> { |
36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | 36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); |
37 | let ast_node = fn_.source(ctx.db()).value; | 37 | let ast_node = fn_.source(ctx.db())?.value; |
38 | 38 | ||
39 | FunctionRender { ctx, name, func: fn_, ast_node } | 39 | Some(FunctionRender { ctx, name, func: fn_, ast_node }) |
40 | } | 40 | } |
41 | 41 | ||
42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { | 42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index dac79592f..6f4f9945c 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> { | |||
39 | } | 39 | } |
40 | 40 | ||
41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { | 41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { |
42 | // FIXME: Currently proc-macro do not have ast-node, | ||
43 | // such that it does not have source | ||
44 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
45 | if self.macro_.is_proc_macro() { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | let mut builder = | 42 | let mut builder = |
50 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) | 43 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) |
51 | .kind(CompletionItemKind::Macro) | 44 | .kind(CompletionItemKind::Macro) |
52 | .set_documentation(self.docs.clone()) | 45 | .set_documentation(self.docs.clone()) |
53 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 46 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
54 | .add_import(import_to_add) | 47 | .add_import(import_to_add) |
55 | .detail(self.detail()); | 48 | .set_detail(self.detail()); |
56 | 49 | ||
57 | let needs_bang = self.needs_bang(); | 50 | let needs_bang = self.needs_bang(); |
58 | builder = match self.ctx.snippet_cap() { | 51 | builder = match self.ctx.snippet_cap() { |
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> { | |||
95 | format!("{}!", self.name) | 88 | format!("{}!", self.name) |
96 | } | 89 | } |
97 | 90 | ||
98 | fn detail(&self) -> String { | 91 | fn detail(&self) -> Option<String> { |
99 | let ast_node = self.macro_.source(self.ctx.db()).value; | 92 | let ast_node = self.macro_.source(self.ctx.db())?.value; |
100 | macro_label(&ast_node) | 93 | Some(macro_label(&ast_node)) |
101 | } | 94 | } |
102 | } | 95 | } |
103 | 96 | ||
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs index 9605c7fa9..69b445b9c 100644 --- a/crates/completion/src/render/type_alias.rs +++ b/crates/completion/src/render/type_alias.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | type_alias: hir::TypeAlias, | 16 | type_alias: hir::TypeAlias, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | TypeAliasRender::new(ctx, type_alias).render() | 18 | TypeAliasRender::new(ctx, type_alias)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> TypeAliasRender<'a> { | 28 | impl<'a> TypeAliasRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> { |
30 | let ast_node = type_alias.source(ctx.db()).value; | 30 | let ast_node = type_alias.source(ctx.db())?.value; |
31 | TypeAliasRender { ctx, type_alias, ast_node } | 31 | Some(TypeAliasRender { ctx, type_alias, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 6dc5ad63b..d4ea7327e 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -14,7 +14,7 @@ log = "0.4.8" | |||
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | either = "1.5.3" | 15 | either = "1.5.3" |
16 | arrayvec = "0.5.1" | 16 | arrayvec = "0.5.1" |
17 | itertools = "0.9.0" | 17 | itertools = "0.10.0" |
18 | 18 | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | 19 | stdx = { path = "../stdx", version = "0.0.0" } |
20 | syntax = { path = "../syntax", version = "0.0.0" } | 20 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index d32ce37ed..99fb65bac 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -3,15 +3,15 @@ use hir_def::{ | |||
3 | attr::{Attrs, Documentation}, | 3 | attr::{Attrs, Documentation}, |
4 | path::ModPath, | 4 | path::ModPath, |
5 | resolver::HasResolver, | 5 | resolver::HasResolver, |
6 | AttrDefId, ModuleDefId, | 6 | AttrDefId, GenericParamId, ModuleDefId, |
7 | }; | 7 | }; |
8 | use hir_expand::hygiene::Hygiene; | 8 | use hir_expand::hygiene::Hygiene; |
9 | use hir_ty::db::HirDatabase; | 9 | use hir_ty::db::HirDatabase; |
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Adt, Const, Enum, Field, Function, MacroDef, Module, ModuleDef, Static, Struct, Trait, | 13 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module, |
14 | TypeAlias, Union, Variant, | 14 | ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasAttrs { | 17 | pub trait HasAttrs { |
@@ -62,25 +62,27 @@ impl_has_attrs![ | |||
62 | (Function, FunctionId), | 62 | (Function, FunctionId), |
63 | (Adt, AdtId), | 63 | (Adt, AdtId), |
64 | (Module, ModuleId), | 64 | (Module, ModuleId), |
65 | (GenericParam, GenericParamId), | ||
65 | ]; | 66 | ]; |
66 | 67 | ||
67 | macro_rules! impl_has_attrs_adt { | 68 | macro_rules! impl_has_attrs_enum { |
68 | ($($adt:ident),*) => {$( | 69 | ($($variant:ident),* for $enum:ident) => {$( |
69 | impl HasAttrs for $adt { | 70 | impl HasAttrs for $variant { |
70 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { | 71 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { |
71 | Adt::$adt(self).attrs(db) | 72 | $enum::$variant(self).attrs(db) |
72 | } | 73 | } |
73 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { | 74 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { |
74 | Adt::$adt(self).docs(db) | 75 | $enum::$variant(self).docs(db) |
75 | } | 76 | } |
76 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { | 77 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { |
77 | Adt::$adt(self).resolve_doc_path(db, link, ns) | 78 | $enum::$variant(self).resolve_doc_path(db, link, ns) |
78 | } | 79 | } |
79 | } | 80 | } |
80 | )*}; | 81 | )*}; |
81 | } | 82 | } |
82 | 83 | ||
83 | impl_has_attrs_adt![Struct, Union, Enum]; | 84 | impl_has_attrs_enum![Struct, Union, Enum for Adt]; |
85 | impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; | ||
84 | 86 | ||
85 | fn resolve_doc_path( | 87 | fn resolve_doc_path( |
86 | db: &dyn HirDatabase, | 88 | db: &dyn HirDatabase, |
@@ -99,6 +101,12 @@ fn resolve_doc_path( | |||
99 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), | 101 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), |
100 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), | 102 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), |
101 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), | 103 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), |
104 | AttrDefId::GenericParamId(it) => match it { | ||
105 | GenericParamId::TypeParamId(it) => it.parent, | ||
106 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
107 | GenericParamId::ConstParamId(it) => it.parent, | ||
108 | } | ||
109 | .resolver(db.upcast()), | ||
102 | AttrDefId::MacroDefId(_) => return None, | 110 | AttrDefId::MacroDefId(_) => return None, |
103 | }; | 111 | }; |
104 | let path = ast::Path::parse(link).ok()?; | 112 | let path = ast::Path::parse(link).ok()?; |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 804cdb143..62eccf475 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -18,10 +18,10 @@ use hir_def::{ | |||
18 | resolver::{HasResolver, Resolver}, | 18 | resolver::{HasResolver, Resolver}, |
19 | src::HasSource as _, | 19 | src::HasSource as _, |
20 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
21 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId, | 21 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
22 | FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, | 22 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
23 | LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 23 | LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, |
24 | UnionId, | 24 | TypeAliasId, TypeParamId, UnionId, |
25 | }; | 25 | }; |
26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; | 26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; |
27 | use hir_expand::{ | 27 | use hir_expand::{ |
@@ -996,13 +996,7 @@ impl MacroDef { | |||
996 | 996 | ||
997 | /// XXX: this parses the file | 997 | /// XXX: this parses the file |
998 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 998 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
999 | // FIXME: Currently proc-macro do not have ast-node, | 999 | self.source(db)?.value.name().map(|it| it.as_name()) |
1000 | // such that it does not have source | ||
1001 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
1002 | if self.is_proc_macro() { | ||
1003 | return None; | ||
1004 | } | ||
1005 | self.source(db).value.name().map(|it| it.as_name()) | ||
1006 | } | 1000 | } |
1007 | 1001 | ||
1008 | /// Indicate it is a proc-macro | 1002 | /// Indicate it is a proc-macro |
@@ -1138,7 +1132,12 @@ impl GenericDef { | |||
1138 | id: LifetimeParamId { parent: self.into(), local_id }, | 1132 | id: LifetimeParamId { parent: self.into(), local_id }, |
1139 | }) | 1133 | }) |
1140 | .map(GenericParam::LifetimeParam); | 1134 | .map(GenericParam::LifetimeParam); |
1141 | ty_params.chain(lt_params).collect() | 1135 | let const_params = generics |
1136 | .consts | ||
1137 | .iter() | ||
1138 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1139 | .map(GenericParam::ConstParam); | ||
1140 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1142 | } | 1141 | } |
1143 | 1142 | ||
1144 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | 1143 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { |
@@ -1250,8 +1249,9 @@ impl Label { | |||
1250 | pub enum GenericParam { | 1249 | pub enum GenericParam { |
1251 | TypeParam(TypeParam), | 1250 | TypeParam(TypeParam), |
1252 | LifetimeParam(LifetimeParam), | 1251 | LifetimeParam(LifetimeParam), |
1252 | ConstParam(ConstParam), | ||
1253 | } | 1253 | } |
1254 | impl_from!(TypeParam, LifetimeParam for GenericParam); | 1254 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); |
1255 | 1255 | ||
1256 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1256 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1257 | pub struct TypeParam { | 1257 | pub struct TypeParam { |
@@ -1313,6 +1313,26 @@ impl LifetimeParam { | |||
1313 | } | 1313 | } |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1317 | pub struct ConstParam { | ||
1318 | pub(crate) id: ConstParamId, | ||
1319 | } | ||
1320 | |||
1321 | impl ConstParam { | ||
1322 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1323 | let params = db.generic_params(self.id.parent); | ||
1324 | params.consts[self.id.local_id].name.clone() | ||
1325 | } | ||
1326 | |||
1327 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1328 | self.id.parent.module(db.upcast()).into() | ||
1329 | } | ||
1330 | |||
1331 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1332 | self.id.parent.into() | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1316 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1336 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1317 | pub struct Impl { | 1337 | pub struct Impl { |
1318 | pub(crate) id: ImplId, | 1338 | pub(crate) id: ImplId, |
@@ -1365,7 +1385,7 @@ impl Impl { | |||
1365 | } | 1385 | } |
1366 | 1386 | ||
1367 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1387 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1368 | let src = self.source(db); | 1388 | let src = self.source(db)?; |
1369 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1389 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
1370 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | 1390 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); |
1371 | 1391 | ||
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index a0792b9a6..3e47a5e9d 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs | |||
@@ -6,13 +6,13 @@ | |||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | item_scope::ItemInNs, | 8 | item_scope::ItemInNs, |
9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId, | 9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, |
10 | VariantId, | 10 | ModuleDefId, VariantId, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, | 14 | code_model::GenericParam, Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, |
15 | VariantDef, | 15 | MacroDef, ModuleDef, Variant, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | macro_rules! from_id { | 18 | macro_rules! from_id { |
@@ -44,6 +44,7 @@ from_id![ | |||
44 | (hir_def::ImplId, crate::Impl), | 44 | (hir_def::ImplId, crate::Impl), |
45 | (hir_def::TypeParamId, crate::TypeParam), | 45 | (hir_def::TypeParamId, crate::TypeParam), |
46 | (hir_def::LifetimeParamId, crate::LifetimeParam), | 46 | (hir_def::LifetimeParamId, crate::LifetimeParam), |
47 | (hir_def::ConstParamId, crate::ConstParam), | ||
47 | (hir_expand::MacroDefId, crate::MacroDef) | 48 | (hir_expand::MacroDefId, crate::MacroDef) |
48 | ]; | 49 | ]; |
49 | 50 | ||
@@ -67,6 +68,26 @@ impl From<Adt> for AdtId { | |||
67 | } | 68 | } |
68 | } | 69 | } |
69 | 70 | ||
71 | impl From<GenericParamId> for GenericParam { | ||
72 | fn from(id: GenericParamId) -> Self { | ||
73 | match id { | ||
74 | GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), | ||
75 | GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), | ||
76 | GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl From<GenericParam> for GenericParamId { | ||
82 | fn from(id: GenericParam) -> Self { | ||
83 | match id { | ||
84 | GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), | ||
85 | GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), | ||
86 | GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
70 | impl From<EnumVariantId> for Variant { | 91 | impl From<EnumVariantId> for Variant { |
71 | fn from(id: EnumVariantId) -> Self { | 92 | fn from(id: EnumVariantId) -> Self { |
72 | Variant { parent: id.parent.into(), id: id.local_id } | 93 | Variant { parent: id.parent.into(), id: id.local_id } |
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 0dc07c33e..7c57d8378 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -10,13 +10,13 @@ use hir_expand::InFile; | |||
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | db::HirDatabase, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef, | 13 | db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam, |
14 | Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, | 14 | MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasSource { | 17 | pub trait HasSource { |
18 | type Ast; | 18 | type Ast; |
19 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>; | 19 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>; |
20 | } | 20 | } |
21 | 21 | ||
22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: | 22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: |
@@ -46,97 +46,104 @@ impl Module { | |||
46 | 46 | ||
47 | impl HasSource for Field { | 47 | impl HasSource for Field { |
48 | type Ast = FieldSource; | 48 | type Ast = FieldSource; |
49 | fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> { | 49 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
50 | let var = VariantId::from(self.parent); | 50 | let var = VariantId::from(self.parent); |
51 | let src = var.child_source(db.upcast()); | 51 | let src = var.child_source(db.upcast()); |
52 | src.map(|it| match it[self.id].clone() { | 52 | let field_source = src.map(|it| match it[self.id].clone() { |
53 | Either::Left(it) => FieldSource::Pos(it), | 53 | Either::Left(it) => FieldSource::Pos(it), |
54 | Either::Right(it) => FieldSource::Named(it), | 54 | Either::Right(it) => FieldSource::Named(it), |
55 | }) | 55 | }); |
56 | Some(field_source) | ||
56 | } | 57 | } |
57 | } | 58 | } |
58 | impl HasSource for Struct { | 59 | impl HasSource for Struct { |
59 | type Ast = ast::Struct; | 60 | type Ast = ast::Struct; |
60 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> { | 61 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
61 | self.id.lookup(db.upcast()).source(db.upcast()) | 62 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
62 | } | 63 | } |
63 | } | 64 | } |
64 | impl HasSource for Union { | 65 | impl HasSource for Union { |
65 | type Ast = ast::Union; | 66 | type Ast = ast::Union; |
66 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> { | 67 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
67 | self.id.lookup(db.upcast()).source(db.upcast()) | 68 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
68 | } | 69 | } |
69 | } | 70 | } |
70 | impl HasSource for Enum { | 71 | impl HasSource for Enum { |
71 | type Ast = ast::Enum; | 72 | type Ast = ast::Enum; |
72 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> { | 73 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
73 | self.id.lookup(db.upcast()).source(db.upcast()) | 74 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
74 | } | 75 | } |
75 | } | 76 | } |
76 | impl HasSource for Variant { | 77 | impl HasSource for Variant { |
77 | type Ast = ast::Variant; | 78 | type Ast = ast::Variant; |
78 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> { | 79 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> { |
79 | self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) | 80 | Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) |
80 | } | 81 | } |
81 | } | 82 | } |
82 | impl HasSource for Function { | 83 | impl HasSource for Function { |
83 | type Ast = ast::Fn; | 84 | type Ast = ast::Fn; |
84 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> { | 85 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
85 | self.id.lookup(db.upcast()).source(db.upcast()) | 86 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
86 | } | 87 | } |
87 | } | 88 | } |
88 | impl HasSource for Const { | 89 | impl HasSource for Const { |
89 | type Ast = ast::Const; | 90 | type Ast = ast::Const; |
90 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> { | 91 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
91 | self.id.lookup(db.upcast()).source(db.upcast()) | 92 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
92 | } | 93 | } |
93 | } | 94 | } |
94 | impl HasSource for Static { | 95 | impl HasSource for Static { |
95 | type Ast = ast::Static; | 96 | type Ast = ast::Static; |
96 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> { | 97 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
97 | self.id.lookup(db.upcast()).source(db.upcast()) | 98 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
98 | } | 99 | } |
99 | } | 100 | } |
100 | impl HasSource for Trait { | 101 | impl HasSource for Trait { |
101 | type Ast = ast::Trait; | 102 | type Ast = ast::Trait; |
102 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> { | 103 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
103 | self.id.lookup(db.upcast()).source(db.upcast()) | 104 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
104 | } | 105 | } |
105 | } | 106 | } |
106 | impl HasSource for TypeAlias { | 107 | impl HasSource for TypeAlias { |
107 | type Ast = ast::TypeAlias; | 108 | type Ast = ast::TypeAlias; |
108 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> { | 109 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
109 | self.id.lookup(db.upcast()).source(db.upcast()) | 110 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
110 | } | 111 | } |
111 | } | 112 | } |
112 | impl HasSource for MacroDef { | 113 | impl HasSource for MacroDef { |
113 | type Ast = ast::Macro; | 114 | type Ast = ast::Macro; |
114 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> { | 115 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
115 | InFile { | 116 | let ast_id = self.id.ast_id?; |
116 | file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, | 117 | Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) }) |
117 | value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()), | ||
118 | } | ||
119 | } | 118 | } |
120 | } | 119 | } |
121 | impl HasSource for Impl { | 120 | impl HasSource for Impl { |
122 | type Ast = ast::Impl; | 121 | type Ast = ast::Impl; |
123 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { | 122 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
124 | self.id.lookup(db.upcast()).source(db.upcast()) | 123 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
125 | } | 124 | } |
126 | } | 125 | } |
127 | 126 | ||
128 | impl HasSource for TypeParam { | 127 | impl HasSource for TypeParam { |
129 | type Ast = Either<ast::Trait, ast::TypeParam>; | 128 | type Ast = Either<ast::Trait, ast::TypeParam>; |
130 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 129 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
131 | let child_source = self.id.parent.child_source(db.upcast()); | 130 | let child_source = self.id.parent.child_source(db.upcast()); |
132 | child_source.map(|it| it[self.id.local_id].clone()) | 131 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
133 | } | 132 | } |
134 | } | 133 | } |
135 | 134 | ||
136 | impl HasSource for LifetimeParam { | 135 | impl HasSource for LifetimeParam { |
137 | type Ast = ast::LifetimeParam; | 136 | type Ast = ast::LifetimeParam; |
138 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 137 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
138 | let child_source = self.id.parent.child_source(db.upcast()); | ||
139 | Some(child_source.map(|it| it[self.id.local_id].clone())) | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl HasSource for ConstParam { | ||
144 | type Ast = ast::ConstParam; | ||
145 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | ||
139 | let child_source = self.id.parent.child_source(db.upcast()); | 146 | let child_source = self.id.parent.child_source(db.upcast()); |
140 | child_source.map(|it| it[self.id.local_id].clone()) | 147 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
141 | } | 148 | } |
142 | } | 149 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7ac9fd507..769945c47 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -34,9 +34,10 @@ pub use crate::{ | |||
34 | attrs::{HasAttrs, Namespace}, | 34 | attrs::{HasAttrs, Namespace}, |
35 | code_model::{ | 35 | code_model::{ |
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, | 36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, |
37 | Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef, | 37 | ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, |
38 | HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, | 38 | GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, |
39 | Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, | 39 | Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, |
40 | Variant, VariantDef, | ||
40 | }, | 41 | }, |
41 | has_source::HasSource, | 42 | has_source::HasSource, |
42 | semantics::{PathResolution, Semantics, SemanticsScope}, | 43 | semantics::{PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 67cd16e31..cd689c869 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -25,9 +25,9 @@ use crate::{ | |||
25 | diagnostics::Diagnostic, | 25 | diagnostics::Diagnostic, |
26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
28 | AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam, | 28 | AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label, |
29 | Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 29 | LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, |
30 | VariantDef, | 30 | TypeAlias, TypeParam, VariantDef, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | 33 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -38,6 +38,7 @@ pub enum PathResolution { | |||
38 | Local(Local), | 38 | Local(Local), |
39 | /// A generic parameter | 39 | /// A generic parameter |
40 | TypeParam(TypeParam), | 40 | TypeParam(TypeParam), |
41 | ConstParam(ConstParam), | ||
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
43 | AssocItem(AssocItem), | 44 | AssocItem(AssocItem), |
@@ -59,7 +60,9 @@ impl PathResolution { | |||
59 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | 60 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { |
60 | Some(TypeNs::TypeAliasId((*alias).into())) | 61 | Some(TypeNs::TypeAliasId((*alias).into())) |
61 | } | 62 | } |
62 | PathResolution::Local(_) | PathResolution::Macro(_) => None, | 63 | PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => { |
64 | None | ||
65 | } | ||
63 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | 66 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), |
64 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | 67 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), |
65 | PathResolution::AssocItem(AssocItem::Const(_)) | 68 | PathResolution::AssocItem(AssocItem::Const(_)) |
@@ -744,6 +747,7 @@ to_def_impls![ | |||
744 | (crate::Variant, ast::Variant, enum_variant_to_def), | 747 | (crate::Variant, ast::Variant, enum_variant_to_def), |
745 | (crate::TypeParam, ast::TypeParam, type_param_to_def), | 748 | (crate::TypeParam, ast::TypeParam, type_param_to_def), |
746 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 749 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), |
750 | (crate::ConstParam, ast::ConstParam, const_param_to_def), | ||
747 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), | 751 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), |
748 | (crate::Local, ast::IdentPat, bind_pat_to_def), | 752 | (crate::Local, ast::IdentPat, bind_pat_to_def), |
749 | (crate::Label, ast::Label, label_to_def), | 753 | (crate::Label, ast::Label, label_to_def), |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 424e6e8a9..4b9ebff72 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -6,9 +6,9 @@ use hir_def::{ | |||
6 | dyn_map::DynMap, | 6 | dyn_map::DynMap, |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | keys::{self, Key}, | 8 | keys::{self, Key}, |
9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, | 9 | ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, |
10 | LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
11 | VariantId, | 11 | UnionId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -157,6 +157,18 @@ impl SourceToDefCtx<'_, '_> { | |||
157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() | 157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() |
158 | } | 158 | } |
159 | 159 | ||
160 | pub(super) fn const_param_to_def( | ||
161 | &mut self, | ||
162 | src: InFile<ast::ConstParam>, | ||
163 | ) -> Option<ConstParamId> { | ||
164 | let container: ChildContainer = | ||
165 | self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into(); | ||
166 | let db = self.db; | ||
167 | let dyn_map = | ||
168 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); | ||
169 | dyn_map[keys::CONST_PARAM].get(&src).copied() | ||
170 | } | ||
171 | |||
160 | // FIXME: use DynMap as well? | 172 | // FIXME: use DynMap as well? |
161 | pub(super) fn macro_rules_to_def( | 173 | pub(super) fn macro_rules_to_def( |
162 | &mut self, | 174 | &mut self, |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index bddc49c05..30a8e513d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -479,6 +479,7 @@ pub(crate) fn resolve_hir_path( | |||
479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | 479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), |
480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | 480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), |
481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), | 481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), |
482 | ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()), | ||
482 | }; | 483 | }; |
483 | Some(res) | 484 | Some(res) |
484 | }); | 485 | }); |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index a88b5f57e..e8b581e2f 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -17,7 +17,7 @@ either = "1.5.3" | |||
17 | anymap = "0.12.1" | 17 | anymap = "0.12.1" |
18 | drop_bomb = "0.1.4" | 18 | drop_bomb = "0.1.4" |
19 | fst = { version = "0.4", default-features = false } | 19 | fst = { version = "0.4", default-features = false } |
20 | itertools = "0.9.0" | 20 | itertools = "0.10.0" |
21 | indexmap = "1.4.0" | 21 | indexmap = "1.4.0" |
22 | smallvec = "1.4.0" | 22 | smallvec = "1.4.0" |
23 | 23 | ||
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 042e119b1..6b79e7bad 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -21,7 +21,7 @@ use crate::{ | |||
21 | nameres::ModuleSource, | 21 | nameres::ModuleSource, |
22 | path::{ModPath, PathKind}, | 22 | path::{ModPath, PathKind}, |
23 | src::HasChildSource, | 23 | src::HasChildSource, |
24 | AdtId, AttrDefId, Lookup, | 24 | AdtId, AttrDefId, GenericParamId, Lookup, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | /// Holds documentation | 27 | /// Holds documentation |
@@ -235,6 +235,25 @@ impl Attrs { | |||
235 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 235 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
236 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 236 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
238 | AttrDefId::GenericParamId(it) => match it { | ||
239 | GenericParamId::TypeParamId(it) => { | ||
240 | let src = it.parent.child_source(db); | ||
241 | RawAttrs::from_attrs_owner( | ||
242 | db, | ||
243 | src.with_value( | ||
244 | src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _), | ||
245 | ), | ||
246 | ) | ||
247 | } | ||
248 | GenericParamId::LifetimeParamId(it) => { | ||
249 | let src = it.parent.child_source(db); | ||
250 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
251 | } | ||
252 | GenericParamId::ConstParamId(it) => { | ||
253 | let src = it.parent.child_source(db); | ||
254 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
255 | } | ||
256 | }, | ||
238 | }; | 257 | }; |
239 | 258 | ||
240 | raw_attrs.filter(db, def.krate(db)) | 259 | raw_attrs.filter(db, def.krate(db)) |
@@ -260,14 +279,13 @@ impl Attrs { | |||
260 | } | 279 | } |
261 | 280 | ||
262 | pub fn docs(&self) -> Option<Documentation> { | 281 | pub fn docs(&self) -> Option<Documentation> { |
263 | let docs = self | 282 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { |
264 | .by_key("doc") | 283 | AttrInput::Literal(s) => Some(s), |
265 | .attrs() | 284 | AttrInput::TokenTree(_) => None, |
266 | .flat_map(|attr| match attr.input.as_ref()? { | 285 | }); |
267 | AttrInput::Literal(s) => Some(s), | 286 | // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the |
268 | AttrInput::TokenTree(_) => None, | 287 | // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524). |
269 | }) | 288 | let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n")) |
270 | .intersperse(&SmolStr::new_inline("\n")) | ||
271 | .map(|it| it.as_str()) | 289 | .map(|it| it.as_str()) |
272 | .collect::<String>(); | 290 | .collect::<String>(); |
273 | if docs.is_empty() { | 291 | if docs.is_empty() { |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index bb8fca009..9b5b886c2 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -21,11 +21,11 @@ use crate::{ | |||
21 | keys, | 21 | keys, |
22 | src::{HasChildSource, HasSource}, | 22 | src::{HasChildSource, HasSource}, |
23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
24 | AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup, | 24 | AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId, |
25 | TypeParamId, | 25 | LocalTypeParamId, Lookup, TypeParamId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// Data about a generic parameter (to a function, struct, impl, ...). | 28 | /// Data about a generic type parameter (to a function, struct, impl, ...). |
29 | #[derive(Clone, PartialEq, Eq, Debug)] | 29 | #[derive(Clone, PartialEq, Eq, Debug)] |
30 | pub struct TypeParamData { | 30 | pub struct TypeParamData { |
31 | pub name: Option<Name>, | 31 | pub name: Option<Name>, |
@@ -33,12 +33,19 @@ pub struct TypeParamData { | |||
33 | pub provenance: TypeParamProvenance, | 33 | pub provenance: TypeParamProvenance, |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Data about a generic parameter (to a function, struct, impl, ...). | 36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). |
37 | #[derive(Clone, PartialEq, Eq, Debug)] | 37 | #[derive(Clone, PartialEq, Eq, Debug)] |
38 | pub struct LifetimeParamData { | 38 | pub struct LifetimeParamData { |
39 | pub name: Name, | 39 | pub name: Name, |
40 | } | 40 | } |
41 | 41 | ||
42 | /// Data about a generic const parameter (to a function, struct, impl, ...). | ||
43 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
44 | pub struct ConstParamData { | ||
45 | pub name: Name, | ||
46 | pub ty: TypeRef, | ||
47 | } | ||
48 | |||
42 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
43 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
44 | TypeParamList, | 51 | TypeParamList, |
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance { | |||
51 | pub struct GenericParams { | 58 | pub struct GenericParams { |
52 | pub types: Arena<TypeParamData>, | 59 | pub types: Arena<TypeParamData>, |
53 | pub lifetimes: Arena<LifetimeParamData>, | 60 | pub lifetimes: Arena<LifetimeParamData>, |
61 | pub consts: Arena<ConstParamData>, | ||
54 | pub where_predicates: Vec<WherePredicate>, | 62 | pub where_predicates: Vec<WherePredicate>, |
55 | } | 63 | } |
56 | 64 | ||
@@ -76,6 +84,7 @@ pub enum WherePredicateTypeTarget { | |||
76 | pub(crate) struct SourceMap { | 84 | pub(crate) struct SourceMap { |
77 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, | 85 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, |
78 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, | 86 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, |
87 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, | ||
79 | } | 88 | } |
80 | 89 | ||
81 | impl GenericParams { | 90 | impl GenericParams { |
@@ -268,6 +277,13 @@ impl GenericParams { | |||
268 | let lifetime_ref = LifetimeRef::new_name(name); | 277 | let lifetime_ref = LifetimeRef::new_name(name); |
269 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); | 278 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); |
270 | } | 279 | } |
280 | for const_param in params.const_params() { | ||
281 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
282 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); | ||
283 | let param = ConstParamData { name, ty }; | ||
284 | let param_id = self.consts.alloc(param); | ||
285 | sm.const_params.insert(param_id, const_param.clone()); | ||
286 | } | ||
271 | } | 287 | } |
272 | 288 | ||
273 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { | 289 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { |
@@ -353,12 +369,16 @@ impl GenericParams { | |||
353 | }); | 369 | }); |
354 | } | 370 | } |
355 | 371 | ||
356 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | 372 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
357 | self.types | 373 | self.types |
358 | .iter() | 374 | .iter() |
359 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) | 375 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) |
360 | } | 376 | } |
361 | 377 | ||
378 | pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> { | ||
379 | self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None }) | ||
380 | } | ||
381 | |||
362 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { | 382 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { |
363 | self.types.iter().find_map(|(id, p)| { | 383 | self.types.iter().find_map(|(id, p)| { |
364 | if p.provenance == TypeParamProvenance::TraitSelf { | 384 | if p.provenance == TypeParamProvenance::TraitSelf { |
@@ -390,6 +410,16 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId { | |||
390 | } | 410 | } |
391 | } | 411 | } |
392 | 412 | ||
413 | impl HasChildSource<LocalConstParamId> for GenericDefId { | ||
414 | type Value = ast::ConstParam; | ||
415 | fn child_source( | ||
416 | &self, | ||
417 | db: &dyn DefDatabase, | ||
418 | ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> { | ||
419 | GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params) | ||
420 | } | ||
421 | } | ||
422 | |||
393 | impl ChildBySource for GenericDefId { | 423 | impl ChildBySource for GenericDefId { |
394 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | 424 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { |
395 | let mut res = DynMap::default(); | 425 | let mut res = DynMap::default(); |
@@ -406,6 +436,10 @@ impl ChildBySource for GenericDefId { | |||
406 | let id = LifetimeParamId { parent: *self, local_id }; | 436 | let id = LifetimeParamId { parent: *self, local_id }; |
407 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); | 437 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); |
408 | } | 438 | } |
439 | for (local_id, src) in sm.value.const_params.iter() { | ||
440 | let id = ConstParamId { parent: *self, local_id }; | ||
441 | res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id); | ||
442 | } | ||
409 | res | 443 | res |
410 | } | 444 | } |
411 | } | 445 | } |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index c0f108848..30b22f51d 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -238,32 +238,53 @@ pub enum ImportKind { | |||
238 | BuiltinType, | 238 | BuiltinType, |
239 | } | 239 | } |
240 | 240 | ||
241 | /// A way to match import map contents against the search query. | ||
242 | #[derive(Debug)] | ||
243 | pub enum SearchMode { | ||
244 | /// Import map entry should strictly match the query string. | ||
245 | Equals, | ||
246 | /// Import map entry should contain the query string. | ||
247 | Contains, | ||
248 | /// Import map entry should contain all letters from the query string, | ||
249 | /// in the same order, but not necessary adjacent. | ||
250 | Fuzzy, | ||
251 | } | ||
252 | |||
241 | #[derive(Debug)] | 253 | #[derive(Debug)] |
242 | pub struct Query { | 254 | pub struct Query { |
243 | query: String, | 255 | query: String, |
244 | lowercased: String, | 256 | lowercased: String, |
245 | anchor_end: bool, | 257 | name_only: bool, |
258 | search_mode: SearchMode, | ||
246 | case_sensitive: bool, | 259 | case_sensitive: bool, |
247 | limit: usize, | 260 | limit: usize, |
248 | exclude_import_kinds: FxHashSet<ImportKind>, | 261 | exclude_import_kinds: FxHashSet<ImportKind>, |
249 | } | 262 | } |
250 | 263 | ||
251 | impl Query { | 264 | impl Query { |
252 | pub fn new(query: &str) -> Self { | 265 | pub fn new(query: String) -> Self { |
266 | let lowercased = query.to_lowercase(); | ||
253 | Self { | 267 | Self { |
254 | lowercased: query.to_lowercase(), | 268 | query, |
255 | query: query.to_string(), | 269 | lowercased, |
256 | anchor_end: false, | 270 | name_only: false, |
271 | search_mode: SearchMode::Contains, | ||
257 | case_sensitive: false, | 272 | case_sensitive: false, |
258 | limit: usize::max_value(), | 273 | limit: usize::max_value(), |
259 | exclude_import_kinds: FxHashSet::default(), | 274 | exclude_import_kinds: FxHashSet::default(), |
260 | } | 275 | } |
261 | } | 276 | } |
262 | 277 | ||
263 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | 278 | /// Matches entries' names only, ignoring the rest of |
264 | /// segment. | 279 | /// the qualifier. |
265 | pub fn anchor_end(self) -> Self { | 280 | /// Example: for `std::marker::PhantomData`, the name is `PhantomData`. |
266 | Self { anchor_end: true, ..self } | 281 | pub fn name_only(self) -> Self { |
282 | Self { name_only: true, ..self } | ||
283 | } | ||
284 | |||
285 | /// Specifies the way to search for the entries using the query. | ||
286 | pub fn search_mode(self, search_mode: SearchMode) -> Self { | ||
287 | Self { search_mode, ..self } | ||
267 | } | 288 | } |
268 | 289 | ||
269 | /// Limits the returned number of items to `limit`. | 290 | /// Limits the returned number of items to `limit`. |
@@ -283,6 +304,40 @@ impl Query { | |||
283 | } | 304 | } |
284 | } | 305 | } |
285 | 306 | ||
307 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | ||
308 | let mut input = if query.name_only { | ||
309 | input_path.segments.last().unwrap().to_string() | ||
310 | } else { | ||
311 | input_path.to_string() | ||
312 | }; | ||
313 | if enforce_lowercase || !query.case_sensitive { | ||
314 | input.make_ascii_lowercase(); | ||
315 | } | ||
316 | |||
317 | let query_string = | ||
318 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | ||
319 | |||
320 | match query.search_mode { | ||
321 | SearchMode::Equals => &input == query_string, | ||
322 | SearchMode::Contains => input.contains(query_string), | ||
323 | SearchMode::Fuzzy => { | ||
324 | let mut unchecked_query_chars = query_string.chars(); | ||
325 | let mut mismatching_query_char = unchecked_query_chars.next(); | ||
326 | |||
327 | for input_char in input.chars() { | ||
328 | match mismatching_query_char { | ||
329 | None => return true, | ||
330 | Some(matching_query_char) if matching_query_char == input_char => { | ||
331 | mismatching_query_char = unchecked_query_chars.next(); | ||
332 | } | ||
333 | _ => (), | ||
334 | } | ||
335 | } | ||
336 | mismatching_query_char.is_none() | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
286 | /// Searches dependencies of `krate` for an importable path matching `query`. | 341 | /// Searches dependencies of `krate` for an importable path matching `query`. |
287 | /// | 342 | /// |
288 | /// This returns a list of items that could be imported from dependencies of `krate`. | 343 | /// This returns a list of items that could be imported from dependencies of `krate`. |
@@ -312,39 +367,29 @@ pub fn search_dependencies<'a>( | |||
312 | let importables = &import_map.importables[indexed_value.value as usize..]; | 367 | let importables = &import_map.importables[indexed_value.value as usize..]; |
313 | 368 | ||
314 | // Path shared by the importable items in this group. | 369 | // Path shared by the importable items in this group. |
315 | let path = &import_map.map[&importables[0]].path; | 370 | let common_importables_path = &import_map.map[&importables[0]].path; |
316 | 371 | if !contains_query(&query, common_importables_path, true) { | |
317 | if query.anchor_end { | 372 | continue; |
318 | // Last segment must match query. | ||
319 | let last = path.segments.last().unwrap().to_string(); | ||
320 | if last.to_lowercase() != query.lowercased { | ||
321 | continue; | ||
322 | } | ||
323 | } | 373 | } |
324 | 374 | ||
375 | let common_importables_path_fst = fst_path(common_importables_path); | ||
325 | // Add the items from this `ModPath` group. Those are all subsequent items in | 376 | // Add the items from this `ModPath` group. Those are all subsequent items in |
326 | // `importables` whose paths match `path`. | 377 | // `importables` whose paths match `path`. |
327 | let iter = importables | 378 | let iter = importables |
328 | .iter() | 379 | .iter() |
329 | .copied() | 380 | .copied() |
330 | .take_while(|item| { | 381 | .take_while(|item| { |
331 | let item_path = &import_map.map[item].path; | 382 | common_importables_path_fst == fst_path(&import_map.map[item].path) |
332 | fst_path(item_path) == fst_path(path) | ||
333 | }) | 383 | }) |
334 | .filter(|&item| match item_import_kind(item) { | 384 | .filter(|&item| match item_import_kind(item) { |
335 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | 385 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), |
336 | None => true, | 386 | None => true, |
387 | }) | ||
388 | .filter(|item| { | ||
389 | !query.case_sensitive // we've already checked the common importables path case-insensitively | ||
390 | || contains_query(&query, &import_map.map[item].path, false) | ||
337 | }); | 391 | }); |
338 | 392 | res.extend(iter); | |
339 | if query.case_sensitive { | ||
340 | // FIXME: This does not do a subsequence match. | ||
341 | res.extend(iter.filter(|item| { | ||
342 | let item_path = &import_map.map[item].path; | ||
343 | item_path.to_string().contains(&query.query) | ||
344 | })); | ||
345 | } else { | ||
346 | res.extend(iter); | ||
347 | } | ||
348 | 393 | ||
349 | if res.len() >= query.limit { | 394 | if res.len() >= query.limit { |
350 | res.truncate(query.limit); | 395 | res.truncate(query.limit); |
@@ -387,8 +432,9 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { | |||
387 | mod tests { | 432 | mod tests { |
388 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 433 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
389 | use expect_test::{expect, Expect}; | 434 | use expect_test::{expect, Expect}; |
435 | use stdx::format_to; | ||
390 | 436 | ||
391 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; | 437 | use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup}; |
392 | 438 | ||
393 | use super::*; | 439 | use super::*; |
394 | 440 | ||
@@ -407,14 +453,32 @@ mod tests { | |||
407 | .into_iter() | 453 | .into_iter() |
408 | .filter_map(|item| { | 454 | .filter_map(|item| { |
409 | let mark = match item { | 455 | let mark = match item { |
456 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | ||
457 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | ||
410 | ItemInNs::Types(_) => "t", | 458 | ItemInNs::Types(_) => "t", |
411 | ItemInNs::Values(_) => "v", | 459 | ItemInNs::Values(_) => "v", |
412 | ItemInNs::Macros(_) => "m", | 460 | ItemInNs::Macros(_) => "m", |
413 | }; | 461 | }; |
414 | let item = assoc_to_trait(&db, item); | ||
415 | item.krate(db.upcast()).map(|krate| { | 462 | item.krate(db.upcast()).map(|krate| { |
416 | let map = db.import_map(krate); | 463 | let map = db.import_map(krate); |
417 | let path = map.path_of(item).unwrap(); | 464 | |
465 | let path = match assoc_to_trait(&db, item) { | ||
466 | Some(trait_) => { | ||
467 | let mut full_path = map.path_of(trait_).unwrap().to_string(); | ||
468 | if let ItemInNs::Types(ModuleDefId::FunctionId(function_id)) | ||
469 | | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item | ||
470 | { | ||
471 | format_to!( | ||
472 | full_path, | ||
473 | "::{}", | ||
474 | FunctionData::fn_data_query(&db, function_id).name, | ||
475 | ); | ||
476 | } | ||
477 | full_path | ||
478 | } | ||
479 | None => map.path_of(item).unwrap().to_string(), | ||
480 | }; | ||
481 | |||
418 | format!( | 482 | format!( |
419 | "{}::{} ({})\n", | 483 | "{}::{} ({})\n", |
420 | crate_graph[krate].display_name.as_ref().unwrap(), | 484 | crate_graph[krate].display_name.as_ref().unwrap(), |
@@ -427,15 +491,15 @@ mod tests { | |||
427 | expect.assert_eq(&actual) | 491 | expect.assert_eq(&actual) |
428 | } | 492 | } |
429 | 493 | ||
430 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs { | 494 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { |
431 | let assoc: AssocItemId = match item { | 495 | let assoc: AssocItemId = match item { |
432 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { | 496 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { |
433 | ModuleDefId::TypeAliasId(it) => it.into(), | 497 | ModuleDefId::TypeAliasId(it) => it.into(), |
434 | ModuleDefId::FunctionId(it) => it.into(), | 498 | ModuleDefId::FunctionId(it) => it.into(), |
435 | ModuleDefId::ConstId(it) => it.into(), | 499 | ModuleDefId::ConstId(it) => it.into(), |
436 | _ => return item, | 500 | _ => return None, |
437 | }, | 501 | }, |
438 | _ => return item, | 502 | _ => return None, |
439 | }; | 503 | }; |
440 | 504 | ||
441 | let container = match assoc { | 505 | let container = match assoc { |
@@ -445,8 +509,8 @@ mod tests { | |||
445 | }; | 509 | }; |
446 | 510 | ||
447 | match container { | 511 | match container { |
448 | AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()), | 512 | AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())), |
449 | _ => item, | 513 | _ => None, |
450 | } | 514 | } |
451 | } | 515 | } |
452 | 516 | ||
@@ -685,7 +749,7 @@ mod tests { | |||
685 | } | 749 | } |
686 | 750 | ||
687 | #[test] | 751 | #[test] |
688 | fn search() { | 752 | fn search_mode() { |
689 | let ra_fixture = r#" | 753 | let ra_fixture = r#" |
690 | //- /main.rs crate:main deps:dep | 754 | //- /main.rs crate:main deps:dep |
691 | //- /dep.rs crate:dep deps:tdep | 755 | //- /dep.rs crate:dep deps:tdep |
@@ -713,28 +777,96 @@ mod tests { | |||
713 | check_search( | 777 | check_search( |
714 | ra_fixture, | 778 | ra_fixture, |
715 | "main", | 779 | "main", |
716 | Query::new("fmt"), | 780 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), |
717 | expect![[r#" | 781 | expect![[r#" |
718 | dep::fmt (t) | 782 | dep::fmt (t) |
719 | dep::Fmt (t) | 783 | dep::Fmt (t) |
720 | dep::Fmt (v) | 784 | dep::Fmt (v) |
721 | dep::Fmt (m) | 785 | dep::Fmt (m) |
722 | dep::fmt::Display (t) | 786 | dep::fmt::Display (t) |
723 | dep::format (v) | 787 | dep::format (f) |
788 | dep::fmt::Display::fmt (f) | ||
789 | "#]], | ||
790 | ); | ||
791 | |||
792 | check_search( | ||
793 | ra_fixture, | ||
794 | "main", | ||
795 | Query::new("fmt".to_string()).search_mode(SearchMode::Equals), | ||
796 | expect![[r#" | ||
797 | dep::fmt (t) | ||
798 | dep::Fmt (t) | ||
799 | dep::Fmt (v) | ||
800 | dep::Fmt (m) | ||
801 | dep::fmt::Display::fmt (f) | ||
802 | "#]], | ||
803 | ); | ||
804 | |||
805 | check_search( | ||
806 | ra_fixture, | ||
807 | "main", | ||
808 | Query::new("fmt".to_string()).search_mode(SearchMode::Contains), | ||
809 | expect![[r#" | ||
810 | dep::fmt (t) | ||
811 | dep::Fmt (t) | ||
812 | dep::Fmt (v) | ||
813 | dep::Fmt (m) | ||
724 | dep::fmt::Display (t) | 814 | dep::fmt::Display (t) |
815 | dep::fmt::Display::fmt (f) | ||
725 | "#]], | 816 | "#]], |
726 | ); | 817 | ); |
818 | } | ||
819 | |||
820 | #[test] | ||
821 | fn name_only() { | ||
822 | let ra_fixture = r#" | ||
823 | //- /main.rs crate:main deps:dep | ||
824 | //- /dep.rs crate:dep deps:tdep | ||
825 | use tdep::fmt as fmt_dep; | ||
826 | pub mod fmt { | ||
827 | pub trait Display { | ||
828 | fn fmt(); | ||
829 | } | ||
830 | } | ||
831 | #[macro_export] | ||
832 | macro_rules! Fmt { | ||
833 | () => {}; | ||
834 | } | ||
835 | pub struct Fmt; | ||
836 | |||
837 | pub fn format() {} | ||
838 | pub fn no() {} | ||
839 | |||
840 | //- /tdep.rs crate:tdep | ||
841 | pub mod fmt { | ||
842 | pub struct NotImportableFromMain; | ||
843 | } | ||
844 | "#; | ||
727 | 845 | ||
728 | check_search( | 846 | check_search( |
729 | ra_fixture, | 847 | ra_fixture, |
730 | "main", | 848 | "main", |
731 | Query::new("fmt").anchor_end(), | 849 | Query::new("fmt".to_string()), |
732 | expect![[r#" | 850 | expect![[r#" |
733 | dep::fmt (t) | 851 | dep::fmt (t) |
734 | dep::Fmt (t) | 852 | dep::Fmt (t) |
735 | dep::Fmt (v) | 853 | dep::Fmt (v) |
736 | dep::Fmt (m) | 854 | dep::Fmt (m) |
737 | dep::fmt::Display (t) | 855 | dep::fmt::Display (t) |
856 | dep::fmt::Display::fmt (f) | ||
857 | "#]], | ||
858 | ); | ||
859 | |||
860 | check_search( | ||
861 | ra_fixture, | ||
862 | "main", | ||
863 | Query::new("fmt".to_string()).name_only(), | ||
864 | expect![[r#" | ||
865 | dep::fmt (t) | ||
866 | dep::Fmt (t) | ||
867 | dep::Fmt (v) | ||
868 | dep::Fmt (m) | ||
869 | dep::fmt::Display::fmt (f) | ||
738 | "#]], | 870 | "#]], |
739 | ); | 871 | ); |
740 | } | 872 | } |
@@ -752,7 +884,7 @@ mod tests { | |||
752 | check_search( | 884 | check_search( |
753 | ra_fixture, | 885 | ra_fixture, |
754 | "main", | 886 | "main", |
755 | Query::new("FMT"), | 887 | Query::new("FMT".to_string()), |
756 | expect![[r#" | 888 | expect![[r#" |
757 | dep::fmt (t) | 889 | dep::fmt (t) |
758 | dep::fmt (v) | 890 | dep::fmt (v) |
@@ -764,7 +896,7 @@ mod tests { | |||
764 | check_search( | 896 | check_search( |
765 | ra_fixture, | 897 | ra_fixture, |
766 | "main", | 898 | "main", |
767 | Query::new("FMT").case_sensitive(), | 899 | Query::new("FMT".to_string()).case_sensitive(), |
768 | expect![[r#" | 900 | expect![[r#" |
769 | dep::FMT (t) | 901 | dep::FMT (t) |
770 | dep::FMT (v) | 902 | dep::FMT (v) |
@@ -793,7 +925,7 @@ mod tests { | |||
793 | pub fn no() {} | 925 | pub fn no() {} |
794 | "#, | 926 | "#, |
795 | "main", | 927 | "main", |
796 | Query::new("").limit(2), | 928 | Query::new("".to_string()).limit(2), |
797 | expect![[r#" | 929 | expect![[r#" |
798 | dep::fmt (t) | 930 | dep::fmt (t) |
799 | dep::Fmt (t) | 931 | dep::Fmt (t) |
@@ -814,7 +946,7 @@ mod tests { | |||
814 | check_search( | 946 | check_search( |
815 | ra_fixture, | 947 | ra_fixture, |
816 | "main", | 948 | "main", |
817 | Query::new("FMT"), | 949 | Query::new("FMT".to_string()), |
818 | expect![[r#" | 950 | expect![[r#" |
819 | dep::fmt (t) | 951 | dep::fmt (t) |
820 | dep::fmt (v) | 952 | dep::fmt (v) |
@@ -826,7 +958,7 @@ mod tests { | |||
826 | check_search( | 958 | check_search( |
827 | ra_fixture, | 959 | ra_fixture, |
828 | "main", | 960 | "main", |
829 | Query::new("FMT").exclude_import_kind(ImportKind::Adt), | 961 | Query::new("FMT".to_string()).exclude_import_kind(ImportKind::Adt), |
830 | expect![[r#""#]], | 962 | expect![[r#""#]], |
831 | ); | 963 | ); |
832 | } | 964 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 100dbf5d6..b6f510731 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -260,6 +260,7 @@ impl GenericParamsStorage { | |||
260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | 260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { |
261 | if params.types.is_empty() | 261 | if params.types.is_empty() |
262 | && params.lifetimes.is_empty() | 262 | && params.lifetimes.is_empty() |
263 | && params.consts.is_empty() | ||
263 | && params.where_predicates.is_empty() | 264 | && params.where_predicates.is_empty() |
264 | { | 265 | { |
265 | return GenericParamsId::EMPTY; | 266 | return GenericParamsId::EMPTY; |
@@ -269,8 +270,12 @@ impl GenericParamsStorage { | |||
269 | } | 270 | } |
270 | } | 271 | } |
271 | 272 | ||
272 | static EMPTY_GENERICS: GenericParams = | 273 | static EMPTY_GENERICS: GenericParams = GenericParams { |
273 | GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() }; | 274 | types: Arena::new(), |
275 | lifetimes: Arena::new(), | ||
276 | consts: Arena::new(), | ||
277 | where_predicates: Vec::new(), | ||
278 | }; | ||
274 | 279 | ||
275 | #[derive(Default, Debug, Eq, PartialEq)] | 280 | #[derive(Default, Debug, Eq, PartialEq)] |
276 | struct ItemTreeData { | 281 | struct ItemTreeData { |
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index 9c585de2c..89b3ed868 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs | |||
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr}; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | dyn_map::{DynMap, Policy}, | 10 | dyn_map::{DynMap, Policy}, |
11 | ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId, | 11 | ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, |
12 | StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 12 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | 15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; |
@@ -29,6 +29,7 @@ pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new(); | |||
29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); | 29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); |
30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); | 30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); |
31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); | 31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); |
32 | pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); | ||
32 | 33 | ||
33 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); | 34 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); |
34 | 35 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index ba09a9126..211cb2faf 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -232,6 +232,13 @@ pub struct LifetimeParamId { | |||
232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; | 232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; |
233 | 233 | ||
234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
235 | pub struct ConstParamId { | ||
236 | pub parent: GenericDefId, | ||
237 | pub local_id: LocalConstParamId, | ||
238 | } | ||
239 | pub type LocalConstParamId = Idx<generics::ConstParamData>; | ||
240 | |||
241 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
235 | pub enum ContainerId { | 242 | pub enum ContainerId { |
236 | ModuleId(ModuleId), | 243 | ModuleId(ModuleId), |
237 | DefWithBodyId(DefWithBodyId), | 244 | DefWithBodyId(DefWithBodyId), |
@@ -254,6 +261,15 @@ pub enum AdtId { | |||
254 | } | 261 | } |
255 | impl_from!(StructId, UnionId, EnumId for AdtId); | 262 | impl_from!(StructId, UnionId, EnumId for AdtId); |
256 | 263 | ||
264 | /// A generic param | ||
265 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
266 | pub enum GenericParamId { | ||
267 | TypeParamId(TypeParamId), | ||
268 | LifetimeParamId(LifetimeParamId), | ||
269 | ConstParamId(ConstParamId), | ||
270 | } | ||
271 | impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId); | ||
272 | |||
257 | /// The defs which can be visible in the module. | 273 | /// The defs which can be visible in the module. |
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
259 | pub enum ModuleDefId { | 275 | pub enum ModuleDefId { |
@@ -350,6 +366,7 @@ pub enum AttrDefId { | |||
350 | TypeAliasId(TypeAliasId), | 366 | TypeAliasId(TypeAliasId), |
351 | MacroDefId(MacroDefId), | 367 | MacroDefId(MacroDefId), |
352 | ImplId(ImplId), | 368 | ImplId(ImplId), |
369 | GenericParamId(GenericParamId), | ||
353 | } | 370 | } |
354 | 371 | ||
355 | impl_from!( | 372 | impl_from!( |
@@ -363,7 +380,8 @@ impl_from!( | |||
363 | TraitId, | 380 | TraitId, |
364 | TypeAliasId, | 381 | TypeAliasId, |
365 | MacroDefId, | 382 | MacroDefId, |
366 | ImplId | 383 | ImplId, |
384 | GenericParamId | ||
367 | for AttrDefId | 385 | for AttrDefId |
368 | ); | 386 | ); |
369 | 387 | ||
@@ -488,6 +506,15 @@ impl AttrDefId { | |||
488 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, | 506 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, |
489 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, | 507 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, |
490 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, | 508 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, |
509 | AttrDefId::GenericParamId(it) => { | ||
510 | match it { | ||
511 | GenericParamId::TypeParamId(it) => it.parent, | ||
512 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
513 | GenericParamId::ConstParamId(it) => it.parent, | ||
514 | } | ||
515 | .module(db) | ||
516 | .krate | ||
517 | } | ||
491 | // FIXME: `MacroDefId` should store the defining module, then this can implement | 518 | // FIXME: `MacroDefId` should store the defining module, then this can implement |
492 | // `HasModule` | 519 | // `HasModule` |
493 | AttrDefId::MacroDefId(it) => it.krate, | 520 | AttrDefId::MacroDefId(it) => it.krate, |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ffd0381d4..5682e122d 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -249,7 +249,7 @@ impl CrateDefMap { | |||
249 | buf.push_str(" _"); | 249 | buf.push_str(" _"); |
250 | } | 250 | } |
251 | 251 | ||
252 | buf.push_str("\n"); | 252 | buf.push('\n'); |
253 | } | 253 | } |
254 | 254 | ||
255 | for (name, child) in map.modules[module].children.iter() { | 255 | for (name, child) in map.modules[module].children.iter() { |
@@ -454,7 +454,7 @@ mod diagnostics { | |||
454 | }); | 454 | }); |
455 | for token in tokens { | 455 | for token in tokens { |
456 | if token.kind() == SyntaxKind::IDENT | 456 | if token.kind() == SyntaxKind::IDENT |
457 | && token.to_string() == *name | 457 | && token.text() == name.as_str() |
458 | { | 458 | { |
459 | precise_location = Some(token.text_range()); | 459 | precise_location = Some(token.text_range()); |
460 | break 'outer; | 460 | break 'outer; |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index f9bf5bc72..e5e9e8ca1 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -677,7 +677,7 @@ fn macro_expansion_overflow() { | |||
677 | r#" | 677 | r#" |
678 | macro_rules! a { | 678 | macro_rules! a { |
679 | ($e:expr; $($t:tt)*) => { | 679 | ($e:expr; $($t:tt)*) => { |
680 | b!($($t)*); | 680 | b!(static = (); $($t)*); |
681 | }; | 681 | }; |
682 | () => {}; | 682 | () => {}; |
683 | } | 683 | } |
@@ -689,7 +689,7 @@ macro_rules! b { | |||
689 | () => {}; | 689 | () => {}; |
690 | } | 690 | } |
691 | 691 | ||
692 | b! { static = #[] (); } | 692 | b! { static = #[] ();} |
693 | "#, | 693 | "#, |
694 | expect![[r#" | 694 | expect![[r#" |
695 | crate | 695 | crate |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 8a01e6eea..9518ac109 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -123,7 +123,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
123 | // We follow what it did anyway :) | 123 | // We follow what it did anyway :) |
124 | if segments.len() == 1 && kind == PathKind::Plain { | 124 | if segments.len() == 1 && kind == PathKind::Plain { |
125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | 125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
126 | if let Some(crate_id) = hygiene.local_inner_macros() { | 126 | if let Some(crate_id) = hygiene.local_inner_macros(path) { |
127 | kind = PathKind::DollarCrate(crate_id); | 127 | kind = PathKind::DollarCrate(crate_id); |
128 | } | 128 | } |
129 | } | 129 | } |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index f8cc5e075..129f1dbac 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -20,9 +20,9 @@ use crate::{ | |||
20 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 21 | per_ns::PerNs, |
22 | visibility::{RawVisibility, Visibility}, | 22 | visibility::{RawVisibility, Visibility}, |
23 | AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, | 23 | AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId, |
24 | FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, | 24 | EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, |
25 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, | 25 | ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | #[derive(Debug, Clone, Default)] | 28 | #[derive(Debug, Clone, Default)] |
@@ -93,6 +93,7 @@ pub enum ValueNs { | |||
93 | StaticId(StaticId), | 93 | StaticId(StaticId), |
94 | StructId(StructId), | 94 | StructId(StructId), |
95 | EnumVariantId(EnumVariantId), | 95 | EnumVariantId(EnumVariantId), |
96 | GenericParam(ConstParamId), | ||
96 | } | 97 | } |
97 | 98 | ||
98 | impl Resolver { | 99 | impl Resolver { |
@@ -163,7 +164,7 @@ impl Resolver { | |||
163 | } | 164 | } |
164 | 165 | ||
165 | Scope::GenericParams { params, def } => { | 166 | Scope::GenericParams { params, def } => { |
166 | if let Some(local_id) = params.find_by_name(first_name) { | 167 | if let Some(local_id) = params.find_type_by_name(first_name) { |
167 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 168 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
168 | return Some(( | 169 | return Some(( |
169 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), | 170 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), |
@@ -285,11 +286,17 @@ impl Resolver { | |||
285 | Scope::ExprScope(_) => continue, | 286 | Scope::ExprScope(_) => continue, |
286 | 287 | ||
287 | Scope::GenericParams { params, def } if n_segments > 1 => { | 288 | Scope::GenericParams { params, def } if n_segments > 1 => { |
288 | if let Some(local_id) = params.find_by_name(first_name) { | 289 | if let Some(local_id) = params.find_type_by_name(first_name) { |
289 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); | 290 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); |
290 | return Some(ResolveValueResult::Partial(ty, 1)); | 291 | return Some(ResolveValueResult::Partial(ty, 1)); |
291 | } | 292 | } |
292 | } | 293 | } |
294 | Scope::GenericParams { params, def } if n_segments == 1 => { | ||
295 | if let Some(local_id) = params.find_const_by_name(first_name) { | ||
296 | let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def }); | ||
297 | return Some(ResolveValueResult::ValueNs(val)); | ||
298 | } | ||
299 | } | ||
293 | Scope::GenericParams { .. } => continue, | 300 | Scope::GenericParams { .. } => continue, |
294 | 301 | ||
295 | Scope::ImplDefScope(impl_) => { | 302 | Scope::ImplDefScope(impl_) => { |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 6382521fb..80b60d59f 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -259,7 +259,8 @@ fn format_args_expand( | |||
259 | } | 259 | } |
260 | for arg in &mut args { | 260 | for arg in &mut args { |
261 | // Remove `key =`. | 261 | // Remove `key =`. |
262 | if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { | 262 | if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) |
263 | { | ||
263 | arg.drain(..2); | 264 | arg.drain(..2); |
264 | } | 265 | } |
265 | } | 266 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 06f0a3ed9..0a0d021e0 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -404,7 +404,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
404 | TRY_EXPR => FragmentKind::Expr, | 404 | TRY_EXPR => FragmentKind::Expr, |
405 | TUPLE_EXPR => FragmentKind::Expr, | 405 | TUPLE_EXPR => FragmentKind::Expr, |
406 | PAREN_EXPR => FragmentKind::Expr, | 406 | PAREN_EXPR => FragmentKind::Expr, |
407 | 407 | ARRAY_EXPR => FragmentKind::Expr, | |
408 | FOR_EXPR => FragmentKind::Expr, | 408 | FOR_EXPR => FragmentKind::Expr, |
409 | PATH_EXPR => FragmentKind::Expr, | 409 | PATH_EXPR => FragmentKind::Expr, |
410 | CLOSURE_EXPR => FragmentKind::Expr, | 410 | CLOSURE_EXPR => FragmentKind::Expr, |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 7ab0a5e52..6042e15b2 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -2,30 +2,94 @@ | |||
2 | //! | 2 | //! |
3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at | 3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at |
4 | //! this moment, this is horribly incomplete and handles only `$crate`. | 4 | //! this moment, this is horribly incomplete and handles only `$crate`. |
5 | use std::sync::Arc; | ||
6 | |||
7 | use arena::{Arena, Idx}; | ||
5 | use base_db::CrateId; | 8 | use base_db::CrateId; |
6 | use either::Either; | 9 | use either::Either; |
7 | use syntax::ast; | 10 | use mbe::Origin; |
11 | use syntax::{ast, AstNode}; | ||
8 | 12 | ||
9 | use crate::{ | 13 | use crate::{ |
10 | db::AstDatabase, | 14 | db::AstDatabase, |
11 | name::{AsName, Name}, | 15 | name::{AsName, Name}, |
12 | HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, | 16 | ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, |
13 | }; | 17 | }; |
14 | 18 | ||
15 | #[derive(Clone, Debug)] | 19 | #[derive(Clone, Debug)] |
16 | pub struct Hygiene { | 20 | pub struct Hygiene { |
17 | // This is what `$crate` expands to | 21 | frames: Option<Arc<HygieneFrames>>, |
18 | def_crate: Option<CrateId>, | 22 | } |
23 | |||
24 | impl Hygiene { | ||
25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { | ||
26 | Hygiene { frames: Some(Arc::new(HygieneFrames::new(db, file_id.clone()))) } | ||
27 | } | ||
28 | |||
29 | pub fn new_unhygienic() -> Hygiene { | ||
30 | Hygiene { frames: None } | ||
31 | } | ||
32 | |||
33 | // FIXME: this should just return name | ||
34 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | ||
35 | if let Some(frames) = &self.frames { | ||
36 | if name_ref.text() == "$crate" { | ||
37 | if let Some(krate) = frames.root_crate(&name_ref) { | ||
38 | return Either::Right(krate); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | Either::Left(name_ref.as_name()) | ||
44 | } | ||
45 | |||
46 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { | ||
47 | let frames = self.frames.as_ref()?; | ||
48 | |||
49 | let mut token = path.syntax().first_token()?; | ||
50 | let mut current = frames.first(); | ||
51 | |||
52 | while let Some((frame, data)) = | ||
53 | current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?))) | ||
54 | { | ||
55 | let (mapped, origin) = data; | ||
56 | if origin == Origin::Def { | ||
57 | return if frame.local_inner { frame.krate } else { None }; | ||
58 | } | ||
59 | current = Some(&frames.0[frame.call_site?]); | ||
60 | token = mapped.value; | ||
61 | } | ||
62 | None | ||
63 | } | ||
64 | } | ||
65 | |||
66 | #[derive(Default, Debug)] | ||
67 | struct HygieneFrames(Arena<HygieneFrame>); | ||
68 | |||
69 | #[derive(Clone, Debug)] | ||
70 | struct HygieneFrame { | ||
71 | expansion: Option<ExpansionInfo>, | ||
19 | 72 | ||
20 | // Indicate this is a local inner macro | 73 | // Indicate this is a local inner macro |
21 | local_inner: bool, | 74 | local_inner: bool, |
75 | krate: Option<CrateId>, | ||
76 | |||
77 | call_site: Option<Idx<HygieneFrame>>, | ||
78 | def_site: Option<Idx<HygieneFrame>>, | ||
22 | } | 79 | } |
23 | 80 | ||
24 | impl Hygiene { | 81 | impl HygieneFrames { |
25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { | 82 | fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { |
26 | let (def_crate, local_inner) = match file_id.0 { | 83 | let mut frames = HygieneFrames::default(); |
84 | frames.add(db, file_id); | ||
85 | frames | ||
86 | } | ||
87 | |||
88 | fn add(&mut self, db: &dyn AstDatabase, file_id: HirFileId) -> Option<Idx<HygieneFrame>> { | ||
89 | let (krate, local_inner) = match file_id.0 { | ||
27 | HirFileIdRepr::FileId(_) => (None, false), | 90 | HirFileIdRepr::FileId(_) => (None, false), |
28 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { | 91 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { |
92 | MacroCallId::EagerMacro(_id) => (None, false), | ||
29 | MacroCallId::LazyMacro(id) => { | 93 | MacroCallId::LazyMacro(id) => { |
30 | let loc = db.lookup_intern_macro(id); | 94 | let loc = db.lookup_intern_macro(id); |
31 | match loc.def.kind { | 95 | match loc.def.kind { |
@@ -36,31 +100,68 @@ impl Hygiene { | |||
36 | MacroDefKind::ProcMacro(_) => (None, false), | 100 | MacroDefKind::ProcMacro(_) => (None, false), |
37 | } | 101 | } |
38 | } | 102 | } |
39 | MacroCallId::EagerMacro(_id) => (None, false), | ||
40 | }, | 103 | }, |
41 | }; | 104 | }; |
42 | Hygiene { def_crate, local_inner } | ||
43 | } | ||
44 | 105 | ||
45 | pub fn new_unhygienic() -> Hygiene { | 106 | let expansion = file_id.expansion_info(db); |
46 | Hygiene { def_crate: None, local_inner: false } | 107 | let expansion = match expansion { |
108 | None => { | ||
109 | return Some(self.0.alloc(HygieneFrame { | ||
110 | expansion: None, | ||
111 | local_inner, | ||
112 | krate, | ||
113 | call_site: None, | ||
114 | def_site: None, | ||
115 | })); | ||
116 | } | ||
117 | Some(it) => it, | ||
118 | }; | ||
119 | |||
120 | let def_site = expansion.def.clone(); | ||
121 | let call_site = expansion.arg.file_id; | ||
122 | let idx = self.0.alloc(HygieneFrame { | ||
123 | expansion: Some(expansion), | ||
124 | local_inner, | ||
125 | krate, | ||
126 | call_site: None, | ||
127 | def_site: None, | ||
128 | }); | ||
129 | |||
130 | self.0[idx].call_site = self.add(db, call_site); | ||
131 | self.0[idx].def_site = def_site.and_then(|it| self.add(db, it.file_id)); | ||
132 | |||
133 | Some(idx) | ||
47 | } | 134 | } |
48 | 135 | ||
49 | // FIXME: this should just return name | 136 | fn first(&self) -> Option<&HygieneFrame> { |
50 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | 137 | self.0.iter().next().map(|it| it.1) |
51 | if let Some(def_crate) = self.def_crate { | ||
52 | if name_ref.text() == "$crate" { | ||
53 | return Either::Right(def_crate); | ||
54 | } | ||
55 | } | ||
56 | Either::Left(name_ref.as_name()) | ||
57 | } | 138 | } |
58 | 139 | ||
59 | pub fn local_inner_macros(&self) -> Option<CrateId> { | 140 | fn root_crate(&self, name_ref: &ast::NameRef) -> Option<CrateId> { |
60 | if self.local_inner { | 141 | let mut token = name_ref.syntax().first_token()?; |
61 | self.def_crate | 142 | let first = self.first()?; |
62 | } else { | 143 | let mut result = first.krate; |
63 | None | 144 | let mut current = Some(first); |
145 | |||
146 | while let Some((frame, (mapped, origin))) = | ||
147 | current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?))) | ||
148 | { | ||
149 | result = frame.krate; | ||
150 | |||
151 | let site = match origin { | ||
152 | Origin::Def => frame.def_site, | ||
153 | Origin::Call => frame.call_site, | ||
154 | }; | ||
155 | |||
156 | let site = match site { | ||
157 | None => break, | ||
158 | Some(it) => it, | ||
159 | }; | ||
160 | |||
161 | current = Some(&self.0[site]); | ||
162 | token = mapped.value; | ||
64 | } | 163 | } |
164 | |||
165 | result | ||
65 | } | 166 | } |
66 | } | 167 | } |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 3fa1b1d77..5b6734a5f 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -340,11 +340,8 @@ impl ExpansionInfo { | |||
340 | Some(self.expanded.with_value(token)) | 340 | Some(self.expanded.with_value(token)) |
341 | } | 341 | } |
342 | 342 | ||
343 | pub fn map_token_up( | 343 | pub fn map_token_up(&self, token: &SyntaxToken) -> Option<(InFile<SyntaxToken>, Origin)> { |
344 | &self, | 344 | let token_id = self.exp_map.token_by_range(token.text_range())?; |
345 | token: InFile<&SyntaxToken>, | ||
346 | ) -> Option<(InFile<SyntaxToken>, Origin)> { | ||
347 | let token_id = self.exp_map.token_by_range(token.value.text_range())?; | ||
348 | 345 | ||
349 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | 346 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
350 | let (token_map, tt) = match origin { | 347 | let (token_map, tt) = match origin { |
@@ -359,7 +356,7 @@ impl ExpansionInfo { | |||
359 | ), | 356 | ), |
360 | }; | 357 | }; |
361 | 358 | ||
362 | let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; | 359 | let range = token_map.range_by_token(token_id)?.by_kind(token.kind())?; |
363 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) | 360 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) |
364 | .into_token()?; | 361 | .into_token()?; |
365 | Some((tt.with_value(token), origin)) | 362 | Some((tt.with_value(token), origin)) |
@@ -495,7 +492,7 @@ fn ascend_call_token( | |||
495 | expansion: &ExpansionInfo, | 492 | expansion: &ExpansionInfo, |
496 | token: InFile<SyntaxToken>, | 493 | token: InFile<SyntaxToken>, |
497 | ) -> Option<InFile<SyntaxToken>> { | 494 | ) -> Option<InFile<SyntaxToken>> { |
498 | let (mapped, origin) = expansion.map_token_up(token.as_ref())?; | 495 | let (mapped, origin) = expansion.map_token_up(&token.value)?; |
499 | if origin != Origin::Call { | 496 | if origin != Origin::Call { |
500 | return None; | 497 | return None; |
501 | } | 498 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 965c1780a..2dfccd191 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | itertools = "0.9.0" | 13 | itertools = "0.10.0" |
14 | arrayvec = "0.5.1" | 14 | arrayvec = "0.5.1" |
15 | smallvec = "1.2.0" | 15 | smallvec = "1.2.0" |
16 | ena = "0.14.0" | 16 | ena = "0.14.0" |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 66bdb8e88..f3567c49e 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -5,8 +5,8 @@ use std::sync::Arc; | |||
5 | use arena::map::ArenaMap; | 5 | use arena::map::ArenaMap; |
6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; | 6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, | 8 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, |
9 | TypeParamId, VariantId, | 9 | LocalFieldId, TypeParamId, VariantId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -37,6 +37,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] | 37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] |
38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; | 38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; |
39 | 39 | ||
40 | #[salsa::invoke(crate::lower::const_param_ty_query)] | ||
41 | fn const_param_ty(&self, def: ConstParamId) -> Ty; | ||
42 | |||
40 | #[salsa::invoke(crate::lower::impl_trait_query)] | 43 | #[salsa::invoke(crate::lower::impl_trait_query)] |
41 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; | 44 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; |
42 | 45 | ||
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 849415706..b4e453411 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | 156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this |
157 | // diagnostic if there are no type mismatches in the containing function. | 157 | // diagnostic if there are no type mismatches in the containing function. |
158 | if self.infer.type_mismatches.iter().next().is_some() { | 158 | if self.infer.type_mismatches.iter().next().is_some() { |
159 | return Some(()); | 159 | return None; |
160 | } | 160 | } |
161 | 161 | ||
162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | 162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); |
@@ -170,6 +170,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
170 | let mut args = args.clone(); | 170 | let mut args = args.clone(); |
171 | args.insert(0, *receiver); | 171 | args.insert(0, *receiver); |
172 | 172 | ||
173 | let receiver = &self.infer.type_of_expr[*receiver]; | ||
174 | if receiver.strip_references().is_unknown() { | ||
175 | // if the receiver is of unknown type, it's very likely we | ||
176 | // don't know enough to correctly resolve the method call. | ||
177 | // This is kind of a band-aid for #6975. | ||
178 | return None; | ||
179 | } | ||
180 | |||
173 | // FIXME: note that we erase information about substs here. This | 181 | // FIXME: note that we erase information about substs here. This |
174 | // is not right, but, luckily, doesn't matter as we care only | 182 | // is not right, but, luckily, doesn't matter as we care only |
175 | // about the number of params | 183 | // about the number of params |
@@ -505,6 +513,22 @@ fn f() { | |||
505 | } | 513 | } |
506 | 514 | ||
507 | #[test] | 515 | #[test] |
516 | fn method_unknown_receiver() { | ||
517 | // note: this is incorrect code, so there might be errors on this in the | ||
518 | // future, but we shouldn't emit an argument count diagnostic here | ||
519 | check_diagnostics( | ||
520 | r#" | ||
521 | trait Foo { fn method(&self, arg: usize) {} } | ||
522 | |||
523 | fn f() { | ||
524 | let x; | ||
525 | x.method(); | ||
526 | } | ||
527 | "#, | ||
528 | ); | ||
529 | } | ||
530 | |||
531 | #[test] | ||
508 | fn tuple_struct() { | 532 | fn tuple_struct() { |
509 | check_diagnostics( | 533 | check_diagnostics( |
510 | r#" | 534 | r#" |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 70a3f3075..f2fc69b2f 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -648,6 +648,8 @@ impl<'a> InferenceContext<'a> { | |||
648 | } | 648 | } |
649 | Expr::Array(array) => { | 649 | Expr::Array(array) => { |
650 | let elem_ty = match &expected.ty { | 650 | let elem_ty = match &expected.ty { |
651 | // FIXME: remove when https://github.com/rust-lang/rust/issues/80501 is fixed | ||
652 | #[allow(unreachable_patterns)] | ||
651 | ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { | 653 | ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { |
652 | st.as_single().clone() | 654 | st.as_single().clone() |
653 | } | 655 | } |
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 80d7ed10e..5d541104e 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -89,6 +89,7 @@ impl<'a> InferenceContext<'a> { | |||
89 | return None; | 89 | return None; |
90 | } | 90 | } |
91 | } | 91 | } |
92 | ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | let ty = self.db.value_ty(typable); | 95 | let ty = self.db.value_ty(typable); |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 357bd92f9..e00c7e176 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -791,6 +791,10 @@ impl Ty { | |||
791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | 791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) |
792 | } | 792 | } |
793 | 793 | ||
794 | pub fn is_unknown(&self) -> bool { | ||
795 | matches!(self, Ty::Unknown) | ||
796 | } | ||
797 | |||
794 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | 798 | /// If this is a `dyn Trait` type, this returns the `Trait` part. |
795 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | 799 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { |
796 | match self { | 800 | match self { |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8da56cd11..222f61a11 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -16,9 +16,9 @@ use hir_def::{ | |||
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 16 | path::{GenericArg, Path, PathSegment, PathSegments}, |
17 | resolver::{HasResolver, Resolver, TypeNs}, | 17 | resolver::{HasResolver, Resolver, TypeNs}, |
18 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TypeBound, TypeRef}, |
19 | AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, | 19 | AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, |
20 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | UnionId, VariantId, | 21 | TypeAliasId, TypeParamId, UnionId, VariantId, |
22 | }; | 22 | }; |
23 | use hir_expand::name::Name; | 23 | use hir_expand::name::Name; |
24 | use smallvec::SmallVec; | 24 | use smallvec::SmallVec; |
@@ -1221,6 +1221,15 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde | |||
1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) | 1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { | ||
1225 | let parent_data = db.generic_params(def.parent); | ||
1226 | let data = &parent_data.consts[def.local_id]; | ||
1227 | let resolver = def.parent.resolver(db.upcast()); | ||
1228 | let ctx = TyLoweringContext::new(db, &resolver); | ||
1229 | |||
1230 | Ty::from_hir(&ctx, &data.ty) | ||
1231 | } | ||
1232 | |||
1224 | pub(crate) fn impl_self_ty_recover( | 1233 | pub(crate) fn impl_self_ty_recover( |
1225 | db: &dyn HirDatabase, | 1234 | db: &dyn HirDatabase, |
1226 | _cycle: &[String], | 1235 | _cycle: &[String], |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index a7656b864..23b79abc4 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -371,6 +371,37 @@ expand!(); | |||
371 | } | 371 | } |
372 | 372 | ||
373 | #[test] | 373 | #[test] |
374 | fn infer_macro_with_dollar_crate_in_def_site() { | ||
375 | check_types( | ||
376 | r#" | ||
377 | //- /main.rs crate:main deps:foo | ||
378 | use foo::expand; | ||
379 | |||
380 | macro_rules! list { | ||
381 | ($($tt:tt)*) => { $($tt)* } | ||
382 | } | ||
383 | |||
384 | fn test() { | ||
385 | let r = expand!(); | ||
386 | r; | ||
387 | //^ u128 | ||
388 | } | ||
389 | |||
390 | //- /lib.rs crate:foo | ||
391 | #[macro_export] | ||
392 | macro_rules! expand { | ||
393 | () => { list!($crate::m!()) }; | ||
394 | } | ||
395 | |||
396 | #[macro_export] | ||
397 | macro_rules! m { | ||
398 | () => { 0u128 }; | ||
399 | } | ||
400 | "#, | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
374 | fn infer_type_value_non_legacy_macro_use_as() { | 405 | fn infer_type_value_non_legacy_macro_use_as() { |
375 | check_infer( | 406 | check_infer( |
376 | r#" | 407 | r#" |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 307a257b1..cffe8630b 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -326,6 +326,24 @@ fn infer_paren_macro_call() { | |||
326 | } | 326 | } |
327 | 327 | ||
328 | #[test] | 328 | #[test] |
329 | fn infer_array_macro_call() { | ||
330 | check_infer( | ||
331 | r#" | ||
332 | macro_rules! bar { () => {0u32} } | ||
333 | fn test() { | ||
334 | let a = [bar!()]; | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | !0..4 '0u32': u32 | ||
339 | 44..69 '{ ...()]; }': () | ||
340 | 54..55 'a': [u32; _] | ||
341 | 58..66 '[bar!()]': [u32; _] | ||
342 | "#]], | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | #[test] | ||
329 | fn bug_1030() { | 347 | fn bug_1030() { |
330 | check_infer( | 348 | check_infer( |
331 | r#" | 349 | r#" |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a61282d5a..8d431b920 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -2375,3 +2375,19 @@ fn infer_operator_overload() { | |||
2375 | "#]], | 2375 | "#]], |
2376 | ); | 2376 | ); |
2377 | } | 2377 | } |
2378 | |||
2379 | #[test] | ||
2380 | fn infer_const_params() { | ||
2381 | check_infer( | ||
2382 | r#" | ||
2383 | fn foo<const FOO: usize>() { | ||
2384 | let bar = FOO; | ||
2385 | } | ||
2386 | "#, | ||
2387 | expect![[r#" | ||
2388 | 27..49 '{ ...FOO; }': () | ||
2389 | 37..40 'bar': usize | ||
2390 | 43..46 'FOO': usize | ||
2391 | "#]], | ||
2392 | ); | ||
2393 | } | ||
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 4d483580d..f1544dbe0 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | indexmap = "1.4.0" | 14 | indexmap = "1.4.0" |
15 | itertools = "0.9.0" | 15 | itertools = "0.10.0" |
16 | log = "0.4.8" | 16 | log = "0.4.8" |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | oorandom = "11.1.2" | 18 | oorandom = "11.1.2" |
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 60e0cd4ad..3c2d39f5d 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -8,7 +8,7 @@ use ide_db::RootDatabase; | |||
8 | use syntax::{ast, match_ast, AstNode, TextRange}; | 8 | use syntax::{ast, match_ast, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, | 11 | display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | #[derive(Debug, Clone)] | 14 | #[derive(Debug, Clone)] |
@@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
61 | match node { | 61 | match node { |
62 | ast::Fn(it) => { | 62 | ast::Fn(it) => { |
63 | let def = sema.to_def(&it)?; | 63 | let def = sema.to_def(&it)?; |
64 | Some(def.to_nav(sema.db)) | 64 | def.try_to_nav(sema.db) |
65 | }, | 65 | }, |
66 | _ => None, | 66 | _ => None, |
67 | } | 67 | } |
@@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
99 | match callable.kind() { | 99 | match callable.kind() { |
100 | hir::CallableKind::Function(it) => { | 100 | hir::CallableKind::Function(it) => { |
101 | let fn_def: hir::Function = it.into(); | 101 | let fn_def: hir::Function = it.into(); |
102 | let nav = fn_def.to_nav(db); | 102 | let nav = fn_def.try_to_nav(db)?; |
103 | Some(nav) | 103 | Some(nav) |
104 | } | 104 | } |
105 | _ => None, | 105 | _ => None, |
@@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
107 | } | 107 | } |
108 | FnCallNode::MethodCallExpr(expr) => { | 108 | FnCallNode::MethodCallExpr(expr) => { |
109 | let function = sema.resolve_method_call(&expr)?; | 109 | let function = sema.resolve_method_call(&expr)?; |
110 | Some(function.to_nav(db)) | 110 | function.try_to_nav(db) |
111 | } | 111 | } |
112 | } { | 112 | } { |
113 | Some((func_target, name_ref.syntax().text_range())) | 113 | Some((func_target, name_ref.syntax().text_range())) |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 038273750..79d126ff2 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -199,6 +199,12 @@ fn check_unnecessary_braces_in_use_statement( | |||
199 | ) -> Option<()> { | 199 | ) -> Option<()> { |
200 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | 200 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; |
201 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | 201 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { |
202 | // If there is a comment inside the bracketed `use`, | ||
203 | // assume it is a commented out module path and don't show diagnostic. | ||
204 | if use_tree_list.has_inner_comment() { | ||
205 | return Some(()); | ||
206 | } | ||
207 | |||
202 | let use_range = use_tree_list.syntax().text_range(); | 208 | let use_range = use_tree_list.syntax().text_range(); |
203 | let edit = | 209 | let edit = |
204 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) | 210 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) |
@@ -638,6 +644,22 @@ mod a { | |||
638 | } | 644 | } |
639 | "#, | 645 | "#, |
640 | ); | 646 | ); |
647 | check_no_diagnostics( | ||
648 | r#" | ||
649 | use a; | ||
650 | use a::{ | ||
651 | c, | ||
652 | // d::e | ||
653 | }; | ||
654 | |||
655 | mod a { | ||
656 | mod c {} | ||
657 | mod d { | ||
658 | mod e {} | ||
659 | } | ||
660 | } | ||
661 | "#, | ||
662 | ); | ||
641 | check_fix( | 663 | check_fix( |
642 | r" | 664 | r" |
643 | mod b {} | 665 | mod b {} |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index d79f5c170..ec0f840e9 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -156,20 +156,23 @@ fn missing_record_expr_field_fix( | |||
156 | let record_fields = match VariantDef::from(def_id) { | 156 | let record_fields = match VariantDef::from(def_id) { |
157 | VariantDef::Struct(s) => { | 157 | VariantDef::Struct(s) => { |
158 | module = s.module(sema.db); | 158 | module = s.module(sema.db); |
159 | let source = s.source(sema.db); | 159 | #[allow(deprecated)] |
160 | let source = s.source(sema.db)?; | ||
160 | def_file_id = source.file_id; | 161 | def_file_id = source.file_id; |
161 | let fields = source.value.field_list()?; | 162 | let fields = source.value.field_list()?; |
162 | record_field_list(fields)? | 163 | record_field_list(fields)? |
163 | } | 164 | } |
164 | VariantDef::Union(u) => { | 165 | VariantDef::Union(u) => { |
165 | module = u.module(sema.db); | 166 | module = u.module(sema.db); |
166 | let source = u.source(sema.db); | 167 | #[allow(deprecated)] |
168 | let source = u.source(sema.db)?; | ||
167 | def_file_id = source.file_id; | 169 | def_file_id = source.file_id; |
168 | source.value.record_field_list()? | 170 | source.value.record_field_list()? |
169 | } | 171 | } |
170 | VariantDef::Variant(e) => { | 172 | VariantDef::Variant(e) => { |
171 | module = e.module(sema.db); | 173 | module = e.module(sema.db); |
172 | let source = e.source(sema.db); | 174 | #[allow(deprecated)] |
175 | let source = e.source(sema.db)?; | ||
173 | def_file_id = source.file_id; | 176 | def_file_id = source.file_id; |
174 | let fields = source.value.field_list()?; | 177 | let fields = source.value.field_list()?; |
175 | record_field_list(fields)? | 178 | record_field_list(fields)? |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 6431e7d6d..e24c78301 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -24,6 +24,7 @@ pub enum SymbolKind { | |||
24 | Impl, | 24 | Impl, |
25 | Field, | 25 | Field, |
26 | TypeParam, | 26 | TypeParam, |
27 | ConstParam, | ||
27 | LifetimeParam, | 28 | LifetimeParam, |
28 | ValueParam, | 29 | ValueParam, |
29 | SelfParam, | 30 | SelfParam, |
@@ -209,40 +210,32 @@ impl ToNav for FileSymbol { | |||
209 | impl TryToNav for Definition { | 210 | impl TryToNav for Definition { |
210 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 211 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
211 | match self { | 212 | match self { |
212 | Definition::Macro(it) => { | 213 | Definition::Macro(it) => it.try_to_nav(db), |
213 | // FIXME: Currently proc-macro do not have ast-node, | 214 | Definition::Field(it) => it.try_to_nav(db), |
214 | // such that it does not have source | ||
215 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
216 | if it.is_proc_macro() { | ||
217 | return None; | ||
218 | } | ||
219 | Some(it.to_nav(db)) | ||
220 | } | ||
221 | Definition::Field(it) => Some(it.to_nav(db)), | ||
222 | Definition::ModuleDef(it) => it.try_to_nav(db), | 215 | Definition::ModuleDef(it) => it.try_to_nav(db), |
223 | Definition::SelfType(it) => Some(it.to_nav(db)), | 216 | Definition::SelfType(it) => it.try_to_nav(db), |
224 | Definition::Local(it) => Some(it.to_nav(db)), | 217 | Definition::Local(it) => Some(it.to_nav(db)), |
225 | Definition::TypeParam(it) => Some(it.to_nav(db)), | 218 | Definition::TypeParam(it) => it.try_to_nav(db), |
226 | Definition::LifetimeParam(it) => Some(it.to_nav(db)), | 219 | Definition::LifetimeParam(it) => it.try_to_nav(db), |
227 | Definition::Label(it) => Some(it.to_nav(db)), | 220 | Definition::Label(it) => Some(it.to_nav(db)), |
221 | Definition::ConstParam(it) => it.try_to_nav(db), | ||
228 | } | 222 | } |
229 | } | 223 | } |
230 | } | 224 | } |
231 | 225 | ||
232 | impl TryToNav for hir::ModuleDef { | 226 | impl TryToNav for hir::ModuleDef { |
233 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 227 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
234 | let res = match self { | 228 | match self { |
235 | hir::ModuleDef::Module(it) => it.to_nav(db), | 229 | hir::ModuleDef::Module(it) => Some(it.to_nav(db)), |
236 | hir::ModuleDef::Function(it) => it.to_nav(db), | 230 | hir::ModuleDef::Function(it) => it.try_to_nav(db), |
237 | hir::ModuleDef::Adt(it) => it.to_nav(db), | 231 | hir::ModuleDef::Adt(it) => it.try_to_nav(db), |
238 | hir::ModuleDef::Variant(it) => it.to_nav(db), | 232 | hir::ModuleDef::Variant(it) => it.try_to_nav(db), |
239 | hir::ModuleDef::Const(it) => it.to_nav(db), | 233 | hir::ModuleDef::Const(it) => it.try_to_nav(db), |
240 | hir::ModuleDef::Static(it) => it.to_nav(db), | 234 | hir::ModuleDef::Static(it) => it.try_to_nav(db), |
241 | hir::ModuleDef::Trait(it) => it.to_nav(db), | 235 | hir::ModuleDef::Trait(it) => it.try_to_nav(db), |
242 | hir::ModuleDef::TypeAlias(it) => it.to_nav(db), | 236 | hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), |
243 | hir::ModuleDef::BuiltinType(_) => return None, | 237 | hir::ModuleDef::BuiltinType(_) => None, |
244 | }; | 238 | } |
245 | Some(res) | ||
246 | } | 239 | } |
247 | } | 240 | } |
248 | 241 | ||
@@ -277,13 +270,13 @@ impl ToNavFromAst for hir::Trait { | |||
277 | const KIND: SymbolKind = SymbolKind::Trait; | 270 | const KIND: SymbolKind = SymbolKind::Trait; |
278 | } | 271 | } |
279 | 272 | ||
280 | impl<D> ToNav for D | 273 | impl<D> TryToNav for D |
281 | where | 274 | where |
282 | D: HasSource + ToNavFromAst + Copy + HasAttrs, | 275 | D: HasSource + ToNavFromAst + Copy + HasAttrs, |
283 | D::Ast: ast::NameOwner + ShortLabel, | 276 | D::Ast: ast::NameOwner + ShortLabel, |
284 | { | 277 | { |
285 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 278 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
286 | let src = self.source(db); | 279 | let src = self.source(db)?; |
287 | let mut res = NavigationTarget::from_named( | 280 | let mut res = NavigationTarget::from_named( |
288 | db, | 281 | db, |
289 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 282 | src.as_ref().map(|it| it as &dyn ast::NameOwner), |
@@ -291,7 +284,7 @@ where | |||
291 | ); | 284 | ); |
292 | res.docs = self.docs(db); | 285 | res.docs = self.docs(db); |
293 | res.description = src.value.short_label(); | 286 | res.description = src.value.short_label(); |
294 | res | 287 | Some(res) |
295 | } | 288 | } |
296 | } | 289 | } |
297 | 290 | ||
@@ -310,9 +303,9 @@ impl ToNav for hir::Module { | |||
310 | } | 303 | } |
311 | } | 304 | } |
312 | 305 | ||
313 | impl ToNav for hir::Impl { | 306 | impl TryToNav for hir::Impl { |
314 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 307 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
315 | let src = self.source(db); | 308 | let src = self.source(db)?; |
316 | let derive_attr = self.is_builtin_derive(db); | 309 | let derive_attr = self.is_builtin_derive(db); |
317 | let frange = if let Some(item) = &derive_attr { | 310 | let frange = if let Some(item) = &derive_attr { |
318 | item.syntax().original_file_range(db) | 311 | item.syntax().original_file_range(db) |
@@ -325,21 +318,21 @@ impl ToNav for hir::Impl { | |||
325 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) | 318 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) |
326 | }; | 319 | }; |
327 | 320 | ||
328 | NavigationTarget::from_syntax( | 321 | Some(NavigationTarget::from_syntax( |
329 | frange.file_id, | 322 | frange.file_id, |
330 | "impl".into(), | 323 | "impl".into(), |
331 | focus_range, | 324 | focus_range, |
332 | frange.range, | 325 | frange.range, |
333 | SymbolKind::Impl, | 326 | SymbolKind::Impl, |
334 | ) | 327 | )) |
335 | } | 328 | } |
336 | } | 329 | } |
337 | 330 | ||
338 | impl ToNav for hir::Field { | 331 | impl TryToNav for hir::Field { |
339 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 332 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
340 | let src = self.source(db); | 333 | let src = self.source(db)?; |
341 | 334 | ||
342 | match &src.value { | 335 | let field_source = match &src.value { |
343 | FieldSource::Named(it) => { | 336 | FieldSource::Named(it) => { |
344 | let mut res = | 337 | let mut res = |
345 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); | 338 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); |
@@ -357,13 +350,14 @@ impl ToNav for hir::Field { | |||
357 | SymbolKind::Field, | 350 | SymbolKind::Field, |
358 | ) | 351 | ) |
359 | } | 352 | } |
360 | } | 353 | }; |
354 | Some(field_source) | ||
361 | } | 355 | } |
362 | } | 356 | } |
363 | 357 | ||
364 | impl ToNav for hir::MacroDef { | 358 | impl TryToNav for hir::MacroDef { |
365 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 359 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
366 | let src = self.source(db); | 360 | let src = self.source(db)?; |
367 | log::debug!("nav target {:#?}", src.value.syntax()); | 361 | log::debug!("nav target {:#?}", src.value.syntax()); |
368 | let mut res = NavigationTarget::from_named( | 362 | let mut res = NavigationTarget::from_named( |
369 | db, | 363 | db, |
@@ -371,26 +365,26 @@ impl ToNav for hir::MacroDef { | |||
371 | SymbolKind::Macro, | 365 | SymbolKind::Macro, |
372 | ); | 366 | ); |
373 | res.docs = self.docs(db); | 367 | res.docs = self.docs(db); |
374 | res | 368 | Some(res) |
375 | } | 369 | } |
376 | } | 370 | } |
377 | 371 | ||
378 | impl ToNav for hir::Adt { | 372 | impl TryToNav for hir::Adt { |
379 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 373 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
380 | match self { | 374 | match self { |
381 | hir::Adt::Struct(it) => it.to_nav(db), | 375 | hir::Adt::Struct(it) => it.try_to_nav(db), |
382 | hir::Adt::Union(it) => it.to_nav(db), | 376 | hir::Adt::Union(it) => it.try_to_nav(db), |
383 | hir::Adt::Enum(it) => it.to_nav(db), | 377 | hir::Adt::Enum(it) => it.try_to_nav(db), |
384 | } | 378 | } |
385 | } | 379 | } |
386 | } | 380 | } |
387 | 381 | ||
388 | impl ToNav for hir::AssocItem { | 382 | impl TryToNav for hir::AssocItem { |
389 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 383 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
390 | match self { | 384 | match self { |
391 | AssocItem::Function(it) => it.to_nav(db), | 385 | AssocItem::Function(it) => it.try_to_nav(db), |
392 | AssocItem::Const(it) => it.to_nav(db), | 386 | AssocItem::Const(it) => it.try_to_nav(db), |
393 | AssocItem::TypeAlias(it) => it.to_nav(db), | 387 | AssocItem::TypeAlias(it) => it.try_to_nav(db), |
394 | } | 388 | } |
395 | } | 389 | } |
396 | } | 390 | } |
@@ -444,9 +438,9 @@ impl ToNav for hir::Label { | |||
444 | } | 438 | } |
445 | } | 439 | } |
446 | 440 | ||
447 | impl ToNav for hir::TypeParam { | 441 | impl TryToNav for hir::TypeParam { |
448 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
449 | let src = self.source(db); | 443 | let src = self.source(db)?; |
450 | let full_range = match &src.value { | 444 | let full_range = match &src.value { |
451 | Either::Left(it) => it.syntax().text_range(), | 445 | Either::Left(it) => it.syntax().text_range(), |
452 | Either::Right(it) => it.syntax().text_range(), | 446 | Either::Right(it) => it.syntax().text_range(), |
@@ -455,7 +449,7 @@ impl ToNav for hir::TypeParam { | |||
455 | Either::Left(_) => None, | 449 | Either::Left(_) => None, |
456 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), | 450 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), |
457 | }; | 451 | }; |
458 | NavigationTarget { | 452 | Some(NavigationTarget { |
459 | file_id: src.file_id.original_file(db), | 453 | file_id: src.file_id.original_file(db), |
460 | name: self.name(db).to_string().into(), | 454 | name: self.name(db).to_string().into(), |
461 | kind: Some(SymbolKind::TypeParam), | 455 | kind: Some(SymbolKind::TypeParam), |
@@ -464,15 +458,15 @@ impl ToNav for hir::TypeParam { | |||
464 | container_name: None, | 458 | container_name: None, |
465 | description: None, | 459 | description: None, |
466 | docs: None, | 460 | docs: None, |
467 | } | 461 | }) |
468 | } | 462 | } |
469 | } | 463 | } |
470 | 464 | ||
471 | impl ToNav for hir::LifetimeParam { | 465 | impl TryToNav for hir::LifetimeParam { |
472 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 466 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
473 | let src = self.source(db); | 467 | let src = self.source(db)?; |
474 | let full_range = src.value.syntax().text_range(); | 468 | let full_range = src.value.syntax().text_range(); |
475 | NavigationTarget { | 469 | Some(NavigationTarget { |
476 | file_id: src.file_id.original_file(db), | 470 | file_id: src.file_id.original_file(db), |
477 | name: self.name(db).to_string().into(), | 471 | name: self.name(db).to_string().into(), |
478 | kind: Some(SymbolKind::LifetimeParam), | 472 | kind: Some(SymbolKind::LifetimeParam), |
@@ -481,7 +475,24 @@ impl ToNav for hir::LifetimeParam { | |||
481 | container_name: None, | 475 | container_name: None, |
482 | description: None, | 476 | description: None, |
483 | docs: None, | 477 | docs: None, |
484 | } | 478 | }) |
479 | } | ||
480 | } | ||
481 | |||
482 | impl TryToNav for hir::ConstParam { | ||
483 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | ||
484 | let src = self.source(db)?; | ||
485 | let full_range = src.value.syntax().text_range(); | ||
486 | Some(NavigationTarget { | ||
487 | file_id: src.file_id.original_file(db), | ||
488 | name: self.name(db).to_string().into(), | ||
489 | kind: Some(SymbolKind::ConstParam), | ||
490 | full_range, | ||
491 | focus_range: src.value.name().map(|n| n.syntax().text_range()), | ||
492 | container_name: None, | ||
493 | description: None, | ||
494 | docs: None, | ||
495 | }) | ||
485 | } | 496 | } |
486 | } | 497 | } |
487 | 498 | ||
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index e10516f43..367fac05e 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -193,6 +193,7 @@ fn rewrite_intra_doc_link( | |||
193 | Definition::SelfType(_) | 193 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 194 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 195 | | Definition::TypeParam(_) |
196 | | Definition::ConstParam(_) | ||
196 | | Definition::LifetimeParam(_) | 197 | | Definition::LifetimeParam(_) |
197 | | Definition::Label(_) => return None, | 198 | | Definition::Label(_) => return None, |
198 | }?; | 199 | }?; |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 6eac39639..da9378a97 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics}; | |||
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; |
4 | 4 | ||
5 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 5 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
6 | 6 | ||
7 | // Feature: Go to Implementation | 7 | // Feature: Go to Implementation |
8 | // | 8 | // |
@@ -55,7 +55,7 @@ fn impls_for_def( | |||
55 | impls | 55 | impls |
56 | .into_iter() | 56 | .into_iter() |
57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) | 57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) |
58 | .map(|imp| imp.to_nav(sema.db)) | 58 | .filter_map(|imp| imp.try_to_nav(sema.db)) |
59 | .collect(), | 59 | .collect(), |
60 | ) | 60 | ) |
61 | } | 61 | } |
@@ -69,7 +69,7 @@ fn impls_for_trait( | |||
69 | 69 | ||
70 | let impls = Impl::for_trait(sema.db, krate, tr); | 70 | let impls = Impl::for_trait(sema.db, krate, tr); |
71 | 71 | ||
72 | Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect()) | 72 | Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()) |
73 | } | 73 | } |
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index aba6bf5dc..7e84e06be 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ide_db::RootDatabase; | 1 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 3 | ||
4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 4 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
5 | 5 | ||
6 | // Feature: Go to Type Definition | 6 | // Feature: Go to Type Definition |
7 | // | 7 | // |
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition( | |||
37 | 37 | ||
38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; | 38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
39 | 39 | ||
40 | let nav = adt_def.to_nav(db); | 40 | let nav = adt_def.try_to_nav(db)?; |
41 | Some(RangeInfo::new(node.text_range(), vec![nav])) | 41 | Some(RangeInfo::new(node.text_range(), vec![nav])) |
42 | } | 42 | } |
43 | 43 | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 73245fbe7..2737c900f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, | |||
13 | use test_utils::mark; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, | 16 | display::{macro_label, ShortLabel, TryToNav}, |
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
@@ -109,6 +109,8 @@ pub(crate) fn hover( | |||
109 | match node { | 109 | match node { |
110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), | 110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), |
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
112 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | ||
113 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | ||
112 | _ => None, | 114 | _ => None, |
113 | } | 115 | } |
114 | }; | 116 | }; |
@@ -181,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
181 | 183 | ||
182 | match def { | 184 | match def { |
183 | Definition::ModuleDef(it) => match it { | 185 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | 186 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), |
185 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | 187 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), |
186 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | 188 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), |
187 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | 189 | ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), |
188 | _ => None, | 190 | _ => None, |
189 | }, | 191 | }, |
190 | _ => None, | 192 | _ => None, |
@@ -204,7 +206,8 @@ fn runnable_action( | |||
204 | _ => None, | 206 | _ => None, |
205 | }, | 207 | }, |
206 | ModuleDef::Function(it) => { | 208 | ModuleDef::Function(it) => { |
207 | let src = it.source(sema.db); | 209 | #[allow(deprecated)] |
210 | let src = it.source(sema.db)?; | ||
208 | if src.file_id != file_id.into() { | 211 | if src.file_id != file_id.into() { |
209 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 212 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
210 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 213 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
@@ -324,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
324 | let mod_path = definition_mod_path(db, &def); | 327 | let mod_path = definition_mod_path(db, &def); |
325 | return match def { | 328 | return match def { |
326 | Definition::Macro(it) => { | 329 | Definition::Macro(it) => { |
327 | // FIXME: Currently proc-macro do not have ast-node, | 330 | let label = macro_label(&it.source(db)?.value); |
328 | // such that it does not have source | ||
329 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
330 | if it.is_proc_macro() { | ||
331 | return None; | ||
332 | } | ||
333 | let label = macro_label(&it.source(db).value); | ||
334 | from_def_source_labeled(db, it, Some(label), mod_path) | 331 | from_def_source_labeled(db, it, Some(label), mod_path) |
335 | } | 332 | } |
336 | Definition::Field(def) => { | 333 | Definition::Field(def) => { |
337 | let src = def.source(db).value; | 334 | #[allow(deprecated)] |
335 | let src = def.source(db)?.value; | ||
338 | if let FieldSource::Named(it) = src { | 336 | if let FieldSource::Named(it) = src { |
339 | from_def_source_labeled(db, def, it.short_label(), mod_path) | 337 | from_def_source_labeled(db, def, it.short_label(), mod_path) |
340 | } else { | 338 | } else { |
@@ -360,9 +358,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
360 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | 358 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
361 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | 359 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
362 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 360 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
363 | ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), | 361 | ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)), |
364 | }, | 362 | }, |
365 | Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), | 363 | Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), |
366 | Definition::SelfType(impl_def) => { | 364 | Definition::SelfType(impl_def) => { |
367 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 365 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
368 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 366 | Adt::Struct(it) => from_def_source(db, it, mod_path), |
@@ -370,7 +368,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 368 | Adt::Enum(it) => from_def_source(db, it, mod_path), |
371 | }) | 369 | }) |
372 | } | 370 | } |
373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { | 371 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
372 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | ||
373 | Definition::TypeParam(_) | Definition::ConstParam(_) => { | ||
374 | // FIXME: Hover for generic param | 374 | // FIXME: Hover for generic param |
375 | None | 375 | None |
376 | } | 376 | } |
@@ -381,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
381 | D: HasSource<Ast = A> + HasAttrs + Copy, | 381 | D: HasSource<Ast = A> + HasAttrs + Copy, |
382 | A: ShortLabel, | 382 | A: ShortLabel, |
383 | { | 383 | { |
384 | let short_label = def.source(db).value.short_label(); | 384 | #[allow(deprecated)] |
385 | let short_label = def.source(db)?.value.short_label(); | ||
385 | from_def_source_labeled(db, def, short_label, mod_path) | 386 | from_def_source_labeled(db, def, short_label, mod_path) |
386 | } | 387 | } |
387 | 388 | ||
@@ -403,7 +404,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
403 | return tokens.max_by_key(priority); | 404 | return tokens.max_by_key(priority); |
404 | fn priority(n: &SyntaxToken) -> usize { | 405 | fn priority(n: &SyntaxToken) -> usize { |
405 | match n.kind() { | 406 | match n.kind() { |
406 | IDENT | INT_NUMBER => 3, | 407 | IDENT | INT_NUMBER | LIFETIME_IDENT => 3, |
407 | T!['('] | T![')'] => 2, | 408 | T!['('] | T![')'] => 2, |
408 | kind if kind.is_trivia() => 0, | 409 | kind if kind.is_trivia() => 0, |
409 | _ => 1, | 410 | _ => 1, |
@@ -1169,7 +1170,10 @@ fn f() { fo<|>o!(); } | |||
1169 | r#"struct TS(String, i32<|>);"#, | 1170 | r#"struct TS(String, i32<|>);"#, |
1170 | expect![[r#" | 1171 | expect![[r#" |
1171 | *i32* | 1172 | *i32* |
1173 | |||
1174 | ```rust | ||
1172 | i32 | 1175 | i32 |
1176 | ``` | ||
1173 | "#]], | 1177 | "#]], |
1174 | ) | 1178 | ) |
1175 | } | 1179 | } |
@@ -3221,4 +3225,36 @@ fn no_hover() { | |||
3221 | "#, | 3225 | "#, |
3222 | ); | 3226 | ); |
3223 | } | 3227 | } |
3228 | |||
3229 | #[test] | ||
3230 | fn hover_label() { | ||
3231 | check( | ||
3232 | r#" | ||
3233 | fn foo() { | ||
3234 | 'label<|>: loop {} | ||
3235 | } | ||
3236 | "#, | ||
3237 | expect![[r#" | ||
3238 | *'label* | ||
3239 | |||
3240 | ```rust | ||
3241 | 'label | ||
3242 | ``` | ||
3243 | "#]], | ||
3244 | ); | ||
3245 | } | ||
3246 | |||
3247 | #[test] | ||
3248 | fn hover_lifetime() { | ||
3249 | check( | ||
3250 | r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, | ||
3251 | expect![[r#" | ||
3252 | *'lifetime* | ||
3253 | |||
3254 | ```rust | ||
3255 | 'lifetime | ||
3256 | ``` | ||
3257 | "#]], | ||
3258 | ); | ||
3259 | } | ||
3224 | } | 3260 | } |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 25c2047ca..a450794f3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -480,7 +480,7 @@ impl Analysis { | |||
480 | config: &CompletionConfig, | 480 | config: &CompletionConfig, |
481 | position: FilePosition, | 481 | position: FilePosition, |
482 | full_import_path: &str, | 482 | full_import_path: &str, |
483 | imported_name: &str, | 483 | imported_name: String, |
484 | ) -> Cancelable<Vec<TextEdit>> { | 484 | ) -> Cancelable<Vec<TextEdit>> { |
485 | Ok(self | 485 | Ok(self |
486 | .with_db(|db| { | 486 | .with_db(|db| { |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 21b2d7ca1..fa58fc319 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -1144,4 +1144,20 @@ fn foo<'a>() -> &'a () { | |||
1144 | "#]], | 1144 | "#]], |
1145 | ); | 1145 | ); |
1146 | } | 1146 | } |
1147 | |||
1148 | #[test] | ||
1149 | fn test_find_const_param() { | ||
1150 | check( | ||
1151 | r#" | ||
1152 | fn foo<const FOO<|>: usize>() -> usize { | ||
1153 | FOO | ||
1154 | } | ||
1155 | "#, | ||
1156 | expect![[r#" | ||
1157 | FOO ConstParam FileId(0) 7..23 13..16 Other | ||
1158 | |||
1159 | FileId(0) 42..45 Other | ||
1160 | "#]], | ||
1161 | ); | ||
1162 | } | ||
1147 | } | 1163 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 891183266..c893afc7c 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -230,7 +230,7 @@ impl TestAttr { | |||
230 | 230 | ||
231 | const RUSTDOC_FENCE: &str = "```"; | 231 | const RUSTDOC_FENCE: &str = "```"; |
232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
233 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 233 | &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; |
234 | 234 | ||
235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | 235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { |
236 | attrs.docs().map_or(false, |doc| { | 236 | attrs.docs().map_or(false, |doc| { |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 5ad96581b..ba0085244 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -819,6 +819,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
819 | }, | 819 | }, |
820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), | 820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), |
821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), | 821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), |
822 | Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam), | ||
822 | Definition::Local(local) => { | 823 | Definition::Local(local) => { |
823 | let tag = if local.is_param(db) { | 824 | let tag = if local.is_param(db) { |
824 | HighlightTag::Symbol(SymbolKind::ValueParam) | 825 | HighlightTag::Symbol(SymbolKind::ValueParam) |
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs index 9eb184c74..6cbd683c6 100644 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ b/crates/ide/src/syntax_highlighting/injection.rs | |||
@@ -54,8 +54,17 @@ pub(super) fn highlight_injection( | |||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | 54 | type RangesMap = BTreeMap<TextSize, TextSize>; |
55 | 55 | ||
56 | const RUSTDOC_FENCE: &'static str = "```"; | 56 | const RUSTDOC_FENCE: &'static str = "```"; |
57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = | 57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ |
58 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | 58 | "", |
59 | "rust", | ||
60 | "should_panic", | ||
61 | "ignore", | ||
62 | "no_run", | ||
63 | "compile_fail", | ||
64 | "edition2015", | ||
65 | "edition2018", | ||
66 | "edition2021", | ||
67 | ]; | ||
59 | 68 | ||
60 | /// Extracts Rust code from documentation comments as well as a mapping from | 69 | /// Extracts Rust code from documentation comments as well as a mapping from |
61 | /// the extracted source code back to the original source ranges. | 70 | /// the extracted source code back to the original source ranges. |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 2a6cc0cab..8b8867079 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -77,6 +77,7 @@ impl HighlightTag { | |||
77 | SymbolKind::Function => "function", | 77 | SymbolKind::Function => "function", |
78 | SymbolKind::TypeAlias => "type_alias", | 78 | SymbolKind::TypeAlias => "type_alias", |
79 | SymbolKind::TypeParam => "type_param", | 79 | SymbolKind::TypeParam => "type_param", |
80 | SymbolKind::ConstParam => "const_param", | ||
80 | SymbolKind::LifetimeParam => "lifetime", | 81 | SymbolKind::LifetimeParam => "lifetime", |
81 | SymbolKind::Macro => "macro", | 82 | SymbolKind::Macro => "macro", |
82 | SymbolKind::Local => "variable", | 83 | SymbolKind::Local => "variable", |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 72ff9dd40..02270b077 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -118,6 +118,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> |
119 | <span class="punctuation">}</span> | 119 | <span class="punctuation">}</span> |
120 | 120 | ||
121 | <span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation"><</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">usize</span> <span class="punctuation">{</span> | ||
122 | <span class="const_param">FOO</span> | ||
123 | <span class="punctuation">}</span> | ||
124 | |||
121 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> | 125 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> |
122 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation"><</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 126 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation"><</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
123 | <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> | 127 | <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index e0df0d2b5..30b5b648e 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -91,6 +91,10 @@ fn never() -> ! { | |||
91 | loop {} | 91 | loop {} |
92 | } | 92 | } |
93 | 93 | ||
94 | fn const_param<const FOO: usize>() -> usize { | ||
95 | FOO | ||
96 | } | ||
97 | |||
94 | use ops::Fn; | 98 | use ops::Fn; |
95 | fn baz<F: Fn() -> ()>(f: F) { | 99 | fn baz<F: Fn() -> ()>(f: F) { |
96 | f() | 100 | f() |
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index 0ad6e1000..ebe53c8ee 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml | |||
@@ -19,7 +19,7 @@ fst = { version = "0.4", default-features = false } | |||
19 | rustc-hash = "1.1.0" | 19 | rustc-hash = "1.1.0" |
20 | once_cell = "1.3.1" | 20 | once_cell = "1.3.1" |
21 | either = "1.6.1" | 21 | either = "1.6.1" |
22 | itertools = "0.9.0" | 22 | itertools = "0.10.0" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | syntax = { path = "../syntax", version = "0.0.0" } | 25 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index d33a6cb86..cc5078bf0 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, | 9 | db::HirDatabase, ConstParam, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, |
10 | Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, | 10 | MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode}, | 13 | ast::{self, AstNode}, |
@@ -26,6 +26,7 @@ pub enum Definition { | |||
26 | Local(Local), | 26 | Local(Local), |
27 | TypeParam(TypeParam), | 27 | TypeParam(TypeParam), |
28 | LifetimeParam(LifetimeParam), | 28 | LifetimeParam(LifetimeParam), |
29 | ConstParam(ConstParam), | ||
29 | Label(Label), | 30 | Label(Label), |
30 | } | 31 | } |
31 | 32 | ||
@@ -39,6 +40,7 @@ impl Definition { | |||
39 | Definition::Local(it) => Some(it.module(db)), | 40 | Definition::Local(it) => Some(it.module(db)), |
40 | Definition::TypeParam(it) => Some(it.module(db)), | 41 | Definition::TypeParam(it) => Some(it.module(db)), |
41 | Definition::LifetimeParam(it) => Some(it.module(db)), | 42 | Definition::LifetimeParam(it) => Some(it.module(db)), |
43 | Definition::ConstParam(it) => Some(it.module(db)), | ||
42 | Definition::Label(it) => Some(it.module(db)), | 44 | Definition::Label(it) => Some(it.module(db)), |
43 | } | 45 | } |
44 | } | 46 | } |
@@ -52,6 +54,7 @@ impl Definition { | |||
52 | Definition::Local(_) => None, | 54 | Definition::Local(_) => None, |
53 | Definition::TypeParam(_) => None, | 55 | Definition::TypeParam(_) => None, |
54 | Definition::LifetimeParam(_) => None, | 56 | Definition::LifetimeParam(_) => None, |
57 | Definition::ConstParam(_) => None, | ||
55 | Definition::Label(_) => None, | 58 | Definition::Label(_) => None, |
56 | } | 59 | } |
57 | } | 60 | } |
@@ -79,6 +82,7 @@ impl Definition { | |||
79 | Definition::Local(it) => it.name(db)?, | 82 | Definition::Local(it) => it.name(db)?, |
80 | Definition::TypeParam(it) => it.name(db), | 83 | Definition::TypeParam(it) => it.name(db), |
81 | Definition::LifetimeParam(it) => it.name(db), | 84 | Definition::LifetimeParam(it) => it.name(db), |
85 | Definition::ConstParam(it) => it.name(db), | ||
82 | Definition::Label(it) => it.name(db), | 86 | Definition::Label(it) => it.name(db), |
83 | }; | 87 | }; |
84 | Some(name) | 88 | Some(name) |
@@ -233,6 +237,10 @@ impl NameClass { | |||
233 | let def = sema.to_def(&it)?; | 237 | let def = sema.to_def(&it)?; |
234 | Some(NameClass::Definition(Definition::TypeParam(def))) | 238 | Some(NameClass::Definition(Definition::TypeParam(def))) |
235 | }, | 239 | }, |
240 | ast::ConstParam(it) => { | ||
241 | let def = sema.to_def(&it)?; | ||
242 | Some(NameClass::Definition(Definition::ConstParam(def))) | ||
243 | }, | ||
236 | _ => None, | 244 | _ => None, |
237 | } | 245 | } |
238 | } | 246 | } |
@@ -417,6 +425,7 @@ impl From<PathResolution> for Definition { | |||
417 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | 425 | PathResolution::TypeParam(par) => Definition::TypeParam(par), |
418 | PathResolution::Macro(def) => Definition::Macro(def), | 426 | PathResolution::Macro(def) => Definition::Macro(def), |
419 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | 427 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), |
428 | PathResolution::ConstParam(par) => Definition::ConstParam(par), | ||
420 | } | 429 | } |
421 | } | 430 | } |
422 | } | 431 | } |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index b2980a5d6..0f4c2ca47 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -15,19 +15,23 @@ use rustc_hash::FxHashSet; | |||
15 | pub fn find_exact_imports<'a>( | 15 | pub fn find_exact_imports<'a>( |
16 | sema: &Semantics<'a, RootDatabase>, | 16 | sema: &Semantics<'a, RootDatabase>, |
17 | krate: Crate, | 17 | krate: Crate, |
18 | name_to_import: &str, | 18 | name_to_import: String, |
19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
20 | let _p = profile::span("find_exact_imports"); | 20 | let _p = profile::span("find_exact_imports"); |
21 | find_imports( | 21 | find_imports( |
22 | sema, | 22 | sema, |
23 | krate, | 23 | krate, |
24 | { | 24 | { |
25 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | 25 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); |
26 | local_query.exact(); | 26 | local_query.exact(); |
27 | local_query.limit(40); | 27 | local_query.limit(40); |
28 | local_query | 28 | local_query |
29 | }, | 29 | }, |
30 | import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40), | 30 | import_map::Query::new(name_to_import) |
31 | .limit(40) | ||
32 | .name_only() | ||
33 | .search_mode(import_map::SearchMode::Equals) | ||
34 | .case_sensitive(), | ||
31 | ) | 35 | ) |
32 | } | 36 | } |
33 | 37 | ||
@@ -35,17 +39,18 @@ pub fn find_similar_imports<'a>( | |||
35 | sema: &Semantics<'a, RootDatabase>, | 39 | sema: &Semantics<'a, RootDatabase>, |
36 | krate: Crate, | 40 | krate: Crate, |
37 | limit: Option<usize>, | 41 | limit: Option<usize>, |
38 | name_to_import: &str, | 42 | fuzzy_search_string: String, |
39 | ignore_modules: bool, | 43 | name_only: bool, |
40 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 44 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
41 | let _p = profile::span("find_similar_imports"); | 45 | let _p = profile::span("find_similar_imports"); |
42 | 46 | ||
43 | let mut external_query = import_map::Query::new(name_to_import); | 47 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) |
44 | if ignore_modules { | 48 | .search_mode(import_map::SearchMode::Fuzzy); |
45 | external_query = external_query.exclude_import_kind(import_map::ImportKind::Module); | 49 | if name_only { |
50 | external_query = external_query.name_only(); | ||
46 | } | 51 | } |
47 | 52 | ||
48 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | 53 | let mut local_query = symbol_index::Query::new(fuzzy_search_string); |
49 | 54 | ||
50 | if let Some(limit) = limit { | 55 | if let Some(limit) = limit { |
51 | local_query.limit(limit); | 56 | local_query.limit(limit); |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index ff10f71c3..436c59d2c 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -121,31 +121,56 @@ impl Definition { | |||
121 | 121 | ||
122 | if let Definition::Local(var) = self { | 122 | if let Definition::Local(var) = self { |
123 | let range = match var.parent(db) { | 123 | let range = match var.parent(db) { |
124 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | 124 | DefWithBody::Function(f) => { |
125 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | 125 | f.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
126 | DefWithBody::Static(s) => s.source(db).value.syntax().text_range(), | 126 | } |
127 | DefWithBody::Const(c) => { | ||
128 | c.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
129 | } | ||
130 | DefWithBody::Static(s) => { | ||
131 | s.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
132 | } | ||
127 | }; | 133 | }; |
128 | let mut res = FxHashMap::default(); | 134 | let mut res = FxHashMap::default(); |
129 | res.insert(file_id, Some(range)); | 135 | res.insert(file_id, range); |
130 | return SearchScope::new(res); | 136 | return SearchScope::new(res); |
131 | } | 137 | } |
132 | 138 | ||
133 | if let Definition::LifetimeParam(param) = self { | 139 | if let Definition::LifetimeParam(param) = self { |
140 | #[allow(deprecated)] | ||
134 | let range = match param.parent(db) { | 141 | let range = match param.parent(db) { |
135 | hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(), | 142 | hir::GenericDef::Function(it) => { |
143 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
144 | } | ||
136 | hir::GenericDef::Adt(it) => match it { | 145 | hir::GenericDef::Adt(it) => match it { |
137 | hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), | 146 | hir::Adt::Struct(it) => { |
138 | hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), | 147 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
139 | hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(), | 148 | } |
149 | hir::Adt::Union(it) => { | ||
150 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
151 | } | ||
152 | hir::Adt::Enum(it) => { | ||
153 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
154 | } | ||
140 | }, | 155 | }, |
141 | hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(), | 156 | hir::GenericDef::Trait(it) => { |
142 | hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), | 157 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
143 | hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(), | 158 | } |
144 | hir::GenericDef::Variant(it) => it.source(db).value.syntax().text_range(), | 159 | hir::GenericDef::TypeAlias(it) => { |
145 | hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), | 160 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
161 | } | ||
162 | hir::GenericDef::Impl(it) => { | ||
163 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
164 | } | ||
165 | hir::GenericDef::Variant(it) => { | ||
166 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
167 | } | ||
168 | hir::GenericDef::Const(it) => { | ||
169 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
170 | } | ||
146 | }; | 171 | }; |
147 | let mut res = FxHashMap::default(); | 172 | let mut res = FxHashMap::default(); |
148 | res.insert(file_id, Some(range)); | 173 | res.insert(file_id, range); |
149 | return SearchScope::new(res); | 174 | return SearchScope::new(res); |
150 | } | 175 | } |
151 | 176 | ||
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 3ad609a00..b3472879d 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -14,10 +14,10 @@ mod tests; | |||
14 | 14 | ||
15 | use std::fmt; | 15 | use std::fmt; |
16 | 16 | ||
17 | pub use tt::{Delimiter, Punct}; | 17 | pub use tt::{Delimiter, DelimiterKind, Punct}; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | parser::{parse_pattern, Op}, | 20 | parser::{parse_pattern, parse_template, Op}, |
21 | tt_iter::TtIter, | 21 | tt_iter::TtIter, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -78,8 +78,24 @@ pub struct MacroRules { | |||
78 | 78 | ||
79 | #[derive(Clone, Debug, PartialEq, Eq)] | 79 | #[derive(Clone, Debug, PartialEq, Eq)] |
80 | struct Rule { | 80 | struct Rule { |
81 | lhs: tt::Subtree, | 81 | lhs: MetaTemplate, |
82 | rhs: tt::Subtree, | 82 | rhs: MetaTemplate, |
83 | } | ||
84 | |||
85 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
86 | struct MetaTemplate { | ||
87 | delimiter: Option<Delimiter>, | ||
88 | tokens: Vec<Result<Op, ExpandError>>, | ||
89 | } | ||
90 | |||
91 | impl<'a> MetaTemplate { | ||
92 | fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> { | ||
93 | self.tokens.iter() | ||
94 | } | ||
95 | |||
96 | fn delimiter_kind(&self) -> Option<DelimiterKind> { | ||
97 | self.delimiter.map(|it| it.kind) | ||
98 | } | ||
83 | } | 99 | } |
84 | 100 | ||
85 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 101 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
@@ -167,7 +183,7 @@ impl MacroRules { | |||
167 | rules.push(rule); | 183 | rules.push(rule); |
168 | if let Err(()) = src.expect_char(';') { | 184 | if let Err(()) = src.expect_char(';') { |
169 | if src.len() > 0 { | 185 | if src.len() > 0 { |
170 | return Err(ParseError::Expected("expected `:`".to_string())); | 186 | return Err(ParseError::Expected("expected `;`".to_string())); |
171 | } | 187 | } |
172 | break; | 188 | break; |
173 | } | 189 | } |
@@ -201,23 +217,23 @@ impl MacroRules { | |||
201 | 217 | ||
202 | impl Rule { | 218 | impl Rule { |
203 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { | 219 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { |
204 | let mut lhs = src | 220 | let lhs = src |
205 | .expect_subtree() | 221 | .expect_subtree() |
206 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 222 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
207 | .clone(); | ||
208 | lhs.delimiter = None; | ||
209 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; | 223 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; |
210 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; | 224 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; |
211 | let mut rhs = src | 225 | let rhs = src |
212 | .expect_subtree() | 226 | .expect_subtree() |
213 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 227 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
214 | .clone(); | 228 | |
215 | rhs.delimiter = None; | 229 | let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; |
230 | let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; | ||
231 | |||
216 | Ok(crate::Rule { lhs, rhs }) | 232 | Ok(crate::Rule { lhs, rhs }) |
217 | } | 233 | } |
218 | } | 234 | } |
219 | 235 | ||
220 | fn to_parse_error(e: ExpandError) -> ParseError { | 236 | fn to_parse_error(e: &ExpandError) -> ParseError { |
221 | let msg = match e { | 237 | let msg = match e { |
222 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | 238 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), |
223 | _ => "invalid macro definition".to_string(), | 239 | _ => "invalid macro definition".to_string(), |
@@ -225,22 +241,22 @@ fn to_parse_error(e: ExpandError) -> ParseError { | |||
225 | ParseError::Expected(msg) | 241 | ParseError::Expected(msg) |
226 | } | 242 | } |
227 | 243 | ||
228 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | 244 | fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { |
229 | for op in parse_pattern(pattern) { | 245 | for op in pattern.iter() { |
230 | let op = op.map_err(to_parse_error)?; | 246 | let op = op.as_ref().map_err(|e| to_parse_error(&e))?; |
231 | 247 | ||
232 | match op { | 248 | match op { |
233 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, | 249 | Op::Subtree(subtree) => validate(&subtree)?, |
234 | Op::Repeat { subtree, separator, .. } => { | 250 | Op::Repeat { subtree, separator, .. } => { |
235 | // Checks that no repetition which could match an empty token | 251 | // Checks that no repetition which could match an empty token |
236 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 | 252 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 |
237 | 253 | ||
238 | if separator.is_none() { | 254 | if separator.is_none() { |
239 | if parse_pattern(subtree).all(|child_op| { | 255 | if subtree.iter().all(|child_op| { |
240 | match child_op.map_err(to_parse_error) { | 256 | match child_op.as_ref().map_err(to_parse_error) { |
241 | Ok(Op::Var { kind, .. }) => { | 257 | Ok(Op::Var { kind, .. }) => { |
242 | // vis is optional | 258 | // vis is optional |
243 | if kind.map_or(false, |it| it == "vis") { | 259 | if kind.as_ref().map_or(false, |it| it == "vis") { |
244 | return true; | 260 | return true; |
245 | } | 261 | } |
246 | } | 262 | } |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index 44722c0f1..385b46601 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -2,10 +2,10 @@ | |||
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | mbe_expander::{Binding, Bindings, Fragment}, | 4 | mbe_expander::{Binding, Bindings, Fragment}, |
5 | parser::{parse_pattern, Op, RepeatKind, Separator}, | 5 | parser::{Op, RepeatKind, Separator}, |
6 | subtree_source::SubtreeTokenSource, | 6 | subtree_source::SubtreeTokenSource, |
7 | tt_iter::TtIter, | 7 | tt_iter::TtIter, |
8 | ExpandError, | 8 | ExpandError, MetaTemplate, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use super::ExpandResult; | 11 | use super::ExpandResult; |
@@ -83,7 +83,7 @@ impl Match { | |||
83 | // sense to try using it. Matching errors are added to the `Match`. It might | 83 | // sense to try using it. Matching errors are added to the `Match`. It might |
84 | // make sense to make pattern parsing a separate step? | 84 | // make sense to make pattern parsing a separate step? |
85 | 85 | ||
86 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> { | 86 | pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> { |
87 | assert!(pattern.delimiter == None); | 87 | assert!(pattern.delimiter == None); |
88 | 88 | ||
89 | let mut res = Match::default(); | 89 | let mut res = Match::default(); |
@@ -101,12 +101,12 @@ pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, | |||
101 | 101 | ||
102 | fn match_subtree( | 102 | fn match_subtree( |
103 | res: &mut Match, | 103 | res: &mut Match, |
104 | pattern: &tt::Subtree, | 104 | pattern: &MetaTemplate, |
105 | src: &mut TtIter, | 105 | src: &mut TtIter, |
106 | ) -> Result<(), ExpandError> { | 106 | ) -> Result<(), ExpandError> { |
107 | for op in parse_pattern(pattern) { | 107 | for op in pattern.iter() { |
108 | match op? { | 108 | match op.as_ref().map_err(|err| err.clone())? { |
109 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | 109 | Op::Leaf(lhs) => { |
110 | let rhs = match src.expect_leaf() { | 110 | let rhs = match src.expect_leaf() { |
111 | Ok(l) => l, | 111 | Ok(l) => l, |
112 | Err(()) => { | 112 | Err(()) => { |
@@ -132,7 +132,7 @@ fn match_subtree( | |||
132 | } | 132 | } |
133 | } | 133 | } |
134 | } | 134 | } |
135 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { | 135 | Op::Subtree(lhs) => { |
136 | let rhs = match src.expect_subtree() { | 136 | let rhs = match src.expect_subtree() { |
137 | Ok(s) => s, | 137 | Ok(s) => s, |
138 | Err(()) => { | 138 | Err(()) => { |
@@ -150,7 +150,7 @@ fn match_subtree( | |||
150 | res.add_err(err!("leftover tokens")); | 150 | res.add_err(err!("leftover tokens")); |
151 | } | 151 | } |
152 | } | 152 | } |
153 | Op::Var { name, kind } => { | 153 | Op::Var { name, kind, .. } => { |
154 | let kind = match kind { | 154 | let kind = match kind { |
155 | Some(k) => k, | 155 | Some(k) => k, |
156 | None => { | 156 | None => { |
@@ -172,7 +172,7 @@ fn match_subtree( | |||
172 | } | 172 | } |
173 | } | 173 | } |
174 | Op::Repeat { subtree, kind, separator } => { | 174 | Op::Repeat { subtree, kind, separator } => { |
175 | match_repeat(res, subtree, kind, separator, src)?; | 175 | match_repeat(res, subtree, *kind, separator, src)?; |
176 | } | 176 | } |
177 | } | 177 | } |
178 | } | 178 | } |
@@ -372,9 +372,9 @@ impl<'a> TtIter<'a> { | |||
372 | 372 | ||
373 | pub(super) fn match_repeat( | 373 | pub(super) fn match_repeat( |
374 | res: &mut Match, | 374 | res: &mut Match, |
375 | pattern: &tt::Subtree, | 375 | pattern: &MetaTemplate, |
376 | kind: RepeatKind, | 376 | kind: RepeatKind, |
377 | separator: Option<Separator>, | 377 | separator: &Option<Separator>, |
378 | src: &mut TtIter, | 378 | src: &mut TtIter, |
379 | ) -> Result<(), ExpandError> { | 379 | ) -> Result<(), ExpandError> { |
380 | // Dirty hack to make macro-expansion terminate. | 380 | // Dirty hack to make macro-expansion terminate. |
@@ -489,12 +489,12 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen | |||
489 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) | 489 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) |
490 | } | 490 | } |
491 | 491 | ||
492 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { | 492 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> { |
493 | for op in parse_pattern(pattern) { | 493 | for op in pattern.iter() { |
494 | match op? { | 494 | match op.as_ref().map_err(|e| e.clone())? { |
495 | Op::Var { name, .. } => buf.push(name.clone()), | 495 | Op::Var { name, .. } => buf.push(name.clone()), |
496 | Op::TokenTree(tt::TokenTree::Leaf(_)) => (), | 496 | Op::Leaf(_) => (), |
497 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, | 497 | Op::Subtree(subtree) => collect_vars(buf, subtree)?, |
498 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, | 498 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, |
499 | } | 499 | } |
500 | } | 500 | } |
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs index 57592dc92..57f3f104d 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/mbe_expander/transcriber.rs | |||
@@ -6,8 +6,8 @@ use syntax::SmolStr; | |||
6 | use super::ExpandResult; | 6 | use super::ExpandResult; |
7 | use crate::{ | 7 | use crate::{ |
8 | mbe_expander::{Binding, Bindings, Fragment}, | 8 | mbe_expander::{Binding, Bindings, Fragment}, |
9 | parser::{parse_template, Op, RepeatKind, Separator}, | 9 | parser::{Op, RepeatKind, Separator}, |
10 | ExpandError, | 10 | ExpandError, MetaTemplate, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | impl Bindings { | 13 | impl Bindings { |
@@ -50,7 +50,10 @@ impl Bindings { | |||
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { | 53 | pub(super) fn transcribe( |
54 | template: &MetaTemplate, | ||
55 | bindings: &Bindings, | ||
56 | ) -> ExpandResult<tt::Subtree> { | ||
54 | assert!(template.delimiter == None); | 57 | assert!(template.delimiter == None); |
55 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; | 58 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; |
56 | let mut arena: Vec<tt::TokenTree> = Vec::new(); | 59 | let mut arena: Vec<tt::TokenTree> = Vec::new(); |
@@ -76,35 +79,35 @@ struct ExpandCtx<'a> { | |||
76 | 79 | ||
77 | fn expand_subtree( | 80 | fn expand_subtree( |
78 | ctx: &mut ExpandCtx, | 81 | ctx: &mut ExpandCtx, |
79 | template: &tt::Subtree, | 82 | template: &MetaTemplate, |
80 | arena: &mut Vec<tt::TokenTree>, | 83 | arena: &mut Vec<tt::TokenTree>, |
81 | ) -> ExpandResult<tt::Subtree> { | 84 | ) -> ExpandResult<tt::Subtree> { |
82 | // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation | 85 | // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation |
83 | let start_elements = arena.len(); | 86 | let start_elements = arena.len(); |
84 | let mut err = None; | 87 | let mut err = None; |
85 | for op in parse_template(template) { | 88 | for op in template.iter() { |
86 | let op = match op { | 89 | let op = match op { |
87 | Ok(op) => op, | 90 | Ok(op) => op, |
88 | Err(e) => { | 91 | Err(e) => { |
89 | err = Some(e); | 92 | err = Some(e.clone()); |
90 | break; | 93 | break; |
91 | } | 94 | } |
92 | }; | 95 | }; |
93 | match op { | 96 | match op { |
94 | Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()), | 97 | Op::Leaf(tt) => arena.push(tt.clone().into()), |
95 | Op::TokenTree(tt::TokenTree::Subtree(tt)) => { | 98 | Op::Subtree(tt) => { |
96 | let ExpandResult { value: tt, err: e } = expand_subtree(ctx, tt, arena); | 99 | let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena); |
97 | err = err.or(e); | 100 | err = err.or(e); |
98 | arena.push(tt.into()); | 101 | arena.push(tt.into()); |
99 | } | 102 | } |
100 | Op::Var { name, .. } => { | 103 | Op::Var { name, id, .. } => { |
101 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, name); | 104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id); |
102 | err = err.or(e); | 105 | err = err.or(e); |
103 | push_fragment(arena, fragment); | 106 | push_fragment(arena, fragment); |
104 | } | 107 | } |
105 | Op::Repeat { subtree, kind, separator } => { | 108 | Op::Repeat { subtree, kind, separator } => { |
106 | let ExpandResult { value: fragment, err: e } = | 109 | let ExpandResult { value: fragment, err: e } = |
107 | expand_repeat(ctx, subtree, kind, separator, arena); | 110 | expand_repeat(ctx, subtree, *kind, separator, arena); |
108 | err = err.or(e); | 111 | err = err.or(e); |
109 | push_fragment(arena, fragment) | 112 | push_fragment(arena, fragment) |
110 | } | 113 | } |
@@ -115,12 +118,10 @@ fn expand_subtree( | |||
115 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } | 118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } |
116 | } | 119 | } |
117 | 120 | ||
118 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | 121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { |
119 | if v == "crate" { | 122 | if v == "crate" { |
120 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | 123 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. |
121 | let tt = | 124 | let tt = tt::Leaf::from(tt::Ident { text: "$crate".into(), id }).into(); |
122 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | ||
123 | .into(); | ||
124 | ExpandResult::ok(Fragment::Tokens(tt)) | 125 | ExpandResult::ok(Fragment::Tokens(tt)) |
125 | } else if !ctx.bindings.contains(v) { | 126 | } else if !ctx.bindings.contains(v) { |
126 | // Note that it is possible to have a `$var` inside a macro which is not bound. | 127 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
@@ -139,14 +140,8 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | |||
139 | let tt = tt::Subtree { | 140 | let tt = tt::Subtree { |
140 | delimiter: None, | 141 | delimiter: None, |
141 | token_trees: vec![ | 142 | token_trees: vec![ |
142 | tt::Leaf::from(tt::Punct { | 143 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(), |
143 | char: '$', | 144 | tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(), |
144 | spacing: tt::Spacing::Alone, | ||
145 | id: tt::TokenId::unspecified(), | ||
146 | }) | ||
147 | .into(), | ||
148 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) | ||
149 | .into(), | ||
150 | ], | 145 | ], |
151 | } | 146 | } |
152 | .into(); | 147 | .into(); |
@@ -161,9 +156,9 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | |||
161 | 156 | ||
162 | fn expand_repeat( | 157 | fn expand_repeat( |
163 | ctx: &mut ExpandCtx, | 158 | ctx: &mut ExpandCtx, |
164 | template: &tt::Subtree, | 159 | template: &MetaTemplate, |
165 | kind: RepeatKind, | 160 | kind: RepeatKind, |
166 | separator: Option<Separator>, | 161 | separator: &Option<Separator>, |
167 | arena: &mut Vec<tt::TokenTree>, | 162 | arena: &mut Vec<tt::TokenTree>, |
168 | ) -> ExpandResult<Fragment> { | 163 | ) -> ExpandResult<Fragment> { |
169 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 164 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index c3fdd4040..77cc739b6 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -4,16 +4,17 @@ | |||
4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
5 | use syntax::SmolStr; | 5 | use syntax::SmolStr; |
6 | 6 | ||
7 | use crate::{tt_iter::TtIter, ExpandError}; | 7 | use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; |
8 | 8 | ||
9 | #[derive(Debug)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op<'a> { | 10 | pub(crate) enum Op { |
11 | Var { name: &'a SmolStr, kind: Option<&'a SmolStr> }, | 11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, |
12 | Repeat { subtree: &'a tt::Subtree, kind: RepeatKind, separator: Option<Separator> }, | 12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | TokenTree(&'a tt::TokenTree), | 13 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | ||
14 | } | 15 | } |
15 | 16 | ||
16 | #[derive(Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
17 | pub(crate) enum RepeatKind { | 18 | pub(crate) enum RepeatKind { |
18 | ZeroOrMore, | 19 | ZeroOrMore, |
19 | OneOrMore, | 20 | OneOrMore, |
@@ -45,16 +46,12 @@ impl PartialEq for Separator { | |||
45 | } | 46 | } |
46 | } | 47 | } |
47 | 48 | ||
48 | pub(crate) fn parse_template( | 49 | pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { |
49 | template: &tt::Subtree, | 50 | parse_inner(&template, Mode::Template) |
50 | ) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | ||
51 | parse_inner(template, Mode::Template) | ||
52 | } | 51 | } |
53 | 52 | ||
54 | pub(crate) fn parse_pattern( | 53 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { |
55 | pattern: &tt::Subtree, | 54 | parse_inner(&pattern, Mode::Pattern) |
56 | ) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | ||
57 | parse_inner(pattern, Mode::Pattern) | ||
58 | } | 55 | } |
59 | 56 | ||
60 | #[derive(Clone, Copy)] | 57 | #[derive(Clone, Copy)] |
@@ -63,12 +60,13 @@ enum Mode { | |||
63 | Template, | 60 | Template, |
64 | } | 61 | } |
65 | 62 | ||
66 | fn parse_inner(src: &tt::Subtree, mode: Mode) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | 63 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { |
67 | let mut src = TtIter::new(src); | 64 | let mut src = TtIter::new(&tt); |
68 | std::iter::from_fn(move || { | 65 | std::iter::from_fn(move || { |
69 | let first = src.next()?; | 66 | let first = src.next()?; |
70 | Some(next_op(first, &mut src, mode)) | 67 | Some(next_op(first, &mut src, mode)) |
71 | }) | 68 | }) |
69 | .collect() | ||
72 | } | 70 | } |
73 | 71 | ||
74 | macro_rules! err { | 72 | macro_rules! err { |
@@ -83,37 +81,46 @@ macro_rules! bail { | |||
83 | }; | 81 | }; |
84 | } | 82 | } |
85 | 83 | ||
86 | fn next_op<'a>( | 84 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> { |
87 | first: &'a tt::TokenTree, | ||
88 | src: &mut TtIter<'a>, | ||
89 | mode: Mode, | ||
90 | ) -> Result<Op<'a>, ExpandError> { | ||
91 | let res = match first { | 85 | let res = match first { |
92 | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { | 86 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { |
93 | // Note that the '$' itself is a valid token inside macro_rules. | 87 | // Note that the '$' itself is a valid token inside macro_rules. |
94 | let second = match src.next() { | 88 | let second = match src.next() { |
95 | None => return Ok(Op::TokenTree(first)), | 89 | None => return Ok(Op::Leaf(leaf.clone())), |
96 | Some(it) => it, | 90 | Some(it) => it, |
97 | }; | 91 | }; |
98 | match second { | 92 | match second { |
99 | tt::TokenTree::Subtree(subtree) => { | 93 | tt::TokenTree::Subtree(subtree) => { |
100 | let (separator, kind) = parse_repeat(src)?; | 94 | let (separator, kind) = parse_repeat(src)?; |
95 | let delimiter = subtree.delimiter; | ||
96 | let tokens = parse_inner(&subtree, mode); | ||
97 | let subtree = MetaTemplate { tokens, delimiter }; | ||
101 | Op::Repeat { subtree, separator, kind } | 98 | Op::Repeat { subtree, separator, kind } |
102 | } | 99 | } |
103 | tt::TokenTree::Leaf(leaf) => match leaf { | 100 | tt::TokenTree::Leaf(leaf) => match leaf { |
104 | tt::Leaf::Punct(_) => { | 101 | tt::Leaf::Punct(punct) => { |
105 | return Err(ExpandError::UnexpectedToken); | 102 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); |
103 | |||
104 | if punct.char != '_' { | ||
105 | return Err(ExpandError::UnexpectedToken); | ||
106 | } | ||
107 | let name = UNDERSCORE.clone(); | ||
108 | let kind = eat_fragment_kind(src, mode)?; | ||
109 | let id = punct.id; | ||
110 | Op::Var { name, kind, id } | ||
106 | } | 111 | } |
107 | tt::Leaf::Ident(ident) => { | 112 | tt::Leaf::Ident(ident) => { |
108 | let name = &ident.text; | 113 | let name = ident.text.clone(); |
109 | let kind = eat_fragment_kind(src, mode)?; | 114 | let kind = eat_fragment_kind(src, mode)?; |
110 | Op::Var { name, kind } | 115 | let id = ident.id; |
116 | Op::Var { name, kind, id } | ||
111 | } | 117 | } |
112 | tt::Leaf::Literal(lit) => { | 118 | tt::Leaf::Literal(lit) => { |
113 | if is_boolean_literal(lit) { | 119 | if is_boolean_literal(&lit) { |
114 | let name = &lit.text; | 120 | let name = lit.text.clone(); |
115 | let kind = eat_fragment_kind(src, mode)?; | 121 | let kind = eat_fragment_kind(src, mode)?; |
116 | Op::Var { name, kind } | 122 | let id = lit.id; |
123 | Op::Var { name, kind, id } | ||
117 | } else { | 124 | } else { |
118 | bail!("bad var 2"); | 125 | bail!("bad var 2"); |
119 | } | 126 | } |
@@ -121,19 +128,22 @@ fn next_op<'a>( | |||
121 | }, | 128 | }, |
122 | } | 129 | } |
123 | } | 130 | } |
124 | tt => Op::TokenTree(tt), | 131 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), |
132 | tt::TokenTree::Subtree(subtree) => { | ||
133 | let delimiter = subtree.delimiter; | ||
134 | let tokens = parse_inner(&subtree, mode); | ||
135 | let subtree = MetaTemplate { tokens, delimiter }; | ||
136 | Op::Subtree(subtree) | ||
137 | } | ||
125 | }; | 138 | }; |
126 | Ok(res) | 139 | Ok(res) |
127 | } | 140 | } |
128 | 141 | ||
129 | fn eat_fragment_kind<'a>( | 142 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> { |
130 | src: &mut TtIter<'a>, | ||
131 | mode: Mode, | ||
132 | ) -> Result<Option<&'a SmolStr>, ExpandError> { | ||
133 | if let Mode::Pattern = mode { | 143 | if let Mode::Pattern = mode { |
134 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; | 144 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; |
135 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; | 145 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; |
136 | return Ok(Some(&ident.text)); | 146 | return Ok(Some(ident.text.clone())); |
137 | }; | 147 | }; |
138 | Ok(None) | 148 | Ok(None) |
139 | } | 149 | } |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 2bec7fd49..265c0d63d 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -313,7 +313,7 @@ trait TokenConvertor { | |||
313 | return; | 313 | return; |
314 | } | 314 | } |
315 | 315 | ||
316 | result.push(if k.is_punct() && k != UNDERSCORE { | 316 | result.push(if k.is_punct() { |
317 | assert_eq!(range.len(), TextSize::of('.')); | 317 | assert_eq!(range.len(), TextSize::of('.')); |
318 | let delim = match k { | 318 | let delim = match k { |
319 | T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), | 319 | T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), |
@@ -378,7 +378,6 @@ trait TokenConvertor { | |||
378 | let leaf: tt::Leaf = match k { | 378 | let leaf: tt::Leaf = match k { |
379 | T![true] | T![false] => make_leaf!(Ident), | 379 | T![true] | T![false] => make_leaf!(Ident), |
380 | IDENT => make_leaf!(Ident), | 380 | IDENT => make_leaf!(Ident), |
381 | UNDERSCORE => make_leaf!(Ident), | ||
382 | k if k.is_keyword() => make_leaf!(Ident), | 381 | k if k.is_keyword() => make_leaf!(Ident), |
383 | k if k.is_literal() => make_leaf!(Literal), | 382 | k if k.is_literal() => make_leaf!(Literal), |
384 | LIFETIME_IDENT => { | 383 | LIFETIME_IDENT => { |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 6cd0ed205..1d9afb4fb 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -761,6 +761,18 @@ fn test_last_expr() { | |||
761 | } | 761 | } |
762 | 762 | ||
763 | #[test] | 763 | #[test] |
764 | fn test_expr_with_attr() { | ||
765 | parse_macro( | ||
766 | r#" | ||
767 | macro_rules! m { | ||
768 | ($a:expr) => {0} | ||
769 | } | ||
770 | "#, | ||
771 | ) | ||
772 | .assert_expand_items("m!(#[allow(a)]())", "0"); | ||
773 | } | ||
774 | |||
775 | #[test] | ||
764 | fn test_ty() { | 776 | fn test_ty() { |
765 | parse_macro( | 777 | parse_macro( |
766 | r#" | 778 | r#" |
@@ -1020,6 +1032,42 @@ fn test_underscore() { | |||
1020 | } | 1032 | } |
1021 | 1033 | ||
1022 | #[test] | 1034 | #[test] |
1035 | fn test_underscore_not_greedily() { | ||
1036 | parse_macro( | ||
1037 | r#" | ||
1038 | macro_rules! q { | ||
1039 | ($($a:ident)* _) => {0}; | ||
1040 | } | ||
1041 | "#, | ||
1042 | ) | ||
1043 | // `_` overlaps with `$a:ident` but rustc matches it under the `_` token | ||
1044 | .assert_expand_items(r#"q![a b c d _]"#, r#"0"#); | ||
1045 | |||
1046 | parse_macro( | ||
1047 | r#" | ||
1048 | macro_rules! q { | ||
1049 | ($($a:expr => $b:ident)* _ => $c:expr) => {0}; | ||
1050 | } | ||
1051 | "#, | ||
1052 | ) | ||
1053 | // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr` | ||
1054 | .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#); | ||
1055 | } | ||
1056 | |||
1057 | #[test] | ||
1058 | fn test_underscore_as_type() { | ||
1059 | parse_macro( | ||
1060 | r#" | ||
1061 | macro_rules! q { | ||
1062 | ($a:ty) => {0}; | ||
1063 | } | ||
1064 | "#, | ||
1065 | ) | ||
1066 | // Underscore is a type | ||
1067 | .assert_expand_items(r#"q![_]"#, r#"0"#); | ||
1068 | } | ||
1069 | |||
1070 | #[test] | ||
1023 | fn test_vertical_bar_with_pat() { | 1071 | fn test_vertical_bar_with_pat() { |
1024 | parse_macro( | 1072 | parse_macro( |
1025 | r#" | 1073 | r#" |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index f08c8bab7..63cc90027 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -59,7 +59,7 @@ pub(crate) mod fragments { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | pub(crate) fn expr(p: &mut Parser) { | 61 | pub(crate) fn expr(p: &mut Parser) { |
62 | let _ = expressions::expr(p); | 62 | let _ = expressions::expr_with_attrs(p); |
63 | } | 63 | } |
64 | 64 | ||
65 | pub(crate) fn stmt(p: &mut Parser) { | 65 | pub(crate) fn stmt(p: &mut Parser) { |
diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs index f84ebdbc5..4cd572101 100644 --- a/crates/proc_macro_api/src/msg.rs +++ b/crates/proc_macro_api/src/msg.rs | |||
@@ -58,7 +58,13 @@ pub trait Message: Serialize + DeserializeOwned { | |||
58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { | 58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { |
59 | Ok(match read_json(inp)? { | 59 | Ok(match read_json(inp)? { |
60 | None => None, | 60 | None => None, |
61 | Some(text) => Some(serde_json::from_str(&text)?), | 61 | Some(text) => { |
62 | let mut deserializer = serde_json::Deserializer::from_str(&text); | ||
63 | // Note that some proc-macro generate very deep syntax tree | ||
64 | // We have to disable the current limit of serde here | ||
65 | deserializer.disable_recursion_limit(); | ||
66 | Some(Self::deserialize(&mut deserializer)?) | ||
67 | } | ||
62 | }) | 68 | }) |
63 | } | 69 | } |
64 | fn write(self, out: &mut impl Write) -> io::Result<()> { | 70 | fn write(self, out: &mut impl Write) -> io::Result<()> { |
diff --git a/crates/proc_macro_api/src/process.rs b/crates/proc_macro_api/src/process.rs index d68723ada..6d6ab8888 100644 --- a/crates/proc_macro_api/src/process.rs +++ b/crates/proc_macro_api/src/process.rs | |||
@@ -92,10 +92,11 @@ fn client_loop(task_rx: Receiver<Task>, mut process: Process) { | |||
92 | for Task { req, result_tx } in task_rx { | 92 | for Task { req, result_tx } in task_rx { |
93 | match send_request(&mut stdin, &mut stdout, req) { | 93 | match send_request(&mut stdin, &mut stdout, req) { |
94 | Ok(res) => result_tx.send(res).unwrap(), | 94 | Ok(res) => result_tx.send(res).unwrap(), |
95 | Err(_err) => { | 95 | Err(err) => { |
96 | log::error!( | 96 | log::error!( |
97 | "proc macro server crashed, server process state: {:?}", | 97 | "proc macro server crashed, server process state: {:?}, server request error: {:?}", |
98 | process.child.try_wait() | 98 | process.child.try_wait(), |
99 | err | ||
99 | ); | 100 | ); |
100 | let res = Response::Error(ResponseError { | 101 | let res = Response::Error(ResponseError { |
101 | code: ErrorCode::ServerErrorEnd, | 102 | code: ErrorCode::ServerErrorEnd, |
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index 503f4c101..b54aa1f3b 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -204,17 +204,18 @@ pub mod token_stream { | |||
204 | let content = subtree | 204 | let content = subtree |
205 | .token_trees | 205 | .token_trees |
206 | .iter() | 206 | .iter() |
207 | .map(|tkn| { | 207 | .fold((String::new(), true), |(last, last_to_joint), tkn| { |
208 | let s = to_text(tkn); | 208 | let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); |
209 | let mut is_joint = false; | ||
209 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { | 210 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { |
210 | if punct.spacing == tt::Spacing::Alone { | 211 | if punct.spacing == tt::Spacing::Joint { |
211 | return s + " "; | 212 | is_joint = true; |
212 | } | 213 | } |
213 | } | 214 | } |
214 | s | 215 | (s, is_joint) |
215 | }) | 216 | }) |
216 | .collect::<Vec<_>>() | 217 | .0; |
217 | .concat(); | 218 | |
218 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { | 219 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { |
219 | None => ("", ""), | 220 | None => ("", ""), |
220 | Some(tt::DelimiterKind::Brace) => ("{", "}"), | 221 | Some(tt::DelimiterKind::Brace) => ("{", "}"), |
@@ -710,4 +711,32 @@ mod tests { | |||
710 | assert_eq!(srv.character('c').text, "'c'"); | 711 | assert_eq!(srv.character('c').text, "'c'"); |
711 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); | 712 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); |
712 | } | 713 | } |
714 | |||
715 | #[test] | ||
716 | fn test_rustc_server_to_string() { | ||
717 | let s = TokenStream { | ||
718 | subtree: tt::Subtree { | ||
719 | delimiter: None, | ||
720 | token_trees: vec![ | ||
721 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
722 | text: "struct".into(), | ||
723 | id: tt::TokenId::unspecified(), | ||
724 | })), | ||
725 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
726 | text: "T".into(), | ||
727 | id: tt::TokenId::unspecified(), | ||
728 | })), | ||
729 | tt::TokenTree::Subtree(tt::Subtree { | ||
730 | delimiter: Some(tt::Delimiter { | ||
731 | id: tt::TokenId::unspecified(), | ||
732 | kind: tt::DelimiterKind::Brace, | ||
733 | }), | ||
734 | token_trees: vec![], | ||
735 | }), | ||
736 | ], | ||
737 | }, | ||
738 | }; | ||
739 | |||
740 | assert_eq!(s.to_string(), "struct T {}"); | ||
741 | } | ||
713 | } | 742 | } |
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index c55e85709..a65e42261 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -16,7 +16,7 @@ cargo_metadata = "=0.12.0" | |||
16 | serde = { version = "1.0.106", features = ["derive"] } | 16 | serde = { version = "1.0.106", features = ["derive"] } |
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | itertools = "0.9.0" | 19 | itertools = "0.10.0" |
20 | 20 | ||
21 | arena = { path = "../arena", version = "0.0.0" } | 21 | arena = { path = "../arena", version = "0.0.0" } |
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index bb3b6f2ef..1700cb8a7 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | convert::TryInto, | ||
4 | ffi::OsStr, | 5 | ffi::OsStr, |
5 | ops, | 6 | ops, |
6 | path::{Path, PathBuf}, | 7 | path::{Path, PathBuf}, |
@@ -196,8 +197,23 @@ impl CargoWorkspace { | |||
196 | if let Some(target) = target { | 197 | if let Some(target) = target { |
197 | meta.other_options(vec![String::from("--filter-platform"), target]); | 198 | meta.other_options(vec![String::from("--filter-platform"), target]); |
198 | } | 199 | } |
200 | |||
199 | let mut meta = meta.exec().with_context(|| { | 201 | let mut meta = meta.exec().with_context(|| { |
200 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) | 202 | let cwd: Option<AbsPathBuf> = |
203 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); | ||
204 | |||
205 | let workdir = cargo_toml | ||
206 | .parent() | ||
207 | .map(|p| p.to_path_buf()) | ||
208 | .or(cwd) | ||
209 | .map(|dir| dir.to_string_lossy().to_string()) | ||
210 | .unwrap_or_else(|| "<failed to get path>".into()); | ||
211 | |||
212 | format!( | ||
213 | "Failed to run `cargo metadata --manifest-path {}` in `{}`", | ||
214 | cargo_toml.display(), | ||
215 | workdir | ||
216 | ) | ||
201 | })?; | 217 | })?; |
202 | 218 | ||
203 | let mut out_dir_by_id = FxHashMap::default(); | 219 | let mut out_dir_by_id = FxHashMap::default(); |
@@ -334,6 +350,11 @@ pub(crate) fn load_extern_resources( | |||
334 | let mut cmd = Command::new(toolchain::cargo()); | 350 | let mut cmd = Command::new(toolchain::cargo()); |
335 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | 351 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
336 | 352 | ||
353 | // --all-targets includes tests, benches and examples in addition to the | ||
354 | // default lib and bins. This is an independent concept from the --targets | ||
355 | // flag below. | ||
356 | cmd.arg("--all-targets"); | ||
357 | |||
337 | if let Some(target) = &cargo_features.target { | 358 | if let Some(target) = &cargo_features.target { |
338 | cmd.args(&["--target", target]); | 359 | cmd.args(&["--target", target]); |
339 | } | 360 | } |
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index aab279223..af884eb84 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -139,6 +139,8 @@ enum EditionData { | |||
139 | Edition2015, | 139 | Edition2015, |
140 | #[serde(rename = "2018")] | 140 | #[serde(rename = "2018")] |
141 | Edition2018, | 141 | Edition2018, |
142 | #[serde(rename = "2021")] | ||
143 | Edition2021, | ||
142 | } | 144 | } |
143 | 145 | ||
144 | impl From<EditionData> for Edition { | 146 | impl From<EditionData> for Edition { |
@@ -146,6 +148,7 @@ impl From<EditionData> for Edition { | |||
146 | match data { | 148 | match data { |
147 | EditionData::Edition2015 => Edition::Edition2015, | 149 | EditionData::Edition2015 => Edition::Edition2015, |
148 | EditionData::Edition2018 => Edition::Edition2018, | 150 | EditionData::Edition2018 => Edition::Edition2018, |
151 | EditionData::Edition2021 => Edition::Edition2021, | ||
149 | } | 152 | } |
150 | } | 153 | } |
151 | } | 154 | } |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 53e70eaf7..0a63593fb 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -17,8 +17,9 @@ path = "src/bin/main.rs" | |||
17 | [dependencies] | 17 | [dependencies] |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | crossbeam-channel = "0.5.0" | 19 | crossbeam-channel = "0.5.0" |
20 | dissimilar = "1.0.2" | ||
20 | env_logger = { version = "0.8.1", default-features = false } | 21 | env_logger = { version = "0.8.1", default-features = false } |
21 | itertools = "0.9.0" | 22 | itertools = "0.10.0" |
22 | jod-thread = "0.1.0" | 23 | jod-thread = "0.1.0" |
23 | log = "0.4.8" | 24 | log = "0.4.8" |
24 | lsp-types = { version = "0.86.0", features = ["proposed"] } | 25 | lsp-types = { version = "0.86.0", features = ["proposed"] } |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index a23fb7a33..9445aec07 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -161,11 +161,12 @@ impl AnalysisStatsCmd { | |||
161 | } | 161 | } |
162 | let mut msg = format!("processing: {}", full_name); | 162 | let mut msg = format!("processing: {}", full_name); |
163 | if verbosity.is_verbose() { | 163 | if verbosity.is_verbose() { |
164 | let src = f.source(db); | 164 | if let Some(src) = f.source(db) { |
165 | let original_file = src.file_id.original_file(db); | 165 | let original_file = src.file_id.original_file(db); |
166 | let path = vfs.file_path(original_file); | 166 | let path = vfs.file_path(original_file); |
167 | let syntax_range = src.value.syntax().text_range(); | 167 | let syntax_range = src.value.syntax().text_range(); |
168 | format_to!(msg, " ({} {:?})", path, syntax_range); | 168 | format_to!(msg, " ({} {:?})", path, syntax_range); |
169 | } | ||
169 | } | 170 | } |
170 | if verbosity.is_spammy() { | 171 | if verbosity.is_spammy() { |
171 | bar.println(msg.to_string()); | 172 | bar.println(msg.to_string()); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1db5b4e7d..685a9fdf0 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -679,7 +679,7 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json: | |||
679 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { | 679 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { |
680 | fn key(f: &str) -> &str { | 680 | fn key(f: &str) -> &str { |
681 | f.splitn(2, "_").next().unwrap() | 681 | f.splitn(2, "_").next().unwrap() |
682 | }; | 682 | } |
683 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); | 683 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); |
684 | } | 684 | } |
685 | 685 | ||
diff --git a/crates/rust-analyzer/src/diff.rs b/crates/rust-analyzer/src/diff.rs new file mode 100644 index 000000000..231be5807 --- /dev/null +++ b/crates/rust-analyzer/src/diff.rs | |||
@@ -0,0 +1,53 @@ | |||
1 | //! Generate minimal `TextEdit`s from different text versions | ||
2 | use dissimilar::Chunk; | ||
3 | use ide::{TextEdit, TextRange, TextSize}; | ||
4 | |||
5 | pub(crate) fn diff(left: &str, right: &str) -> TextEdit { | ||
6 | let chunks = dissimilar::diff(left, right); | ||
7 | textedit_from_chunks(chunks) | ||
8 | } | ||
9 | |||
10 | fn textedit_from_chunks(chunks: Vec<dissimilar::Chunk>) -> TextEdit { | ||
11 | let mut builder = TextEdit::builder(); | ||
12 | let mut pos = TextSize::default(); | ||
13 | |||
14 | let mut chunks = chunks.into_iter().peekable(); | ||
15 | while let Some(chunk) = chunks.next() { | ||
16 | if let (Chunk::Delete(deleted), Some(&Chunk::Insert(inserted))) = (chunk, chunks.peek()) { | ||
17 | chunks.next().unwrap(); | ||
18 | let deleted_len = TextSize::of(deleted); | ||
19 | builder.replace(TextRange::at(pos, deleted_len), inserted.into()); | ||
20 | pos += deleted_len; | ||
21 | continue; | ||
22 | } | ||
23 | |||
24 | match chunk { | ||
25 | Chunk::Equal(text) => { | ||
26 | pos += TextSize::of(text); | ||
27 | } | ||
28 | Chunk::Delete(deleted) => { | ||
29 | let deleted_len = TextSize::of(deleted); | ||
30 | builder.delete(TextRange::at(pos, deleted_len)); | ||
31 | pos += deleted_len; | ||
32 | } | ||
33 | Chunk::Insert(inserted) => { | ||
34 | builder.insert(pos, inserted.into()); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | builder.finish() | ||
39 | } | ||
40 | |||
41 | #[cfg(test)] | ||
42 | mod tests { | ||
43 | use super::*; | ||
44 | |||
45 | #[test] | ||
46 | fn diff_applies() { | ||
47 | let mut original = String::from("fn foo(a:u32){\n}"); | ||
48 | let result = "fn foo(a: u32) {}"; | ||
49 | let edit = diff(&original, result); | ||
50 | edit.apply(&mut original); | ||
51 | assert_eq!(original, result); | ||
52 | } | ||
53 | } | ||
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 85f1f81ad..dd486070b 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -31,6 +31,7 @@ use serde_json::to_value; | |||
31 | use stdx::{format_to, split_once}; | 31 | use stdx::{format_to, split_once}; |
32 | use syntax::{algo, ast, AstNode, TextRange, TextSize}; | 32 | use syntax::{algo, ast, AstNode, TextRange, TextSize}; |
33 | 33 | ||
34 | use crate::diff::diff; | ||
34 | use crate::{ | 35 | use crate::{ |
35 | cargo_target_spec::CargoTargetSpec, | 36 | cargo_target_spec::CargoTargetSpec, |
36 | config::RustfmtConfig, | 37 | config::RustfmtConfig, |
@@ -691,7 +692,7 @@ pub(crate) fn handle_completion_resolve( | |||
691 | &snap.config.completion, | 692 | &snap.config.completion, |
692 | FilePosition { file_id, offset }, | 693 | FilePosition { file_id, offset }, |
693 | &resolve_data.full_import_path, | 694 | &resolve_data.full_import_path, |
694 | &resolve_data.imported_name, | 695 | resolve_data.imported_name, |
695 | )? | 696 | )? |
696 | .into_iter() | 697 | .into_iter() |
697 | .flat_map(|edit| { | 698 | .flat_map(|edit| { |
@@ -850,7 +851,7 @@ pub(crate) fn handle_formatting( | |||
850 | let crate_ids = snap.analysis.crate_for(file_id)?; | 851 | let crate_ids = snap.analysis.crate_for(file_id)?; |
851 | 852 | ||
852 | let file_line_index = snap.analysis.file_line_index(file_id)?; | 853 | let file_line_index = snap.analysis.file_line_index(file_id)?; |
853 | let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); | 854 | let file_line_endings = snap.file_line_endings(file_id); |
854 | 855 | ||
855 | let mut rustfmt = match &snap.config.rustfmt { | 856 | let mut rustfmt = match &snap.config.rustfmt { |
856 | RustfmtConfig::Rustfmt { extra_args } => { | 857 | RustfmtConfig::Rustfmt { extra_args } => { |
@@ -871,16 +872,18 @@ pub(crate) fn handle_formatting( | |||
871 | } | 872 | } |
872 | }; | 873 | }; |
873 | 874 | ||
874 | let mut rustfmt = rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; | 875 | let mut rustfmt = |
876 | rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?; | ||
875 | 877 | ||
876 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; | 878 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; |
877 | 879 | ||
878 | let output = rustfmt.wait_with_output()?; | 880 | let output = rustfmt.wait_with_output()?; |
879 | let captured_stdout = String::from_utf8(output.stdout)?; | 881 | let captured_stdout = String::from_utf8(output.stdout)?; |
882 | let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default(); | ||
880 | 883 | ||
881 | if !output.status.success() { | 884 | if !output.status.success() { |
882 | match output.status.code() { | 885 | match output.status.code() { |
883 | Some(1) => { | 886 | Some(1) if !captured_stderr.contains("not installed") => { |
884 | // While `rustfmt` doesn't have a specific exit code for parse errors this is the | 887 | // While `rustfmt` doesn't have a specific exit code for parse errors this is the |
885 | // likely cause exiting with 1. Most Language Servers swallow parse errors on | 888 | // likely cause exiting with 1. Most Language Servers swallow parse errors on |
886 | // formatting because otherwise an error is surfaced to the user on top of the | 889 | // formatting because otherwise an error is surfaced to the user on top of the |
@@ -896,8 +899,9 @@ pub(crate) fn handle_formatting( | |||
896 | format!( | 899 | format!( |
897 | r#"rustfmt exited with: | 900 | r#"rustfmt exited with: |
898 | Status: {} | 901 | Status: {} |
899 | stdout: {}"#, | 902 | stdout: {} |
900 | output.status, captured_stdout, | 903 | stderr: {}"#, |
904 | output.status, captured_stdout, captured_stderr, | ||
901 | ), | 905 | ), |
902 | ) | 906 | ) |
903 | .into()); | 907 | .into()); |
@@ -909,10 +913,11 @@ pub(crate) fn handle_formatting( | |||
909 | // The document is already formatted correctly -- no edits needed. | 913 | // The document is already formatted correctly -- no edits needed. |
910 | Ok(None) | 914 | Ok(None) |
911 | } else { | 915 | } else { |
912 | Ok(Some(vec![lsp_types::TextEdit { | 916 | Ok(Some(to_proto::text_edit_vec( |
913 | range: Range::new(Position::new(0, 0), end_position), | 917 | &file_line_index, |
914 | new_text: captured_stdout, | 918 | file_line_endings, |
915 | }])) | 919 | diff(&file, &captured_stdout), |
920 | ))) | ||
916 | } | 921 | } |
917 | } | 922 | } |
918 | 923 | ||
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index d538ad69a..c9494e300 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -34,6 +34,7 @@ mod request_metrics; | |||
34 | mod lsp_utils; | 34 | mod lsp_utils; |
35 | mod thread_pool; | 35 | mod thread_pool; |
36 | mod document; | 36 | mod document; |
37 | mod diff; | ||
37 | pub mod lsp_ext; | 38 | pub mod lsp_ext; |
38 | pub mod config; | 39 | pub mod config; |
39 | 40 | ||
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs index 968ea55f0..a49a58c00 100644 --- a/crates/rust-analyzer/src/markdown.rs +++ b/crates/rust-analyzer/src/markdown.rs | |||
@@ -1,8 +1,17 @@ | |||
1 | //! Transforms markdown | 1 | //! Transforms markdown |
2 | 2 | ||
3 | const RUSTDOC_FENCE: &str = "```"; | 3 | const RUSTDOC_FENCE: &str = "```"; |
4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = | 4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = &[ |
5 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | 5 | "", |
6 | "rust", | ||
7 | "should_panic", | ||
8 | "ignore", | ||
9 | "no_run", | ||
10 | "compile_fail", | ||
11 | "edition2015", | ||
12 | "edition2018", | ||
13 | "edition2021", | ||
14 | ]; | ||
6 | 15 | ||
7 | pub(crate) fn format_docs(src: &str) -> String { | 16 | pub(crate) fn format_docs(src: &str) -> String { |
8 | let mut processed_lines = Vec::new(); | 17 | let mut processed_lines = Vec::new(); |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index c2f6a655d..5c4366f16 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -44,6 +44,7 @@ define_semantic_token_types![ | |||
44 | (ESCAPE_SEQUENCE, "escapeSequence"), | 44 | (ESCAPE_SEQUENCE, "escapeSequence"), |
45 | (FORMAT_SPECIFIER, "formatSpecifier"), | 45 | (FORMAT_SPECIFIER, "formatSpecifier"), |
46 | (GENERIC, "generic"), | 46 | (GENERIC, "generic"), |
47 | (CONST_PARAMETER, "constParameter"), | ||
47 | (LIFETIME, "lifetime"), | 48 | (LIFETIME, "lifetime"), |
48 | (LABEL, "label"), | 49 | (LABEL, "label"), |
49 | (PUNCTUATION, "punctuation"), | 50 | (PUNCTUATION, "punctuation"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1a38e79f0..999b18351 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -42,6 +42,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { | |||
42 | SymbolKind::Field => lsp_types::SymbolKind::Field, | 42 | SymbolKind::Field => lsp_types::SymbolKind::Field, |
43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, | 43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, |
44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, | 44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, |
45 | SymbolKind::ConstParam => lsp_types::SymbolKind::Constant, | ||
45 | SymbolKind::Impl => lsp_types::SymbolKind::Object, | 46 | SymbolKind::Impl => lsp_types::SymbolKind::Object, |
46 | SymbolKind::Local | 47 | SymbolKind::Local |
47 | | SymbolKind::SelfParam | 48 | | SymbolKind::SelfParam |
@@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers( | |||
378 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, | 379 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, |
379 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, | 380 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, |
380 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, | 381 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, |
382 | SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, | ||
381 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, | 383 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, |
382 | SymbolKind::Label => semantic_tokens::LABEL, | 384 | SymbolKind::Label => semantic_tokens::LABEL, |
383 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, | 385 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index e51eb2626..84db0856d 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs | |||
@@ -190,15 +190,10 @@ pub use std::collections::HashMap; | |||
190 | }, | 190 | }, |
191 | json!([ | 191 | json!([ |
192 | { | 192 | { |
193 | "newText": r#"mod bar; | 193 | "newText": "", |
194 | |||
195 | fn main() {} | ||
196 | |||
197 | pub use std::collections::HashMap; | ||
198 | "#, | ||
199 | "range": { | 194 | "range": { |
200 | "end": { "character": 0, "line": 6 }, | 195 | "end": { "character": 0, "line": 3 }, |
201 | "start": { "character": 0, "line": 0 } | 196 | "start": { "character": 11, "line": 2 } |
202 | } | 197 | } |
203 | } | 198 | } |
204 | ]), | 199 | ]), |
@@ -248,17 +243,17 @@ pub use std::collections::HashMap; | |||
248 | }, | 243 | }, |
249 | json!([ | 244 | json!([ |
250 | { | 245 | { |
251 | "newText": r#"mod bar; | 246 | "newText": "", |
252 | 247 | "range": { | |
253 | async fn test() {} | 248 | "end": { "character": 0, "line": 3 }, |
254 | 249 | "start": { "character": 17, "line": 2 } | |
255 | fn main() {} | 250 | } |
256 | 251 | }, | |
257 | pub use std::collections::HashMap; | 252 | { |
258 | "#, | 253 | "newText": "", |
259 | "range": { | 254 | "range": { |
260 | "end": { "character": 0, "line": 9 }, | 255 | "end": { "character": 0, "line": 6 }, |
261 | "start": { "character": 0, "line": 0 } | 256 | "start": { "character": 11, "line": 5 } |
262 | } | 257 | } |
263 | } | 258 | } |
264 | ]), | 259 | ]), |
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml index 98ed25fb6..339eda86a 100644 --- a/crates/ssr/Cargo.toml +++ b/crates/ssr/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | itertools = "0.9.0" | 15 | itertools = "0.10.0" |
16 | 16 | ||
17 | text_edit = { path = "../text_edit", version = "0.0.0" } | 17 | text_edit = { path = "../text_edit", version = "0.0.0" } |
18 | syntax = { path = "../syntax", version = "0.0.0" } | 18 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index 99b187311..6cf831431 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs | |||
@@ -473,7 +473,9 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
473 | } | 473 | } |
474 | SyntaxElement::Node(n) => { | 474 | SyntaxElement::Node(n) => { |
475 | if let Some(first_token) = n.first_token() { | 475 | if let Some(first_token) = n.first_token() { |
476 | if Some(first_token.to_string()) == next_pattern_token { | 476 | if Some(first_token.text().as_str()) |
477 | == next_pattern_token.as_deref() | ||
478 | { | ||
477 | if let Some(SyntaxElement::Node(p)) = pattern.next() { | 479 | if let Some(SyntaxElement::Node(p)) = pattern.next() { |
478 | // We have a subtree that starts with the next token in our pattern. | 480 | // We have a subtree that starts with the next token in our pattern. |
479 | self.attempt_match_token_tree(phase, &p, &n)?; | 481 | self.attempt_match_token_tree(phase, &p, &n)?; |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 21015591c..5d8389ade 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -11,7 +11,7 @@ edition = "2018" | |||
11 | doctest = false | 11 | doctest = false |
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 77233ab31..824ebf41c 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -220,7 +220,7 @@ impl ast::RecordExprFieldList { | |||
220 | InsertPosition::After($anchor.syntax().clone().into()) | 220 | InsertPosition::After($anchor.syntax().clone().into()) |
221 | } | 221 | } |
222 | }; | 222 | }; |
223 | }; | 223 | } |
224 | 224 | ||
225 | let position = match position { | 225 | let position = match position { |
226 | InsertPosition::First => after_l_curly!(), | 226 | InsertPosition::First => after_l_curly!(), |
@@ -533,7 +533,7 @@ impl ast::GenericParamList { | |||
533 | InsertPosition::After($anchor.syntax().clone().into()) | 533 | InsertPosition::After($anchor.syntax().clone().into()) |
534 | } | 534 | } |
535 | }; | 535 | }; |
536 | }; | 536 | } |
537 | 537 | ||
538 | let position = match self.generic_params().last() { | 538 | let position = match self.generic_params().last() { |
539 | Some(it) => after_field!(it), | 539 | Some(it) => after_field!(it), |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index c45cb514a..2aa472fb4 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -193,6 +193,14 @@ impl ast::UseTreeList { | |||
193 | .and_then(ast::UseTree::cast) | 193 | .and_then(ast::UseTree::cast) |
194 | .expect("UseTreeLists are always nested in UseTrees") | 194 | .expect("UseTreeLists are always nested in UseTrees") |
195 | } | 195 | } |
196 | |||
197 | pub fn has_inner_comment(&self) -> bool { | ||
198 | self.syntax() | ||
199 | .children_with_tokens() | ||
200 | .filter_map(|it| it.into_token()) | ||
201 | .find_map(ast::Comment::cast) | ||
202 | .is_some() | ||
203 | } | ||
196 | } | 204 | } |
197 | 205 | ||
198 | impl ast::Impl { | 206 | impl ast::Impl { |