diff options
Diffstat (limited to 'crates/ide')
45 files changed, 2810 insertions, 2552 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 3c2d39f5d..e8999a7f3 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -5,7 +5,7 @@ use indexmap::IndexMap; | |||
5 | use hir::Semantics; | 5 | use hir::Semantics; |
6 | use ide_db::call_info::FnCallNode; | 6 | use ide_db::call_info::FnCallNode; |
7 | use ide_db::RootDatabase; | 7 | use ide_db::RootDatabase; |
8 | use syntax::{ast, match_ast, AstNode, TextRange}; | 8 | use syntax::{ast, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, | 11 | display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, |
@@ -47,28 +47,23 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
47 | 47 | ||
48 | let mut calls = CallLocations::default(); | 48 | let mut calls = CallLocations::default(); |
49 | 49 | ||
50 | for reference in refs.info.references() { | 50 | for (&file_id, references) in refs.info.references().iter() { |
51 | let file_id = reference.file_range.file_id; | ||
52 | let file = sema.parse(file_id); | 51 | let file = sema.parse(file_id); |
53 | let file = file.syntax(); | 52 | let file = file.syntax(); |
54 | let token = file.token_at_offset(reference.file_range.range.start()).next()?; | 53 | for reference in references { |
55 | let token = sema.descend_into_macros(token); | 54 | let token = file.token_at_offset(reference.range.start()).next()?; |
56 | let syntax = token.parent(); | 55 | let token = sema.descend_into_macros(token); |
57 | 56 | let syntax = token.parent(); | |
58 | // This target is the containing function | 57 | |
59 | if let Some(nav) = syntax.ancestors().find_map(|node| { | 58 | // This target is the containing function |
60 | match_ast! { | 59 | if let Some(nav) = syntax.ancestors().find_map(|node| { |
61 | match node { | 60 | let fn_ = ast::Fn::cast(node)?; |
62 | ast::Fn(it) => { | 61 | let def = sema.to_def(&fn_)?; |
63 | let def = sema.to_def(&it)?; | 62 | def.try_to_nav(sema.db) |
64 | def.try_to_nav(sema.db) | 63 | }) { |
65 | }, | 64 | let relative_range = reference.range; |
66 | _ => None, | 65 | calls.add(&nav, relative_range); |
67 | } | ||
68 | } | 66 | } |
69 | }) { | ||
70 | let relative_range = reference.file_range.range; | ||
71 | calls.add(&nav, relative_range); | ||
72 | } | 67 | } |
73 | } | 68 | } |
74 | 69 | ||
@@ -91,17 +86,12 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
91 | .filter_map(|node| FnCallNode::with_node_exact(&node)) | 86 | .filter_map(|node| FnCallNode::with_node_exact(&node)) |
92 | .filter_map(|call_node| { | 87 | .filter_map(|call_node| { |
93 | let name_ref = call_node.name_ref()?; | 88 | let name_ref = call_node.name_ref()?; |
94 | 89 | let func_target = match call_node { | |
95 | if let Some(func_target) = match &call_node { | ||
96 | FnCallNode::CallExpr(expr) => { | 90 | FnCallNode::CallExpr(expr) => { |
97 | //FIXME: Type::as_callable is broken | 91 | //FIXME: Type::as_callable is broken |
98 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; | 92 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; |
99 | match callable.kind() { | 93 | match callable.kind() { |
100 | hir::CallableKind::Function(it) => { | 94 | hir::CallableKind::Function(it) => it.try_to_nav(db), |
101 | let fn_def: hir::Function = it.into(); | ||
102 | let nav = fn_def.try_to_nav(db)?; | ||
103 | Some(nav) | ||
104 | } | ||
105 | _ => None, | 95 | _ => None, |
106 | } | 96 | } |
107 | } | 97 | } |
@@ -109,11 +99,8 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
109 | let function = sema.resolve_method_call(&expr)?; | 99 | let function = sema.resolve_method_call(&expr)?; |
110 | function.try_to_nav(db) | 100 | function.try_to_nav(db) |
111 | } | 101 | } |
112 | } { | 102 | }?; |
113 | Some((func_target, name_ref.syntax().text_range())) | 103 | Some((func_target, name_ref.syntax().text_range())) |
114 | } else { | ||
115 | None | ||
116 | } | ||
117 | }) | 104 | }) |
118 | .for_each(|(nav, range)| calls.add(&nav, range)); | 105 | .for_each(|(nav, range)| calls.add(&nav, range)); |
119 | 106 | ||
@@ -178,7 +165,7 @@ mod tests { | |||
178 | //- /lib.rs | 165 | //- /lib.rs |
179 | fn callee() {} | 166 | fn callee() {} |
180 | fn caller() { | 167 | fn caller() { |
181 | call<|>ee(); | 168 | call$0ee(); |
182 | } | 169 | } |
183 | "#, | 170 | "#, |
184 | "callee Function FileId(0) 0..14 3..9", | 171 | "callee Function FileId(0) 0..14 3..9", |
@@ -192,7 +179,7 @@ fn caller() { | |||
192 | check_hierarchy( | 179 | check_hierarchy( |
193 | r#" | 180 | r#" |
194 | //- /lib.rs | 181 | //- /lib.rs |
195 | fn call<|>ee() {} | 182 | fn call$0ee() {} |
196 | fn caller() { | 183 | fn caller() { |
197 | callee(); | 184 | callee(); |
198 | } | 185 | } |
@@ -210,7 +197,7 @@ fn caller() { | |||
210 | //- /lib.rs | 197 | //- /lib.rs |
211 | fn callee() {} | 198 | fn callee() {} |
212 | fn caller() { | 199 | fn caller() { |
213 | call<|>ee(); | 200 | call$0ee(); |
214 | callee(); | 201 | callee(); |
215 | } | 202 | } |
216 | "#, | 203 | "#, |
@@ -227,7 +214,7 @@ fn caller() { | |||
227 | //- /lib.rs | 214 | //- /lib.rs |
228 | fn callee() {} | 215 | fn callee() {} |
229 | fn caller1() { | 216 | fn caller1() { |
230 | call<|>ee(); | 217 | call$0ee(); |
231 | } | 218 | } |
232 | 219 | ||
233 | fn caller2() { | 220 | fn caller2() { |
@@ -250,7 +237,7 @@ fn caller2() { | |||
250 | //- /lib.rs cfg:test | 237 | //- /lib.rs cfg:test |
251 | fn callee() {} | 238 | fn callee() {} |
252 | fn caller1() { | 239 | fn caller1() { |
253 | call<|>ee(); | 240 | call$0ee(); |
254 | } | 241 | } |
255 | 242 | ||
256 | #[cfg(test)] | 243 | #[cfg(test)] |
@@ -281,7 +268,7 @@ mod foo; | |||
281 | use foo::callee; | 268 | use foo::callee; |
282 | 269 | ||
283 | fn caller() { | 270 | fn caller() { |
284 | call<|>ee(); | 271 | call$0ee(); |
285 | } | 272 | } |
286 | 273 | ||
287 | //- /foo/mod.rs | 274 | //- /foo/mod.rs |
@@ -299,7 +286,7 @@ pub fn callee() {} | |||
299 | r#" | 286 | r#" |
300 | //- /lib.rs | 287 | //- /lib.rs |
301 | fn callee() {} | 288 | fn callee() {} |
302 | fn call<|>er() { | 289 | fn call$0er() { |
303 | callee(); | 290 | callee(); |
304 | callee(); | 291 | callee(); |
305 | } | 292 | } |
@@ -318,7 +305,7 @@ fn call<|>er() { | |||
318 | mod foo; | 305 | mod foo; |
319 | use foo::callee; | 306 | use foo::callee; |
320 | 307 | ||
321 | fn call<|>er() { | 308 | fn call$0er() { |
322 | callee(); | 309 | callee(); |
323 | } | 310 | } |
324 | 311 | ||
@@ -337,7 +324,7 @@ pub fn callee() {} | |||
337 | r#" | 324 | r#" |
338 | //- /lib.rs | 325 | //- /lib.rs |
339 | fn caller1() { | 326 | fn caller1() { |
340 | call<|>er2(); | 327 | call$0er2(); |
341 | } | 328 | } |
342 | 329 | ||
343 | fn caller2() { | 330 | fn caller2() { |
@@ -365,7 +352,7 @@ fn a() { | |||
365 | fn b() {} | 352 | fn b() {} |
366 | 353 | ||
367 | fn main() { | 354 | fn main() { |
368 | a<|>() | 355 | a$0() |
369 | } | 356 | } |
370 | "#, | 357 | "#, |
371 | "a Function FileId(0) 0..18 3..4", | 358 | "a Function FileId(0) 0..18 3..4", |
@@ -376,7 +363,7 @@ fn main() { | |||
376 | check_hierarchy( | 363 | check_hierarchy( |
377 | r#" | 364 | r#" |
378 | fn a() { | 365 | fn a() { |
379 | b<|>() | 366 | b$0() |
380 | } | 367 | } |
381 | 368 | ||
382 | fn b() {} | 369 | fn b() {} |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 79d126ff2..b35bc2bae 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -13,17 +13,16 @@ use hir::{ | |||
13 | diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, | 13 | diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, |
14 | Semantics, | 14 | Semantics, |
15 | }; | 15 | }; |
16 | use ide_db::base_db::SourceDatabase; | 16 | use ide_db::{base_db::SourceDatabase, RootDatabase}; |
17 | use ide_db::RootDatabase; | ||
18 | use itertools::Itertools; | 17 | use itertools::Itertools; |
19 | use rustc_hash::FxHashSet; | 18 | use rustc_hash::FxHashSet; |
20 | use syntax::{ | 19 | use syntax::{ |
21 | ast::{self, AstNode}, | 20 | ast::{self, AstNode}, |
22 | SyntaxNode, TextRange, T, | 21 | SyntaxNode, TextRange, |
23 | }; | 22 | }; |
24 | use text_edit::TextEdit; | 23 | use text_edit::TextEdit; |
25 | 24 | ||
26 | use crate::{FileId, Label, SourceChange, SourceFileEdit}; | 25 | use crate::{FileId, Label, SourceChange}; |
27 | 26 | ||
28 | use self::fixes::DiagnosticWithFix; | 27 | use self::fixes::DiagnosticWithFix; |
29 | 28 | ||
@@ -125,7 +124,7 @@ pub(crate) fn diagnostics( | |||
125 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 124 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
126 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 125 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
127 | }) | 126 | }) |
128 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | 127 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { |
129 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 128 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
130 | }) | 129 | }) |
131 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 130 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
@@ -220,7 +219,7 @@ fn check_unnecessary_braces_in_use_statement( | |||
220 | Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) | 219 | Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) |
221 | .with_fix(Some(Fix::new( | 220 | .with_fix(Some(Fix::new( |
222 | "Remove unnecessary braces", | 221 | "Remove unnecessary braces", |
223 | SourceFileEdit { file_id, edit }.into(), | 222 | SourceChange::from_text_edit(file_id, edit), |
224 | use_range, | 223 | use_range, |
225 | ))), | 224 | ))), |
226 | ); | 225 | ); |
@@ -233,7 +232,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
233 | single_use_tree: &ast::UseTree, | 232 | single_use_tree: &ast::UseTree, |
234 | ) -> Option<TextEdit> { | 233 | ) -> Option<TextEdit> { |
235 | let use_tree_list_node = single_use_tree.syntax().parent()?; | 234 | let use_tree_list_node = single_use_tree.syntax().parent()?; |
236 | if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { | 235 | if single_use_tree.path()?.segment()?.self_token().is_some() { |
237 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | 236 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); |
238 | let end = use_tree_list_node.text_range().end(); | 237 | let end = use_tree_list_node.text_range().end(); |
239 | return Some(TextEdit::delete(TextRange::new(start, end))); | 238 | return Some(TextEdit::delete(TextRange::new(start, end))); |
@@ -265,13 +264,11 @@ mod tests { | |||
265 | .unwrap(); | 264 | .unwrap(); |
266 | let fix = diagnostic.fix.unwrap(); | 265 | let fix = diagnostic.fix.unwrap(); |
267 | let actual = { | 266 | let actual = { |
268 | let file_id = fix.source_change.source_file_edits.first().unwrap().file_id; | 267 | let file_id = *fix.source_change.source_file_edits.keys().next().unwrap(); |
269 | let mut actual = analysis.file_text(file_id).unwrap().to_string(); | 268 | let mut actual = analysis.file_text(file_id).unwrap().to_string(); |
270 | 269 | ||
271 | // Go from the last one to the first one, so that ranges won't be affected by previous edits. | 270 | for edit in fix.source_change.source_file_edits.values() { |
272 | // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/4901#issuecomment-644675309 | 271 | edit.apply(&mut actual); |
273 | for edit in fix.source_change.source_file_edits.iter().rev() { | ||
274 | edit.edit.apply(&mut actual); | ||
275 | } | 272 | } |
276 | actual | 273 | actual |
277 | }; | 274 | }; |
@@ -305,6 +302,40 @@ mod tests { | |||
305 | } | 302 | } |
306 | 303 | ||
307 | #[test] | 304 | #[test] |
305 | fn test_wrap_return_type_option() { | ||
306 | check_fix( | ||
307 | r#" | ||
308 | //- /main.rs crate:main deps:core | ||
309 | use core::option::Option::{self, Some, None}; | ||
310 | |||
311 | fn div(x: i32, y: i32) -> Option<i32> { | ||
312 | if y == 0 { | ||
313 | return None; | ||
314 | } | ||
315 | x / y$0 | ||
316 | } | ||
317 | //- /core/lib.rs crate:core | ||
318 | pub mod result { | ||
319 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
320 | } | ||
321 | pub mod option { | ||
322 | pub enum Option<T> { Some(T), None } | ||
323 | } | ||
324 | "#, | ||
325 | r#" | ||
326 | use core::option::Option::{self, Some, None}; | ||
327 | |||
328 | fn div(x: i32, y: i32) -> Option<i32> { | ||
329 | if y == 0 { | ||
330 | return None; | ||
331 | } | ||
332 | Some(x / y) | ||
333 | } | ||
334 | "#, | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
308 | fn test_wrap_return_type() { | 339 | fn test_wrap_return_type() { |
309 | check_fix( | 340 | check_fix( |
310 | r#" | 341 | r#" |
@@ -315,12 +346,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> { | |||
315 | if y == 0 { | 346 | if y == 0 { |
316 | return Err(()); | 347 | return Err(()); |
317 | } | 348 | } |
318 | x / y<|> | 349 | x / y$0 |
319 | } | 350 | } |
320 | //- /core/lib.rs crate:core | 351 | //- /core/lib.rs crate:core |
321 | pub mod result { | 352 | pub mod result { |
322 | pub enum Result<T, E> { Ok(T), Err(E) } | 353 | pub enum Result<T, E> { Ok(T), Err(E) } |
323 | } | 354 | } |
355 | pub mod option { | ||
356 | pub enum Option<T> { Some(T), None } | ||
357 | } | ||
324 | "#, | 358 | "#, |
325 | r#" | 359 | r#" |
326 | use core::result::Result::{self, Ok, Err}; | 360 | use core::result::Result::{self, Ok, Err}; |
@@ -346,12 +380,15 @@ fn div<T>(x: T) -> Result<T, i32> { | |||
346 | if x == 0 { | 380 | if x == 0 { |
347 | return Err(7); | 381 | return Err(7); |
348 | } | 382 | } |
349 | <|>x | 383 | $0x |
350 | } | 384 | } |
351 | //- /core/lib.rs crate:core | 385 | //- /core/lib.rs crate:core |
352 | pub mod result { | 386 | pub mod result { |
353 | pub enum Result<T, E> { Ok(T), Err(E) } | 387 | pub enum Result<T, E> { Ok(T), Err(E) } |
354 | } | 388 | } |
389 | pub mod option { | ||
390 | pub enum Option<T> { Some(T), None } | ||
391 | } | ||
355 | "#, | 392 | "#, |
356 | r#" | 393 | r#" |
357 | use core::result::Result::{self, Ok, Err}; | 394 | use core::result::Result::{self, Ok, Err}; |
@@ -379,12 +416,15 @@ fn div(x: i32, y: i32) -> MyResult<i32> { | |||
379 | if y == 0 { | 416 | if y == 0 { |
380 | return Err(()); | 417 | return Err(()); |
381 | } | 418 | } |
382 | x <|>/ y | 419 | x $0/ y |
383 | } | 420 | } |
384 | //- /core/lib.rs crate:core | 421 | //- /core/lib.rs crate:core |
385 | pub mod result { | 422 | pub mod result { |
386 | pub enum Result<T, E> { Ok(T), Err(E) } | 423 | pub enum Result<T, E> { Ok(T), Err(E) } |
387 | } | 424 | } |
425 | pub mod option { | ||
426 | pub enum Option<T> { Some(T), None } | ||
427 | } | ||
388 | "#, | 428 | "#, |
389 | r#" | 429 | r#" |
390 | use core::result::Result::{self, Ok, Err}; | 430 | use core::result::Result::{self, Ok, Err}; |
@@ -414,12 +454,15 @@ fn foo() -> Result<(), i32> { 0 } | |||
414 | pub mod result { | 454 | pub mod result { |
415 | pub enum Result<T, E> { Ok(T), Err(E) } | 455 | pub enum Result<T, E> { Ok(T), Err(E) } |
416 | } | 456 | } |
457 | pub mod option { | ||
458 | pub enum Option<T> { Some(T), None } | ||
459 | } | ||
417 | "#, | 460 | "#, |
418 | ); | 461 | ); |
419 | } | 462 | } |
420 | 463 | ||
421 | #[test] | 464 | #[test] |
422 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | 465 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { |
423 | check_no_diagnostics( | 466 | check_no_diagnostics( |
424 | r#" | 467 | r#" |
425 | //- /main.rs crate:main deps:core | 468 | //- /main.rs crate:main deps:core |
@@ -433,6 +476,9 @@ fn foo() -> SomeOtherEnum { 0 } | |||
433 | pub mod result { | 476 | pub mod result { |
434 | pub enum Result<T, E> { Ok(T), Err(E) } | 477 | pub enum Result<T, E> { Ok(T), Err(E) } |
435 | } | 478 | } |
479 | pub mod option { | ||
480 | pub enum Option<T> { Some(T), None } | ||
481 | } | ||
436 | "#, | 482 | "#, |
437 | ); | 483 | ); |
438 | } | 484 | } |
@@ -444,7 +490,7 @@ pub mod result { | |||
444 | struct TestStruct { one: i32, two: i64 } | 490 | struct TestStruct { one: i32, two: i64 } |
445 | 491 | ||
446 | fn test_fn() { | 492 | fn test_fn() { |
447 | let s = TestStruct {<|>}; | 493 | let s = TestStruct {$0}; |
448 | } | 494 | } |
449 | "#, | 495 | "#, |
450 | r#" | 496 | r#" |
@@ -464,7 +510,7 @@ fn test_fn() { | |||
464 | struct TestStruct { one: i32 } | 510 | struct TestStruct { one: i32 } |
465 | 511 | ||
466 | impl TestStruct { | 512 | impl TestStruct { |
467 | fn test_fn() { let s = Self {<|>}; } | 513 | fn test_fn() { let s = Self {$0}; } |
468 | } | 514 | } |
469 | "#, | 515 | "#, |
470 | r#" | 516 | r#" |
@@ -487,7 +533,7 @@ enum Expr { | |||
487 | 533 | ||
488 | impl Expr { | 534 | impl Expr { |
489 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { | 535 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { |
490 | Expr::Bin {<|> } | 536 | Expr::Bin {$0 } |
491 | } | 537 | } |
492 | } | 538 | } |
493 | "#, | 539 | "#, |
@@ -512,7 +558,7 @@ impl Expr { | |||
512 | struct TestStruct { one: i32, two: i64 } | 558 | struct TestStruct { one: i32, two: i64 } |
513 | 559 | ||
514 | fn test_fn() { | 560 | fn test_fn() { |
515 | let s = TestStruct{ two: 2<|> }; | 561 | let s = TestStruct{ two: 2$0 }; |
516 | } | 562 | } |
517 | "#, | 563 | "#, |
518 | r" | 564 | r" |
@@ -567,7 +613,7 @@ fn test_fn() { | |||
567 | Fix { | 613 | Fix { |
568 | label: "Create module", | 614 | label: "Create module", |
569 | source_change: SourceChange { | 615 | source_change: SourceChange { |
570 | source_file_edits: [], | 616 | source_file_edits: {}, |
571 | file_system_edits: [ | 617 | file_system_edits: [ |
572 | CreateFile { | 618 | CreateFile { |
573 | dst: AnchoredPathBuf { | 619 | dst: AnchoredPathBuf { |
@@ -608,7 +654,7 @@ fn here() {} | |||
608 | macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } | 654 | macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } |
609 | 655 | ||
610 | fn main() { | 656 | fn main() { |
611 | let _x = id![Foo { a: <|>42 }]; | 657 | let _x = id![Foo { a: $042 }]; |
612 | } | 658 | } |
613 | 659 | ||
614 | pub struct Foo { pub a: i32, pub b: i32 } | 660 | pub struct Foo { pub a: i32, pub b: i32 } |
@@ -663,7 +709,7 @@ mod a { | |||
663 | check_fix( | 709 | check_fix( |
664 | r" | 710 | r" |
665 | mod b {} | 711 | mod b {} |
666 | use {<|>b}; | 712 | use {$0b}; |
667 | ", | 713 | ", |
668 | r" | 714 | r" |
669 | mod b {} | 715 | mod b {} |
@@ -673,7 +719,7 @@ mod a { | |||
673 | check_fix( | 719 | check_fix( |
674 | r" | 720 | r" |
675 | mod b {} | 721 | mod b {} |
676 | use {b<|>}; | 722 | use {b$0}; |
677 | ", | 723 | ", |
678 | r" | 724 | r" |
679 | mod b {} | 725 | mod b {} |
@@ -683,7 +729,7 @@ mod a { | |||
683 | check_fix( | 729 | check_fix( |
684 | r" | 730 | r" |
685 | mod a { mod c {} } | 731 | mod a { mod c {} } |
686 | use a::{c<|>}; | 732 | use a::{c$0}; |
687 | ", | 733 | ", |
688 | r" | 734 | r" |
689 | mod a { mod c {} } | 735 | mod a { mod c {} } |
@@ -693,7 +739,7 @@ mod a { | |||
693 | check_fix( | 739 | check_fix( |
694 | r" | 740 | r" |
695 | mod a {} | 741 | mod a {} |
696 | use a::{self<|>}; | 742 | use a::{self$0}; |
697 | ", | 743 | ", |
698 | r" | 744 | r" |
699 | mod a {} | 745 | mod a {} |
@@ -703,7 +749,7 @@ mod a { | |||
703 | check_fix( | 749 | check_fix( |
704 | r" | 750 | r" |
705 | mod a { mod c {} mod d { mod e {} } } | 751 | mod a { mod c {} mod d { mod e {} } } |
706 | use a::{c, d::{e<|>}}; | 752 | use a::{c, d::{e$0}}; |
707 | ", | 753 | ", |
708 | r" | 754 | r" |
709 | mod a { mod c {} mod d { mod e {} } } | 755 | mod a { mod c {} mod d { mod e {} } } |
@@ -717,7 +763,7 @@ mod a { | |||
717 | check_fix( | 763 | check_fix( |
718 | r" | 764 | r" |
719 | fn main() { | 765 | fn main() { |
720 | Foo { bar: 3, baz<|>: false}; | 766 | Foo { bar: 3, baz$0: false}; |
721 | } | 767 | } |
722 | struct Foo { | 768 | struct Foo { |
723 | bar: i32 | 769 | bar: i32 |
@@ -743,7 +789,7 @@ struct Foo { | |||
743 | mod foo; | 789 | mod foo; |
744 | 790 | ||
745 | fn main() { | 791 | fn main() { |
746 | foo::Foo { bar: 3, <|>baz: false}; | 792 | foo::Foo { bar: 3, $0baz: false}; |
747 | } | 793 | } |
748 | //- /foo.rs | 794 | //- /foo.rs |
749 | struct Foo { | 795 | struct Foo { |
@@ -777,7 +823,7 @@ struct Foo { | |||
777 | fn test_rename_incorrect_case() { | 823 | fn test_rename_incorrect_case() { |
778 | check_fix( | 824 | check_fix( |
779 | r#" | 825 | r#" |
780 | pub struct test_struct<|> { one: i32 } | 826 | pub struct test_struct$0 { one: i32 } |
781 | 827 | ||
782 | pub fn some_fn(val: test_struct) -> test_struct { | 828 | pub fn some_fn(val: test_struct) -> test_struct { |
783 | test_struct { one: val.one + 1 } | 829 | test_struct { one: val.one + 1 } |
@@ -794,7 +840,7 @@ pub fn some_fn(val: TestStruct) -> TestStruct { | |||
794 | 840 | ||
795 | check_fix( | 841 | check_fix( |
796 | r#" | 842 | r#" |
797 | pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { | 843 | pub fn some_fn(NonSnakeCase$0: u8) -> u8 { |
798 | NonSnakeCase | 844 | NonSnakeCase |
799 | } | 845 | } |
800 | "#, | 846 | "#, |
@@ -807,7 +853,7 @@ pub fn some_fn(non_snake_case: u8) -> u8 { | |||
807 | 853 | ||
808 | check_fix( | 854 | check_fix( |
809 | r#" | 855 | r#" |
810 | pub fn SomeFn<|>(val: u8) -> u8 { | 856 | pub fn SomeFn$0(val: u8) -> u8 { |
811 | if val != 0 { SomeFn(val - 1) } else { val } | 857 | if val != 0 { SomeFn(val - 1) } else { val } |
812 | } | 858 | } |
813 | "#, | 859 | "#, |
@@ -821,7 +867,7 @@ pub fn some_fn(val: u8) -> u8 { | |||
821 | check_fix( | 867 | check_fix( |
822 | r#" | 868 | r#" |
823 | fn some_fn() { | 869 | fn some_fn() { |
824 | let whatAWeird_Formatting<|> = 10; | 870 | let whatAWeird_Formatting$0 = 10; |
825 | another_func(whatAWeird_Formatting); | 871 | another_func(whatAWeird_Formatting); |
826 | } | 872 | } |
827 | "#, | 873 | "#, |
@@ -839,7 +885,7 @@ fn some_fn() { | |||
839 | check_no_diagnostics( | 885 | check_no_diagnostics( |
840 | r#" | 886 | r#" |
841 | fn foo() { | 887 | fn foo() { |
842 | const ANOTHER_ITEM<|>: &str = "some_item"; | 888 | const ANOTHER_ITEM$0: &str = "some_item"; |
843 | } | 889 | } |
844 | "#, | 890 | "#, |
845 | ); | 891 | ); |
@@ -852,7 +898,7 @@ fn foo() { | |||
852 | pub struct TestStruct; | 898 | pub struct TestStruct; |
853 | 899 | ||
854 | impl TestStruct { | 900 | impl TestStruct { |
855 | pub fn SomeFn<|>() -> TestStruct { | 901 | pub fn SomeFn$0() -> TestStruct { |
856 | TestStruct | 902 | TestStruct |
857 | } | 903 | } |
858 | } | 904 | } |
@@ -871,7 +917,7 @@ impl TestStruct { | |||
871 | 917 | ||
872 | #[test] | 918 | #[test] |
873 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | 919 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { |
874 | let input = r#"fn FOO<|>() {}"#; | 920 | let input = r#"fn FOO$0() {}"#; |
875 | let expected = r#"fn foo() {}"#; | 921 | let expected = r#"fn foo() {}"#; |
876 | 922 | ||
877 | let (analysis, file_position) = fixture::position(input); | 923 | let (analysis, file_position) = fixture::position(input); |
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs index f41bcd619..5c89e2170 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide/src/diagnostics/field_shorthand.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both | 1 | //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both |
2 | //! expressions and patterns. | 2 | //! expressions and patterns. |
3 | 3 | ||
4 | use ide_db::base_db::FileId; | 4 | use ide_db::{base_db::FileId, source_change::SourceChange}; |
5 | use ide_db::source_change::SourceFileEdit; | ||
6 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; |
7 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
8 | 7 | ||
@@ -50,7 +49,7 @@ fn check_expr_field_shorthand( | |||
50 | Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( | 49 | Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( |
51 | Some(Fix::new( | 50 | Some(Fix::new( |
52 | "Use struct shorthand initialization", | 51 | "Use struct shorthand initialization", |
53 | SourceFileEdit { file_id, edit }.into(), | 52 | SourceChange::from_text_edit(file_id, edit), |
54 | field_range, | 53 | field_range, |
55 | )), | 54 | )), |
56 | ), | 55 | ), |
@@ -89,7 +88,7 @@ fn check_pat_field_shorthand( | |||
89 | acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( | 88 | acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( |
90 | Some(Fix::new( | 89 | Some(Fix::new( |
91 | "Use struct field shorthand", | 90 | "Use struct field shorthand", |
92 | SourceFileEdit { file_id, edit }.into(), | 91 | SourceChange::from_text_edit(file_id, edit), |
93 | field_range, | 92 | field_range, |
94 | )), | 93 | )), |
95 | )); | 94 | )); |
@@ -120,7 +119,7 @@ fn main() { A { 0: 0 } } | |||
120 | struct A { a: &'static str } | 119 | struct A { a: &'static str } |
121 | fn main() { | 120 | fn main() { |
122 | let a = "haha"; | 121 | let a = "haha"; |
123 | A { a<|>: a } | 122 | A { a$0: a } |
124 | } | 123 | } |
125 | "#, | 124 | "#, |
126 | r#" | 125 | r#" |
@@ -138,7 +137,7 @@ struct A { a: &'static str, b: &'static str } | |||
138 | fn main() { | 137 | fn main() { |
139 | let a = "haha"; | 138 | let a = "haha"; |
140 | let b = "bb"; | 139 | let b = "bb"; |
141 | A { a<|>: a, b } | 140 | A { a$0: a, b } |
142 | } | 141 | } |
143 | "#, | 142 | "#, |
144 | r#" | 143 | r#" |
@@ -171,7 +170,7 @@ fn f(a: A) { let A { 0: 0 } = a; } | |||
171 | r#" | 170 | r#" |
172 | struct A { a: &'static str } | 171 | struct A { a: &'static str } |
173 | fn f(a: A) { | 172 | fn f(a: A) { |
174 | let A { a<|>: a } = a; | 173 | let A { a$0: a } = a; |
175 | } | 174 | } |
176 | "#, | 175 | "#, |
177 | r#" | 176 | r#" |
@@ -186,7 +185,7 @@ fn f(a: A) { | |||
186 | r#" | 185 | r#" |
187 | struct A { a: &'static str, b: &'static str } | 186 | struct A { a: &'static str, b: &'static str } |
188 | fn f(a: A) { | 187 | fn f(a: A) { |
189 | let A { a<|>: a, b } = a; | 188 | let A { a$0: a, b } = a; |
190 | } | 189 | } |
191 | "#, | 190 | "#, |
192 | r#" | 191 | r#" |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 71ec4df92..e4335119b 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -3,14 +3,14 @@ | |||
3 | use hir::{ | 3 | use hir::{ |
4 | db::AstDatabase, | 4 | db::AstDatabase, |
5 | diagnostics::{ | 5 | diagnostics::{ |
6 | Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField, | 6 | Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField, |
7 | RemoveThisSemicolon, UnresolvedModule, | 7 | RemoveThisSemicolon, UnresolvedModule, |
8 | }, | 8 | }, |
9 | HasSource, HirDisplay, InFile, Semantics, VariantDef, | 9 | HasSource, HirDisplay, InFile, Semantics, VariantDef, |
10 | }; | 10 | }; |
11 | use ide_db::base_db::{AnchoredPathBuf, FileId}; | ||
12 | use ide_db::{ | 11 | use ide_db::{ |
13 | source_change::{FileSystemEdit, SourceFileEdit}, | 12 | base_db::{AnchoredPathBuf, FileId}, |
13 | source_change::{FileSystemEdit, SourceChange}, | ||
14 | RootDatabase, | 14 | RootDatabase, |
15 | }; | 15 | }; |
16 | use syntax::{ | 16 | use syntax::{ |
@@ -88,21 +88,22 @@ impl DiagnosticWithFix for MissingFields { | |||
88 | }; | 88 | }; |
89 | Some(Fix::new( | 89 | Some(Fix::new( |
90 | "Fill struct fields", | 90 | "Fill struct fields", |
91 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(), | 91 | SourceChange::from_text_edit(self.file.original_file(sema.db), edit), |
92 | sema.original_range(&field_list_parent.syntax()).range, | 92 | sema.original_range(&field_list_parent.syntax()).range, |
93 | )) | 93 | )) |
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | impl DiagnosticWithFix for MissingOkInTailExpr { | 97 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { |
98 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 98 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { |
99 | let root = sema.db.parse_or_expand(self.file)?; | 99 | let root = sema.db.parse_or_expand(self.file)?; |
100 | let tail_expr = self.expr.to_node(&root); | 100 | let tail_expr = self.expr.to_node(&root); |
101 | let tail_expr_range = tail_expr.syntax().text_range(); | 101 | let tail_expr_range = tail_expr.syntax().text_range(); |
102 | let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); | 102 | let replacement = format!("{}({})", self.required, tail_expr.syntax()); |
103 | let source_change = | 103 | let edit = TextEdit::replace(tail_expr_range, replacement); |
104 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); | 104 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); |
105 | Some(Fix::new("Wrap with ok", source_change, tail_expr_range)) | 105 | let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; |
106 | Some(Fix::new(name, source_change, tail_expr_range)) | ||
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
@@ -120,8 +121,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon { | |||
120 | .text_range(); | 121 | .text_range(); |
121 | 122 | ||
122 | let edit = TextEdit::delete(semicolon); | 123 | let edit = TextEdit::delete(semicolon); |
123 | let source_change = | 124 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); |
124 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); | ||
125 | 125 | ||
126 | Some(Fix::new("Remove this semicolon", source_change, semicolon)) | 126 | Some(Fix::new("Remove this semicolon", source_change, semicolon)) |
127 | } | 127 | } |
@@ -202,15 +202,11 @@ fn missing_record_expr_field_fix( | |||
202 | new_field = format!(",{}", new_field); | 202 | new_field = format!(",{}", new_field); |
203 | } | 203 | } |
204 | 204 | ||
205 | let source_change = SourceFileEdit { | 205 | let source_change = SourceChange::from_text_edit( |
206 | file_id: def_file_id, | 206 | def_file_id, |
207 | edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), | 207 | TextEdit::insert(last_field_syntax.text_range().end(), new_field), |
208 | }; | 208 | ); |
209 | return Some(Fix::new( | 209 | return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range())); |
210 | "Create field", | ||
211 | source_change.into(), | ||
212 | record_expr_field.syntax().text_range(), | ||
213 | )); | ||
214 | 210 | ||
215 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { | 211 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { |
216 | match field_def_list { | 212 | match field_def_list { |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index e24c78301..00e601244 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -215,10 +215,8 @@ impl TryToNav for Definition { | |||
215 | Definition::ModuleDef(it) => it.try_to_nav(db), | 215 | Definition::ModuleDef(it) => it.try_to_nav(db), |
216 | Definition::SelfType(it) => it.try_to_nav(db), | 216 | Definition::SelfType(it) => it.try_to_nav(db), |
217 | Definition::Local(it) => Some(it.to_nav(db)), | 217 | Definition::Local(it) => Some(it.to_nav(db)), |
218 | Definition::TypeParam(it) => it.try_to_nav(db), | 218 | Definition::GenericParam(it) => it.try_to_nav(db), |
219 | Definition::LifetimeParam(it) => it.try_to_nav(db), | ||
220 | Definition::Label(it) => Some(it.to_nav(db)), | 219 | Definition::Label(it) => Some(it.to_nav(db)), |
221 | Definition::ConstParam(it) => it.try_to_nav(db), | ||
222 | } | 220 | } |
223 | } | 221 | } |
224 | } | 222 | } |
@@ -389,27 +387,44 @@ impl TryToNav for hir::AssocItem { | |||
389 | } | 387 | } |
390 | } | 388 | } |
391 | 389 | ||
390 | impl TryToNav for hir::GenericParam { | ||
391 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | ||
392 | match self { | ||
393 | hir::GenericParam::TypeParam(it) => it.try_to_nav(db), | ||
394 | hir::GenericParam::ConstParam(it) => it.try_to_nav(db), | ||
395 | hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db), | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | |||
392 | impl ToNav for hir::Local { | 400 | impl ToNav for hir::Local { |
393 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 401 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
394 | let src = self.source(db); | 402 | let src = self.source(db); |
395 | let node = match &src.value { | 403 | let (node, name) = match &src.value { |
396 | Either::Left(bind_pat) => { | 404 | Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()), |
397 | bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone()) | 405 | Either::Right(it) => (it.syntax().clone(), it.name()), |
398 | } | ||
399 | Either::Right(it) => it.syntax().clone(), | ||
400 | }; | 406 | }; |
407 | let focus_range = | ||
408 | name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range); | ||
409 | |||
401 | let full_range = src.with_value(&node).original_file_range(db); | 410 | let full_range = src.with_value(&node).original_file_range(db); |
402 | let name = match self.name(db) { | 411 | let name = match self.name(db) { |
403 | Some(it) => it.to_string().into(), | 412 | Some(it) => it.to_string().into(), |
404 | None => "".into(), | 413 | None => "".into(), |
405 | }; | 414 | }; |
406 | let kind = if self.is_param(db) { SymbolKind::ValueParam } else { SymbolKind::Local }; | 415 | let kind = if self.is_self(db) { |
416 | SymbolKind::SelfParam | ||
417 | } else if self.is_param(db) { | ||
418 | SymbolKind::ValueParam | ||
419 | } else { | ||
420 | SymbolKind::Local | ||
421 | }; | ||
407 | NavigationTarget { | 422 | NavigationTarget { |
408 | file_id: full_range.file_id, | 423 | file_id: full_range.file_id, |
409 | name, | 424 | name, |
410 | kind: Some(kind), | 425 | kind: Some(kind), |
411 | full_range: full_range.range, | 426 | full_range: full_range.range, |
412 | focus_range: None, | 427 | focus_range, |
413 | container_name: None, | 428 | container_name: None, |
414 | description: None, | 429 | description: None, |
415 | docs: None, | 430 | docs: None, |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 367fac05e..de10406bc 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Resolves and rewrites links in markdown documentation. | 1 | //! Resolves and rewrites links in markdown documentation. |
2 | 2 | ||
3 | use std::{convert::TryFrom, iter::once}; | 3 | use std::{convert::TryFrom, iter::once, ops::Range}; |
4 | 4 | ||
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; | 6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; |
@@ -39,7 +39,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
39 | if target.contains("://") { | 39 | if target.contains("://") { |
40 | (target.to_string(), title.to_string()) | 40 | (target.to_string(), title.to_string()) |
41 | } else { | 41 | } else { |
42 | // Two posibilities: | 42 | // Two possibilities: |
43 | // * path-based links: `../../module/struct.MyStruct.html` | 43 | // * path-based links: `../../module/struct.MyStruct.html` |
44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` | 44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` |
45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { | 45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { |
@@ -61,6 +61,30 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
61 | out | 61 | out |
62 | } | 62 | } |
63 | 63 | ||
64 | pub(crate) fn extract_definitions_from_markdown( | ||
65 | markdown: &str, | ||
66 | ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> { | ||
67 | let mut res = vec![]; | ||
68 | let mut cb = |link: BrokenLink| { | ||
69 | Some(( | ||
70 | /*url*/ link.reference.to_owned().into(), | ||
71 | /*title*/ link.reference.to_owned().into(), | ||
72 | )) | ||
73 | }; | ||
74 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | ||
75 | for (event, range) in doc.into_offset_iter() { | ||
76 | match event { | ||
77 | Event::Start(Tag::Link(_link_type, ref target, ref title)) => { | ||
78 | let link = if target.is_empty() { title } else { target }; | ||
79 | let (link, ns) = parse_link(link); | ||
80 | res.push((link.to_string(), ns, range)); | ||
81 | } | ||
82 | _ => {} | ||
83 | } | ||
84 | } | ||
85 | res | ||
86 | } | ||
87 | |||
64 | /// Remove all links in markdown documentation. | 88 | /// Remove all links in markdown documentation. |
65 | pub(crate) fn remove_links(markdown: &str) -> String { | 89 | pub(crate) fn remove_links(markdown: &str) -> String { |
66 | let mut drop_link = false; | 90 | let mut drop_link = false; |
@@ -192,9 +216,7 @@ fn rewrite_intra_doc_link( | |||
192 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), | 216 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), |
193 | Definition::SelfType(_) | 217 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 218 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 219 | | Definition::GenericParam(_) |
196 | | Definition::ConstParam(_) | ||
197 | | Definition::LifetimeParam(_) | ||
198 | | Definition::Label(_) => return None, | 220 | | Definition::Label(_) => return None, |
199 | }?; | 221 | }?; |
200 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
@@ -420,7 +442,7 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem) | |||
420 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), | 442 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), |
421 | Some(AssocItemContainer::Trait(..)) | 443 | Some(AssocItemContainer::Trait(..)) |
422 | ); | 444 | ); |
423 | // This distinction may get more complicated when specialisation is available. | 445 | // This distinction may get more complicated when specialization is available. |
424 | // Rustdoc makes this decision based on whether a method 'has defaultness'. | 446 | // Rustdoc makes this decision based on whether a method 'has defaultness'. |
425 | // Currently this is only the case for provided trait methods. | 447 | // Currently this is only the case for provided trait methods. |
426 | if is_trait_method && !function.has_body(db) { | 448 | if is_trait_method && !function.has_body(db) { |
@@ -464,7 +486,7 @@ mod tests { | |||
464 | fn test_doc_url_struct() { | 486 | fn test_doc_url_struct() { |
465 | check( | 487 | check( |
466 | r#" | 488 | r#" |
467 | pub struct Fo<|>o; | 489 | pub struct Fo$0o; |
468 | "#, | 490 | "#, |
469 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], | 491 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], |
470 | ); | 492 | ); |
@@ -474,7 +496,7 @@ pub struct Fo<|>o; | |||
474 | fn test_doc_url_fn() { | 496 | fn test_doc_url_fn() { |
475 | check( | 497 | check( |
476 | r#" | 498 | r#" |
477 | pub fn fo<|>o() {} | 499 | pub fn fo$0o() {} |
478 | "#, | 500 | "#, |
479 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], | 501 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], |
480 | ); | 502 | ); |
@@ -487,7 +509,7 @@ pub fn fo<|>o() {} | |||
487 | pub struct Foo; | 509 | pub struct Foo; |
488 | 510 | ||
489 | impl Foo { | 511 | impl Foo { |
490 | pub fn met<|>hod() {} | 512 | pub fn met$0hod() {} |
491 | } | 513 | } |
492 | 514 | ||
493 | "#, | 515 | "#, |
@@ -500,7 +522,7 @@ impl Foo { | |||
500 | check( | 522 | check( |
501 | r#" | 523 | r#" |
502 | pub trait Bar { | 524 | pub trait Bar { |
503 | fn met<|>hod() {} | 525 | fn met$0hod() {} |
504 | } | 526 | } |
505 | 527 | ||
506 | "#, | 528 | "#, |
@@ -513,7 +535,7 @@ pub trait Bar { | |||
513 | check( | 535 | check( |
514 | r#" | 536 | r#" |
515 | pub trait Foo { | 537 | pub trait Foo { |
516 | fn met<|>hod(); | 538 | fn met$0hod(); |
517 | } | 539 | } |
518 | 540 | ||
519 | "#, | 541 | "#, |
@@ -526,7 +548,7 @@ pub trait Foo { | |||
526 | check( | 548 | check( |
527 | r#" | 549 | r#" |
528 | pub struct Foo { | 550 | pub struct Foo { |
529 | pub fie<|>ld: () | 551 | pub fie$0ld: () |
530 | } | 552 | } |
531 | 553 | ||
532 | "#, | 554 | "#, |
@@ -539,7 +561,7 @@ pub struct Foo { | |||
539 | check( | 561 | check( |
540 | r#" | 562 | r#" |
541 | pub mod foo { | 563 | pub mod foo { |
542 | pub mod ba<|>r {} | 564 | pub mod ba$0r {} |
543 | } | 565 | } |
544 | "#, | 566 | "#, |
545 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], | 567 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], |
@@ -564,7 +586,7 @@ pub mod wrapper { | |||
564 | } | 586 | } |
565 | 587 | ||
566 | fn foo() { | 588 | fn foo() { |
567 | let bar: wrapper::It<|>em; | 589 | let bar: wrapper::It$0em; |
568 | } | 590 | } |
569 | "#, | 591 | "#, |
570 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], | 592 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], |
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 8d75e0f05..ffb3a6f7d 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -144,7 +144,7 @@ macro_rules! foo { | |||
144 | macro_rules! baz { | 144 | macro_rules! baz { |
145 | () => { foo!(); } | 145 | () => { foo!(); } |
146 | } | 146 | } |
147 | f<|>oo!(); | 147 | f$0oo!(); |
148 | "#, | 148 | "#, |
149 | expect![[r#" | 149 | expect![[r#" |
150 | foo | 150 | foo |
@@ -165,7 +165,7 @@ macro_rules! foo { | |||
165 | } | 165 | } |
166 | } | 166 | } |
167 | } | 167 | } |
168 | f<|>oo!(); | 168 | f$0oo!(); |
169 | "#, | 169 | "#, |
170 | expect![[r#" | 170 | expect![[r#" |
171 | foo | 171 | foo |
@@ -192,7 +192,7 @@ macro_rules! match_ast { | |||
192 | } | 192 | } |
193 | 193 | ||
194 | fn main() { | 194 | fn main() { |
195 | mat<|>ch_ast! { | 195 | mat$0ch_ast! { |
196 | match container { | 196 | match container { |
197 | ast::TraitDef(it) => {}, | 197 | ast::TraitDef(it) => {}, |
198 | ast::ImplDef(it) => {}, | 198 | ast::ImplDef(it) => {}, |
@@ -226,7 +226,7 @@ macro_rules! match_ast { | |||
226 | 226 | ||
227 | fn main() { | 227 | fn main() { |
228 | let p = f(|it| { | 228 | let p = f(|it| { |
229 | let res = mat<|>ch_ast! { match c {}}; | 229 | let res = mat$0ch_ast! { match c {}}; |
230 | Some(res) | 230 | Some(res) |
231 | })?; | 231 | })?; |
232 | } | 232 | } |
@@ -250,7 +250,7 @@ macro_rules! foo { | |||
250 | } | 250 | } |
251 | 251 | ||
252 | fn main() { | 252 | fn main() { |
253 | let res = fo<|>o!(); | 253 | let res = fo$0o!(); |
254 | } | 254 | } |
255 | "#, | 255 | "#, |
256 | expect![[r#" | 256 | expect![[r#" |
@@ -272,7 +272,7 @@ macro_rules! foo { | |||
272 | } | 272 | } |
273 | 273 | ||
274 | fn main() { | 274 | fn main() { |
275 | let res = fo<|>o!(); | 275 | let res = fo$0o!(); |
276 | } | 276 | } |
277 | "#, | 277 | "#, |
278 | expect![[r#" | 278 | expect![[r#" |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 6f3022dfd..17a540972 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::RootDatabase; | 4 | use ide_db::RootDatabase; |
5 | use syntax::{ | 5 | use syntax::{ |
6 | algo::{self, find_covering_element, skip_trivia_token}, | 6 | algo::{self, skip_trivia_token}, |
7 | ast::{self, AstNode, AstToken}, | 7 | ast::{self, AstNode, AstToken}, |
8 | Direction, NodeOrToken, | 8 | Direction, NodeOrToken, |
9 | SyntaxKind::{self, *}, | 9 | SyntaxKind::{self, *}, |
@@ -76,7 +76,7 @@ fn try_extend_selection( | |||
76 | }; | 76 | }; |
77 | return Some(leaf_range); | 77 | return Some(leaf_range); |
78 | }; | 78 | }; |
79 | let node = match find_covering_element(root, range) { | 79 | let node = match root.covering_element(range) { |
80 | NodeOrToken::Token(token) => { | 80 | NodeOrToken::Token(token) => { |
81 | if token.text_range() != range { | 81 | if token.text_range() != range { |
82 | return Some(token.text_range()); | 82 | return Some(token.text_range()); |
@@ -120,7 +120,7 @@ fn extend_tokens_from_range( | |||
120 | macro_call: ast::MacroCall, | 120 | macro_call: ast::MacroCall, |
121 | original_range: TextRange, | 121 | original_range: TextRange, |
122 | ) -> Option<TextRange> { | 122 | ) -> Option<TextRange> { |
123 | let src = find_covering_element(¯o_call.syntax(), original_range); | 123 | let src = macro_call.syntax().covering_element(original_range); |
124 | let (first_token, last_token) = match src { | 124 | let (first_token, last_token) = match src { |
125 | NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?), | 125 | NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?), |
126 | NodeOrToken::Token(it) => (it.clone(), it), | 126 | NodeOrToken::Token(it) => (it.clone(), it), |
@@ -334,29 +334,29 @@ mod tests { | |||
334 | 334 | ||
335 | #[test] | 335 | #[test] |
336 | fn test_extend_selection_arith() { | 336 | fn test_extend_selection_arith() { |
337 | do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); | 337 | do_check(r#"fn foo() { $01 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); |
338 | } | 338 | } |
339 | 339 | ||
340 | #[test] | 340 | #[test] |
341 | fn test_extend_selection_list() { | 341 | fn test_extend_selection_list() { |
342 | do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); | 342 | do_check(r#"fn foo($0x: i32) {}"#, &["x", "x: i32"]); |
343 | do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); | 343 | do_check(r#"fn foo($0x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); |
344 | do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); | 344 | do_check(r#"fn foo($0x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); |
345 | do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); | 345 | do_check(r#"fn foo(x: i32, $0y: i32) {}"#, &["y", "y: i32", ", y: i32"]); |
346 | do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); | 346 | do_check(r#"fn foo(x: i32, $0y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); |
347 | do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); | 347 | do_check(r#"fn foo(x: i32,$0y: i32) {}"#, &["y", "y: i32", ",y: i32"]); |
348 | 348 | ||
349 | do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); | 349 | do_check(r#"const FOO: [usize; 2] = [ 22$0 , 33];"#, &["22", "22 , "]); |
350 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); | 350 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0];"#, &["33", ", 33"]); |
351 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); | 351 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0 ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); |
352 | 352 | ||
353 | do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); | 353 | do_check(r#"fn main() { (1, 2$0) }"#, &["2", ", 2", "(1, 2)"]); |
354 | 354 | ||
355 | do_check( | 355 | do_check( |
356 | r#" | 356 | r#" |
357 | const FOO: [usize; 2] = [ | 357 | const FOO: [usize; 2] = [ |
358 | 22, | 358 | 22, |
359 | <|>33, | 359 | $033, |
360 | ]"#, | 360 | ]"#, |
361 | &["33", "33,"], | 361 | &["33", "33,"], |
362 | ); | 362 | ); |
@@ -365,7 +365,7 @@ const FOO: [usize; 2] = [ | |||
365 | r#" | 365 | r#" |
366 | const FOO: [usize; 2] = [ | 366 | const FOO: [usize; 2] = [ |
367 | 22 | 367 | 22 |
368 | , 33<|>, | 368 | , 33$0, |
369 | ]"#, | 369 | ]"#, |
370 | &["33", "33,"], | 370 | &["33", "33,"], |
371 | ); | 371 | ); |
@@ -376,7 +376,7 @@ const FOO: [usize; 2] = [ | |||
376 | do_check( | 376 | do_check( |
377 | r#" | 377 | r#" |
378 | impl S { | 378 | impl S { |
379 | <|> fn foo() { | 379 | $0 fn foo() { |
380 | 380 | ||
381 | } | 381 | } |
382 | }"#, | 382 | }"#, |
@@ -393,7 +393,7 @@ struct A; | |||
393 | /// bla | 393 | /// bla |
394 | /// bla | 394 | /// bla |
395 | struct B { | 395 | struct B { |
396 | <|> | 396 | $0 |
397 | } | 397 | } |
398 | "#, | 398 | "#, |
399 | &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], | 399 | &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], |
@@ -407,7 +407,7 @@ struct B { | |||
407 | fn bar(){} | 407 | fn bar(){} |
408 | 408 | ||
409 | // fn foo() { | 409 | // fn foo() { |
410 | // 1 + <|>1 | 410 | // 1 + $01 |
411 | // } | 411 | // } |
412 | 412 | ||
413 | // fn foo(){} | 413 | // fn foo(){} |
@@ -419,7 +419,7 @@ fn bar(){} | |||
419 | r#" | 419 | r#" |
420 | // #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 420 | // #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
421 | // pub enum Direction { | 421 | // pub enum Direction { |
422 | // <|> Next, | 422 | // $0 Next, |
423 | // Prev | 423 | // Prev |
424 | // } | 424 | // } |
425 | "#, | 425 | "#, |
@@ -433,27 +433,27 @@ fn bar(){} | |||
433 | r#" | 433 | r#" |
434 | /* | 434 | /* |
435 | foo | 435 | foo |
436 | _bar1<|>*/ | 436 | _bar1$0*/ |
437 | "#, | 437 | "#, |
438 | &["_bar1", "/*\nfoo\n_bar1*/"], | 438 | &["_bar1", "/*\nfoo\n_bar1*/"], |
439 | ); | 439 | ); |
440 | 440 | ||
441 | do_check(r#"//!<|>foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); | 441 | do_check(r#"//!$0foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); |
442 | 442 | ||
443 | do_check(r#"/<|>/foo bar"#, &["//foo bar"]); | 443 | do_check(r#"/$0/foo bar"#, &["//foo bar"]); |
444 | } | 444 | } |
445 | 445 | ||
446 | #[test] | 446 | #[test] |
447 | fn test_extend_selection_prefer_idents() { | 447 | fn test_extend_selection_prefer_idents() { |
448 | do_check( | 448 | do_check( |
449 | r#" | 449 | r#" |
450 | fn main() { foo<|>+bar;} | 450 | fn main() { foo$0+bar;} |
451 | "#, | 451 | "#, |
452 | &["foo", "foo+bar"], | 452 | &["foo", "foo+bar"], |
453 | ); | 453 | ); |
454 | do_check( | 454 | do_check( |
455 | r#" | 455 | r#" |
456 | fn main() { foo+<|>bar;} | 456 | fn main() { foo+$0bar;} |
457 | "#, | 457 | "#, |
458 | &["bar", "foo+bar"], | 458 | &["bar", "foo+bar"], |
459 | ); | 459 | ); |
@@ -461,18 +461,18 @@ fn main() { foo+<|>bar;} | |||
461 | 461 | ||
462 | #[test] | 462 | #[test] |
463 | fn test_extend_selection_prefer_lifetimes() { | 463 | fn test_extend_selection_prefer_lifetimes() { |
464 | do_check(r#"fn foo<<|>'a>() {}"#, &["'a", "<'a>"]); | 464 | do_check(r#"fn foo<$0'a>() {}"#, &["'a", "<'a>"]); |
465 | do_check(r#"fn foo<'a<|>>() {}"#, &["'a", "<'a>"]); | 465 | do_check(r#"fn foo<'a$0>() {}"#, &["'a", "<'a>"]); |
466 | } | 466 | } |
467 | 467 | ||
468 | #[test] | 468 | #[test] |
469 | fn test_extend_selection_select_first_word() { | 469 | fn test_extend_selection_select_first_word() { |
470 | do_check(r#"// foo bar b<|>az quxx"#, &["baz", "// foo bar baz quxx"]); | 470 | do_check(r#"// foo bar b$0az quxx"#, &["baz", "// foo bar baz quxx"]); |
471 | do_check( | 471 | do_check( |
472 | r#" | 472 | r#" |
473 | impl S { | 473 | impl S { |
474 | fn foo() { | 474 | fn foo() { |
475 | // hel<|>lo world | 475 | // hel$0lo world |
476 | } | 476 | } |
477 | } | 477 | } |
478 | "#, | 478 | "#, |
@@ -486,7 +486,7 @@ fn foo() { | |||
486 | r#" | 486 | r#" |
487 | fn bar(){} | 487 | fn bar(){} |
488 | 488 | ||
489 | " fn f<|>oo() {" | 489 | " fn f$0oo() {" |
490 | "#, | 490 | "#, |
491 | &["foo", "\" fn foo() {\""], | 491 | &["foo", "\" fn foo() {\""], |
492 | ); | 492 | ); |
@@ -499,7 +499,7 @@ fn bar(){} | |||
499 | fn foo<R>() | 499 | fn foo<R>() |
500 | where | 500 | where |
501 | R: req::Request + 'static, | 501 | R: req::Request + 'static, |
502 | R::Params: DeserializeOwned<|> + panic::UnwindSafe + 'static, | 502 | R::Params: DeserializeOwned$0 + panic::UnwindSafe + 'static, |
503 | R::Result: Serialize + 'static, | 503 | R::Result: Serialize + 'static, |
504 | "#, | 504 | "#, |
505 | &[ | 505 | &[ |
@@ -510,26 +510,26 @@ fn foo<R>() | |||
510 | "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", | 510 | "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", |
511 | ], | 511 | ], |
512 | ); | 512 | ); |
513 | do_check(r#"fn foo<T>() where T: <|>Copy"#, &["Copy"]); | 513 | do_check(r#"fn foo<T>() where T: $0Copy"#, &["Copy"]); |
514 | do_check(r#"fn foo<T>() where T: <|>Copy + Display"#, &["Copy", "Copy + "]); | 514 | do_check(r#"fn foo<T>() where T: $0Copy + Display"#, &["Copy", "Copy + "]); |
515 | do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); | 515 | do_check(r#"fn foo<T>() where T: $0Copy +Display"#, &["Copy", "Copy +"]); |
516 | do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); | 516 | do_check(r#"fn foo<T>() where T: $0Copy+Display"#, &["Copy", "Copy+"]); |
517 | do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]); | 517 | do_check(r#"fn foo<T>() where T: Copy + $0Display"#, &["Display", "+ Display"]); |
518 | do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "Display + "]); | 518 | do_check(r#"fn foo<T>() where T: Copy + $0Display + Sync"#, &["Display", "Display + "]); |
519 | do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]); | 519 | do_check(r#"fn foo<T>() where T: Copy +$0Display"#, &["Display", "+Display"]); |
520 | } | 520 | } |
521 | 521 | ||
522 | #[test] | 522 | #[test] |
523 | fn test_extend_trait_bounds_list_inline() { | 523 | fn test_extend_trait_bounds_list_inline() { |
524 | do_check(r#"fn foo<T: <|>Copy>() {}"#, &["Copy"]); | 524 | do_check(r#"fn foo<T: $0Copy>() {}"#, &["Copy"]); |
525 | do_check(r#"fn foo<T: <|>Copy + Display>() {}"#, &["Copy", "Copy + "]); | 525 | do_check(r#"fn foo<T: $0Copy + Display>() {}"#, &["Copy", "Copy + "]); |
526 | do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]); | 526 | do_check(r#"fn foo<T: $0Copy +Display>() {}"#, &["Copy", "Copy +"]); |
527 | do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]); | 527 | do_check(r#"fn foo<T: $0Copy+Display>() {}"#, &["Copy", "Copy+"]); |
528 | do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]); | 528 | do_check(r#"fn foo<T: Copy + $0Display>() {}"#, &["Display", "+ Display"]); |
529 | do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "Display + "]); | 529 | do_check(r#"fn foo<T: Copy + $0Display + Sync>() {}"#, &["Display", "Display + "]); |
530 | do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]); | 530 | do_check(r#"fn foo<T: Copy +$0Display>() {}"#, &["Display", "+Display"]); |
531 | do_check( | 531 | do_check( |
532 | r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#, | 532 | r#"fn foo<T: Copy$0 + Display, U: Copy>() {}"#, |
533 | &[ | 533 | &[ |
534 | "Copy", | 534 | "Copy", |
535 | "Copy + ", | 535 | "Copy + ", |
@@ -544,19 +544,19 @@ fn foo<R>() | |||
544 | #[test] | 544 | #[test] |
545 | fn test_extend_selection_on_tuple_in_type() { | 545 | fn test_extend_selection_on_tuple_in_type() { |
546 | do_check( | 546 | do_check( |
547 | r#"fn main() { let _: (krate, <|>_crate_def_map, module_id) = (); }"#, | 547 | r#"fn main() { let _: (krate, $0_crate_def_map, module_id) = (); }"#, |
548 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 548 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
549 | ); | 549 | ); |
550 | // white space variations | 550 | // white space variations |
551 | do_check( | 551 | do_check( |
552 | r#"fn main() { let _: (krate,<|>_crate_def_map,module_id) = (); }"#, | 552 | r#"fn main() { let _: (krate,$0_crate_def_map,module_id) = (); }"#, |
553 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 553 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
554 | ); | 554 | ); |
555 | do_check( | 555 | do_check( |
556 | r#" | 556 | r#" |
557 | fn main() { let _: ( | 557 | fn main() { let _: ( |
558 | krate, | 558 | krate, |
559 | _crate<|>_def_map, | 559 | _crate$0_def_map, |
560 | module_id | 560 | module_id |
561 | ) = (); }"#, | 561 | ) = (); }"#, |
562 | &[ | 562 | &[ |
@@ -570,19 +570,19 @@ fn main() { let _: ( | |||
570 | #[test] | 570 | #[test] |
571 | fn test_extend_selection_on_tuple_in_rvalue() { | 571 | fn test_extend_selection_on_tuple_in_rvalue() { |
572 | do_check( | 572 | do_check( |
573 | r#"fn main() { let var = (krate, _crate_def_map<|>, module_id); }"#, | 573 | r#"fn main() { let var = (krate, _crate_def_map$0, module_id); }"#, |
574 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 574 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
575 | ); | 575 | ); |
576 | // white space variations | 576 | // white space variations |
577 | do_check( | 577 | do_check( |
578 | r#"fn main() { let var = (krate,_crate<|>_def_map,module_id); }"#, | 578 | r#"fn main() { let var = (krate,_crate$0_def_map,module_id); }"#, |
579 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 579 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
580 | ); | 580 | ); |
581 | do_check( | 581 | do_check( |
582 | r#" | 582 | r#" |
583 | fn main() { let var = ( | 583 | fn main() { let var = ( |
584 | krate, | 584 | krate, |
585 | _crate_def_map<|>, | 585 | _crate_def_map$0, |
586 | module_id | 586 | module_id |
587 | ); }"#, | 587 | ); }"#, |
588 | &[ | 588 | &[ |
@@ -596,19 +596,19 @@ fn main() { let var = ( | |||
596 | #[test] | 596 | #[test] |
597 | fn test_extend_selection_on_tuple_pat() { | 597 | fn test_extend_selection_on_tuple_pat() { |
598 | do_check( | 598 | do_check( |
599 | r#"fn main() { let (krate, _crate_def_map<|>, module_id) = var; }"#, | 599 | r#"fn main() { let (krate, _crate_def_map$0, module_id) = var; }"#, |
600 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 600 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
601 | ); | 601 | ); |
602 | // white space variations | 602 | // white space variations |
603 | do_check( | 603 | do_check( |
604 | r#"fn main() { let (krate,_crate<|>_def_map,module_id) = var; }"#, | 604 | r#"fn main() { let (krate,_crate$0_def_map,module_id) = var; }"#, |
605 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 605 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
606 | ); | 606 | ); |
607 | do_check( | 607 | do_check( |
608 | r#" | 608 | r#" |
609 | fn main() { let ( | 609 | fn main() { let ( |
610 | krate, | 610 | krate, |
611 | _crate_def_map<|>, | 611 | _crate_def_map$0, |
612 | module_id | 612 | module_id |
613 | ) = var; }"#, | 613 | ) = var; }"#, |
614 | &[ | 614 | &[ |
@@ -623,7 +623,7 @@ fn main() { let ( | |||
623 | fn extend_selection_inside_macros() { | 623 | fn extend_selection_inside_macros() { |
624 | do_check( | 624 | do_check( |
625 | r#"macro_rules! foo { ($item:item) => {$item} } | 625 | r#"macro_rules! foo { ($item:item) => {$item} } |
626 | foo!{fn hello(na<|>me:usize){}}"#, | 626 | foo!{fn hello(na$0me:usize){}}"#, |
627 | &[ | 627 | &[ |
628 | "name", | 628 | "name", |
629 | "name:usize", | 629 | "name:usize", |
@@ -640,7 +640,7 @@ fn main() { let ( | |||
640 | do_check( | 640 | do_check( |
641 | r#" macro_rules! foo2 { ($item:item) => {$item} } | 641 | r#" macro_rules! foo2 { ($item:item) => {$item} } |
642 | macro_rules! foo { ($item:item) => {foo2!($item);} } | 642 | macro_rules! foo { ($item:item) => {foo2!($item);} } |
643 | foo!{fn hello(na<|>me:usize){}}"#, | 643 | foo!{fn hello(na$0me:usize){}}"#, |
644 | &[ | 644 | &[ |
645 | "name", | 645 | "name", |
646 | "name:usize", | 646 | "name:usize", |
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index eb57f9224..cc8218885 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs | |||
@@ -20,12 +20,12 @@ pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) { | |||
20 | (host.analysis(), change_fixture.files) | 20 | (host.analysis(), change_fixture.files) |
21 | } | 21 | } |
22 | 22 | ||
23 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 23 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | 24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { |
25 | let mut host = AnalysisHost::default(); | 25 | let mut host = AnalysisHost::default(); |
26 | let change_fixture = ChangeFixture::parse(ra_fixture); | 26 | let change_fixture = ChangeFixture::parse(ra_fixture); |
27 | host.db.apply_change(change_fixture.change); | 27 | host.db.apply_change(change_fixture.change); |
28 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 28 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
29 | let offset = match range_or_offset { | 29 | let offset = match range_or_offset { |
30 | RangeOrOffset::Range(_) => panic!(), | 30 | RangeOrOffset::Range(_) => panic!(), |
31 | RangeOrOffset::Offset(it) => it, | 31 | RangeOrOffset::Offset(it) => it, |
@@ -33,12 +33,12 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | |||
33 | (host.analysis(), FilePosition { file_id, offset }) | 33 | (host.analysis(), FilePosition { file_id, offset }) |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Creates analysis for a single file, returns range marked with a pair of <|>. | 36 | /// Creates analysis for a single file, returns range marked with a pair of $0. |
37 | pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { | 37 | pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { |
38 | let mut host = AnalysisHost::default(); | 38 | let mut host = AnalysisHost::default(); |
39 | let change_fixture = ChangeFixture::parse(ra_fixture); | 39 | let change_fixture = ChangeFixture::parse(ra_fixture); |
40 | host.db.apply_change(change_fixture.change); | 40 | host.db.apply_change(change_fixture.change); |
41 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 41 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
42 | let range = match range_or_offset { | 42 | let range = match range_or_offset { |
43 | RangeOrOffset::Range(it) => it, | 43 | RangeOrOffset::Range(it) => it, |
44 | RangeOrOffset::Offset(_) => panic!(), | 44 | RangeOrOffset::Offset(_) => panic!(), |
@@ -46,12 +46,12 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { | |||
46 | (host.analysis(), FileRange { file_id, range }) | 46 | (host.analysis(), FileRange { file_id, range }) |
47 | } | 47 | } |
48 | 48 | ||
49 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 49 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
50 | pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { | 50 | pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { |
51 | let mut host = AnalysisHost::default(); | 51 | let mut host = AnalysisHost::default(); |
52 | let change_fixture = ChangeFixture::parse(ra_fixture); | 52 | let change_fixture = ChangeFixture::parse(ra_fixture); |
53 | host.db.apply_change(change_fixture.change); | 53 | host.db.apply_change(change_fixture.change); |
54 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 54 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
55 | let offset = match range_or_offset { | 55 | let offset = match range_or_offset { |
56 | RangeOrOffset::Range(_) => panic!(), | 56 | RangeOrOffset::Range(_) => panic!(), |
57 | RangeOrOffset::Offset(it) => it, | 57 | RangeOrOffset::Offset(it) => it, |
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs index 5cbbe306e..f6e5a522b 100644 --- a/crates/ide/src/fn_references.rs +++ b/crates/ide/src/fn_references.rs | |||
@@ -34,7 +34,7 @@ mod tests { | |||
34 | fn test_find_all_methods() { | 34 | fn test_find_all_methods() { |
35 | let (analysis, pos) = fixture::position( | 35 | let (analysis, pos) = fixture::position( |
36 | r#" | 36 | r#" |
37 | fn private_fn() {<|>} | 37 | fn private_fn() {$0} |
38 | 38 | ||
39 | pub fn pub_fn() {} | 39 | pub fn pub_fn() {} |
40 | 40 | ||
@@ -51,7 +51,7 @@ mod tests { | |||
51 | let (analysis, pos) = fixture::position( | 51 | let (analysis, pos) = fixture::position( |
52 | r#" | 52 | r#" |
53 | trait Foo { | 53 | trait Foo { |
54 | fn bar() {<|>} | 54 | fn bar() {$0} |
55 | fn baz() {} | 55 | fn baz() {} |
56 | } | 56 | } |
57 | "#, | 57 | "#, |
@@ -67,7 +67,7 @@ mod tests { | |||
67 | r#" | 67 | r#" |
68 | //- /lib.rs | 68 | //- /lib.rs |
69 | #[test] | 69 | #[test] |
70 | fn foo() {<|>} | 70 | fn foo() {$0} |
71 | 71 | ||
72 | pub fn pub_fn() {} | 72 | pub fn pub_fn() {} |
73 | 73 | ||
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 912144f8b..a1d2bce1d 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1,15 +1,18 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::Semantics; | 2 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | base_db::FileId, | 4 | defs::{Definition, NameClass, NameRefClass}, |
5 | defs::{NameClass, NameRefClass}, | ||
6 | symbol_index, RootDatabase, | 5 | symbol_index, RootDatabase, |
7 | }; | 6 | }; |
8 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 7 | use syntax::{ |
8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, | ||
9 | }; | ||
9 | 10 | ||
10 | use crate::{ | 11 | use crate::{ |
11 | display::{ToNav, TryToNav}, | 12 | display::{ToNav, TryToNav}, |
12 | FilePosition, NavigationTarget, RangeInfo, SymbolKind, | 13 | doc_links::extract_definitions_from_markdown, |
14 | runnables::doc_owner_to_def, | ||
15 | FilePosition, NavigationTarget, RangeInfo, | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | // Feature: Go to Definition | 18 | // Feature: Go to Definition |
@@ -30,6 +33,10 @@ pub(crate) fn goto_definition( | |||
30 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 33 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
31 | let token = sema.descend_into_macros(original_token.clone()); | 34 | let token = sema.descend_into_macros(original_token.clone()); |
32 | let parent = token.parent(); | 35 | let parent = token.parent(); |
36 | if let Some(comment) = ast::Comment::cast(token.clone()) { | ||
37 | let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?; | ||
38 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | ||
39 | } | ||
33 | 40 | ||
34 | let nav_targets = match_ast! { | 41 | let nav_targets = match_ast! { |
35 | match parent { | 42 | match parent { |
@@ -41,19 +48,6 @@ pub(crate) fn goto_definition( | |||
41 | let nav = def.try_to_nav(sema.db)?; | 48 | let nav = def.try_to_nav(sema.db)?; |
42 | vec![nav] | 49 | vec![nav] |
43 | }, | 50 | }, |
44 | ast::SelfParam(self_param) => { | ||
45 | vec![self_to_nav_target(self_param, position.file_id)?] | ||
46 | }, | ||
47 | ast::PathSegment(segment) => { | ||
48 | segment.self_token()?; | ||
49 | let path = segment.parent_path(); | ||
50 | if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) { | ||
51 | return None; | ||
52 | } | ||
53 | let func = segment.syntax().ancestors().find_map(ast::Fn::cast)?; | ||
54 | let self_param = func.param_list()?.self_param()?; | ||
55 | vec![self_to_nav_target(self_param, position.file_id)?] | ||
56 | }, | ||
57 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { | 51 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { |
58 | let def = name_class.referenced_or_defined(sema.db); | 52 | let def = name_class.referenced_or_defined(sema.db); |
59 | let nav = def.try_to_nav(sema.db)?; | 53 | let nav = def.try_to_nav(sema.db)?; |
@@ -68,31 +62,64 @@ pub(crate) fn goto_definition( | |||
68 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) | 62 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) |
69 | } | 63 | } |
70 | 64 | ||
65 | fn def_for_doc_comment( | ||
66 | sema: &Semantics<RootDatabase>, | ||
67 | position: FilePosition, | ||
68 | doc_comment: &ast::Comment, | ||
69 | ) -> Option<hir::ModuleDef> { | ||
70 | let parent = doc_comment.syntax().parent(); | ||
71 | let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; | ||
72 | |||
73 | let def = doc_owner_to_def(sema, parent)?; | ||
74 | match def { | ||
75 | Definition::ModuleDef(def) => match def { | ||
76 | ModuleDef::Module(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
77 | ModuleDef::Function(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
78 | ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
79 | ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
80 | ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
81 | ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
82 | ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
83 | ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
84 | ModuleDef::BuiltinType(_) => return None, | ||
85 | }, | ||
86 | Definition::Macro(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
87 | Definition::Field(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
88 | Definition::SelfType(_) | ||
89 | | Definition::Local(_) | ||
90 | | Definition::GenericParam(_) | ||
91 | | Definition::Label(_) => return None, | ||
92 | } | ||
93 | } | ||
94 | |||
95 | fn extract_positioned_link_from_comment( | ||
96 | position: FilePosition, | ||
97 | comment: &ast::Comment, | ||
98 | ) -> Option<(String, Option<hir::Namespace>)> { | ||
99 | let comment_range = comment.syntax().text_range(); | ||
100 | let doc_comment = comment.doc_comment()?; | ||
101 | let def_links = extract_definitions_from_markdown(doc_comment); | ||
102 | let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| { | ||
103 | let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32); | ||
104 | match position.offset.checked_sub(matched_position) { | ||
105 | Some(distance) => distance, | ||
106 | None => comment_range.end(), | ||
107 | } | ||
108 | })?; | ||
109 | Some((def_link.to_string(), ns.clone())) | ||
110 | } | ||
111 | |||
71 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 112 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
72 | return tokens.max_by_key(priority); | 113 | return tokens.max_by_key(priority); |
73 | fn priority(n: &SyntaxToken) -> usize { | 114 | fn priority(n: &SyntaxToken) -> usize { |
74 | match n.kind() { | 115 | match n.kind() { |
75 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2, | 116 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2, |
76 | kind if kind.is_trivia() => 0, | 117 | kind if kind.is_trivia() => 0, |
77 | _ => 1, | 118 | _ => 1, |
78 | } | 119 | } |
79 | } | 120 | } |
80 | } | 121 | } |
81 | 122 | ||
82 | fn self_to_nav_target(self_param: ast::SelfParam, file_id: FileId) -> Option<NavigationTarget> { | ||
83 | let self_token = self_param.self_token()?; | ||
84 | Some(NavigationTarget { | ||
85 | file_id, | ||
86 | full_range: self_param.syntax().text_range(), | ||
87 | focus_range: Some(self_token.text_range()), | ||
88 | name: self_token.text().clone(), | ||
89 | kind: Some(SymbolKind::SelfParam), | ||
90 | container_name: None, | ||
91 | description: None, | ||
92 | docs: None, | ||
93 | }) | ||
94 | } | ||
95 | |||
96 | #[derive(Debug)] | 123 | #[derive(Debug)] |
97 | pub(crate) enum ReferenceResult { | 124 | pub(crate) enum ReferenceResult { |
98 | Exact(NavigationTarget), | 125 | Exact(NavigationTarget), |
@@ -166,7 +193,7 @@ mod tests { | |||
166 | check( | 193 | check( |
167 | r#" | 194 | r#" |
168 | //- /main.rs crate:main deps:std | 195 | //- /main.rs crate:main deps:std |
169 | extern crate std<|>; | 196 | extern crate std$0; |
170 | //- /std/lib.rs crate:std | 197 | //- /std/lib.rs crate:std |
171 | // empty | 198 | // empty |
172 | //^ file | 199 | //^ file |
@@ -179,7 +206,7 @@ mod tests { | |||
179 | check( | 206 | check( |
180 | r#" | 207 | r#" |
181 | //- /main.rs crate:main deps:std | 208 | //- /main.rs crate:main deps:std |
182 | extern crate std as abc<|>; | 209 | extern crate std as abc$0; |
183 | //- /std/lib.rs crate:std | 210 | //- /std/lib.rs crate:std |
184 | // empty | 211 | // empty |
185 | //^ file | 212 | //^ file |
@@ -193,7 +220,7 @@ mod tests { | |||
193 | r#" | 220 | r#" |
194 | struct Foo; | 221 | struct Foo; |
195 | //^^^ | 222 | //^^^ |
196 | enum E { X(Foo<|>) } | 223 | enum E { X(Foo$0) } |
197 | "#, | 224 | "#, |
198 | ); | 225 | ); |
199 | } | 226 | } |
@@ -204,7 +231,7 @@ enum E { X(Foo<|>) } | |||
204 | r#" | 231 | r#" |
205 | struct Foo; | 232 | struct Foo; |
206 | //^^^ | 233 | //^^^ |
207 | enum E { X(<|>Foo) } | 234 | enum E { X($0Foo) } |
208 | "#, | 235 | "#, |
209 | ); | 236 | ); |
210 | } | 237 | } |
@@ -217,7 +244,7 @@ enum E { X(<|>Foo) } | |||
217 | use a::Foo; | 244 | use a::Foo; |
218 | mod a; | 245 | mod a; |
219 | mod b; | 246 | mod b; |
220 | enum E { X(Foo<|>) } | 247 | enum E { X(Foo$0) } |
221 | 248 | ||
222 | //- /a.rs | 249 | //- /a.rs |
223 | struct Foo; | 250 | struct Foo; |
@@ -233,7 +260,7 @@ struct Foo; | |||
233 | check( | 260 | check( |
234 | r#" | 261 | r#" |
235 | //- /lib.rs | 262 | //- /lib.rs |
236 | mod <|>foo; | 263 | mod $0foo; |
237 | 264 | ||
238 | //- /foo.rs | 265 | //- /foo.rs |
239 | // empty | 266 | // empty |
@@ -244,7 +271,7 @@ mod <|>foo; | |||
244 | check( | 271 | check( |
245 | r#" | 272 | r#" |
246 | //- /lib.rs | 273 | //- /lib.rs |
247 | mod <|>foo; | 274 | mod $0foo; |
248 | 275 | ||
249 | //- /foo/mod.rs | 276 | //- /foo/mod.rs |
250 | // empty | 277 | // empty |
@@ -260,7 +287,7 @@ mod <|>foo; | |||
260 | macro_rules! foo { () => { () } } | 287 | macro_rules! foo { () => { () } } |
261 | //^^^ | 288 | //^^^ |
262 | fn bar() { | 289 | fn bar() { |
263 | <|>foo!(); | 290 | $0foo!(); |
264 | } | 291 | } |
265 | "#, | 292 | "#, |
266 | ); | 293 | ); |
@@ -273,7 +300,7 @@ fn bar() { | |||
273 | //- /lib.rs | 300 | //- /lib.rs |
274 | use foo::foo; | 301 | use foo::foo; |
275 | fn bar() { | 302 | fn bar() { |
276 | <|>foo!(); | 303 | $0foo!(); |
277 | } | 304 | } |
278 | 305 | ||
279 | //- /foo/lib.rs | 306 | //- /foo/lib.rs |
@@ -289,7 +316,7 @@ macro_rules! foo { () => { () } } | |||
289 | check( | 316 | check( |
290 | r#" | 317 | r#" |
291 | //- /lib.rs | 318 | //- /lib.rs |
292 | use foo::foo<|>; | 319 | use foo::foo$0; |
293 | 320 | ||
294 | //- /foo/lib.rs | 321 | //- /foo/lib.rs |
295 | #[macro_export] | 322 | #[macro_export] |
@@ -312,7 +339,7 @@ define_fn!(foo); | |||
312 | //^^^ | 339 | //^^^ |
313 | 340 | ||
314 | fn bar() { | 341 | fn bar() { |
315 | <|>foo(); | 342 | $0foo(); |
316 | } | 343 | } |
317 | "#, | 344 | "#, |
318 | ); | 345 | ); |
@@ -331,7 +358,7 @@ macro_rules! define_fn { | |||
331 | //^^^^^^^^^^^^^ | 358 | //^^^^^^^^^^^^^ |
332 | 359 | ||
333 | fn bar() { | 360 | fn bar() { |
334 | <|>foo(); | 361 | $0foo(); |
335 | } | 362 | } |
336 | "#, | 363 | "#, |
337 | ); | 364 | ); |
@@ -347,7 +374,7 @@ macro_rules! foo {() => {0}} | |||
347 | 374 | ||
348 | fn bar() { | 375 | fn bar() { |
349 | match (0,1) { | 376 | match (0,1) { |
350 | (<|>foo!(), _) => {} | 377 | ($0foo!(), _) => {} |
351 | } | 378 | } |
352 | } | 379 | } |
353 | "#, | 380 | "#, |
@@ -363,7 +390,7 @@ macro_rules! foo {() => {0}} | |||
363 | //^^^ | 390 | //^^^ |
364 | fn bar() { | 391 | fn bar() { |
365 | match 0 { | 392 | match 0 { |
366 | <|>foo!() => {} | 393 | $0foo!() => {} |
367 | } | 394 | } |
368 | } | 395 | } |
369 | "#, | 396 | "#, |
@@ -375,7 +402,7 @@ fn bar() { | |||
375 | check( | 402 | check( |
376 | r#" | 403 | r#" |
377 | //- /lib.rs crate:main deps:foo | 404 | //- /lib.rs crate:main deps:foo |
378 | use foo as bar<|>; | 405 | use foo as bar$0; |
379 | 406 | ||
380 | //- /foo/lib.rs crate:foo | 407 | //- /foo/lib.rs crate:foo |
381 | // empty | 408 | // empty |
@@ -389,7 +416,7 @@ use foo as bar<|>; | |||
389 | check( | 416 | check( |
390 | r#" | 417 | r#" |
391 | //- /lib.rs crate:main deps:foo | 418 | //- /lib.rs crate:main deps:foo |
392 | use foo::foo as bar<|>; | 419 | use foo::foo as bar$0; |
393 | 420 | ||
394 | //- /foo/lib.rs crate:foo | 421 | //- /foo/lib.rs crate:foo |
395 | #[macro_export] | 422 | #[macro_export] |
@@ -410,7 +437,7 @@ impl Foo { | |||
410 | } | 437 | } |
411 | 438 | ||
412 | fn bar(foo: &Foo) { | 439 | fn bar(foo: &Foo) { |
413 | foo.frobnicate<|>(); | 440 | foo.frobnicate$0(); |
414 | } | 441 | } |
415 | "#, | 442 | "#, |
416 | ); | 443 | ); |
@@ -425,7 +452,7 @@ struct Foo { | |||
425 | } //^^^^ | 452 | } //^^^^ |
426 | 453 | ||
427 | fn bar(foo: &Foo) { | 454 | fn bar(foo: &Foo) { |
428 | foo.spam<|>; | 455 | foo.spam$0; |
429 | } | 456 | } |
430 | "#, | 457 | "#, |
431 | ); | 458 | ); |
@@ -442,7 +469,7 @@ struct Foo { | |||
442 | 469 | ||
443 | fn bar() -> Foo { | 470 | fn bar() -> Foo { |
444 | Foo { | 471 | Foo { |
445 | spam<|>: 0, | 472 | spam$0: 0, |
446 | } | 473 | } |
447 | } | 474 | } |
448 | "#, | 475 | "#, |
@@ -459,7 +486,7 @@ struct Foo { | |||
459 | } //^^^^ | 486 | } //^^^^ |
460 | 487 | ||
461 | fn bar(foo: Foo) -> Foo { | 488 | fn bar(foo: Foo) -> Foo { |
462 | let Foo { spam<|>: _, } = foo | 489 | let Foo { spam$0: _, } = foo |
463 | } | 490 | } |
464 | "#, | 491 | "#, |
465 | ); | 492 | ); |
@@ -474,7 +501,7 @@ struct Foo { spam: u32 } | |||
474 | //^^^^ | 501 | //^^^^ |
475 | 502 | ||
476 | fn bar() -> Foo { | 503 | fn bar() -> Foo { |
477 | Foo { spam<|>: m!() } | 504 | Foo { spam$0: m!() } |
478 | } | 505 | } |
479 | ", | 506 | ", |
480 | ); | 507 | ); |
@@ -489,7 +516,7 @@ struct Foo(u32); | |||
489 | 516 | ||
490 | fn bar() { | 517 | fn bar() { |
491 | let foo = Foo(0); | 518 | let foo = Foo(0); |
492 | foo.<|>0; | 519 | foo.$00; |
493 | } | 520 | } |
494 | "#, | 521 | "#, |
495 | ); | 522 | ); |
@@ -505,7 +532,7 @@ impl Foo { | |||
505 | } //^^^^^^^^^^ | 532 | } //^^^^^^^^^^ |
506 | 533 | ||
507 | fn bar(foo: &Foo) { | 534 | fn bar(foo: &Foo) { |
508 | Foo::frobnicate<|>(); | 535 | Foo::frobnicate$0(); |
509 | } | 536 | } |
510 | "#, | 537 | "#, |
511 | ); | 538 | ); |
@@ -520,7 +547,7 @@ trait Foo { | |||
520 | } //^^^^^^^^^^ | 547 | } //^^^^^^^^^^ |
521 | 548 | ||
522 | fn bar() { | 549 | fn bar() { |
523 | Foo::frobnicate<|>(); | 550 | Foo::frobnicate$0(); |
524 | } | 551 | } |
525 | "#, | 552 | "#, |
526 | ); | 553 | ); |
@@ -537,7 +564,7 @@ trait Trait { | |||
537 | impl Trait for Foo {} | 564 | impl Trait for Foo {} |
538 | 565 | ||
539 | fn bar() { | 566 | fn bar() { |
540 | Foo::frobnicate<|>(); | 567 | Foo::frobnicate$0(); |
541 | } | 568 | } |
542 | "#, | 569 | "#, |
543 | ); | 570 | ); |
@@ -551,7 +578,7 @@ struct Foo; | |||
551 | impl Foo { | 578 | impl Foo { |
552 | //^^^ | 579 | //^^^ |
553 | pub fn new() -> Self { | 580 | pub fn new() -> Self { |
554 | Self<|> {} | 581 | Self$0 {} |
555 | } | 582 | } |
556 | } | 583 | } |
557 | "#, | 584 | "#, |
@@ -561,7 +588,7 @@ impl Foo { | |||
561 | struct Foo; | 588 | struct Foo; |
562 | impl Foo { | 589 | impl Foo { |
563 | //^^^ | 590 | //^^^ |
564 | pub fn new() -> Self<|> { | 591 | pub fn new() -> Self$0 { |
565 | Self {} | 592 | Self {} |
566 | } | 593 | } |
567 | } | 594 | } |
@@ -573,7 +600,7 @@ impl Foo { | |||
573 | enum Foo { A } | 600 | enum Foo { A } |
574 | impl Foo { | 601 | impl Foo { |
575 | //^^^ | 602 | //^^^ |
576 | pub fn new() -> Self<|> { | 603 | pub fn new() -> Self$0 { |
577 | Foo::A | 604 | Foo::A |
578 | } | 605 | } |
579 | } | 606 | } |
@@ -585,7 +612,7 @@ impl Foo { | |||
585 | enum Foo { A } | 612 | enum Foo { A } |
586 | impl Foo { | 613 | impl Foo { |
587 | //^^^ | 614 | //^^^ |
588 | pub fn thing(a: &Self<|>) { | 615 | pub fn thing(a: &Self$0) { |
589 | } | 616 | } |
590 | } | 617 | } |
591 | "#, | 618 | "#, |
@@ -603,7 +630,7 @@ trait Make { | |||
603 | impl Make for Foo { | 630 | impl Make for Foo { |
604 | //^^^ | 631 | //^^^ |
605 | fn new() -> Self { | 632 | fn new() -> Self { |
606 | Self<|> {} | 633 | Self$0 {} |
607 | } | 634 | } |
608 | } | 635 | } |
609 | "#, | 636 | "#, |
@@ -617,7 +644,7 @@ trait Make { | |||
617 | } | 644 | } |
618 | impl Make for Foo { | 645 | impl Make for Foo { |
619 | //^^^ | 646 | //^^^ |
620 | fn new() -> Self<|> { | 647 | fn new() -> Self$0 { |
621 | Self {} | 648 | Self {} |
622 | } | 649 | } |
623 | } | 650 | } |
@@ -629,7 +656,7 @@ impl Make for Foo { | |||
629 | fn goto_def_when_used_on_definition_name_itself() { | 656 | fn goto_def_when_used_on_definition_name_itself() { |
630 | check( | 657 | check( |
631 | r#" | 658 | r#" |
632 | struct Foo<|> { value: u32 } | 659 | struct Foo$0 { value: u32 } |
633 | //^^^ | 660 | //^^^ |
634 | "#, | 661 | "#, |
635 | ); | 662 | ); |
@@ -637,21 +664,21 @@ struct Foo<|> { value: u32 } | |||
637 | check( | 664 | check( |
638 | r#" | 665 | r#" |
639 | struct Foo { | 666 | struct Foo { |
640 | field<|>: string, | 667 | field$0: string, |
641 | } //^^^^^ | 668 | } //^^^^^ |
642 | "#, | 669 | "#, |
643 | ); | 670 | ); |
644 | 671 | ||
645 | check( | 672 | check( |
646 | r#" | 673 | r#" |
647 | fn foo_test<|>() { } | 674 | fn foo_test$0() { } |
648 | //^^^^^^^^ | 675 | //^^^^^^^^ |
649 | "#, | 676 | "#, |
650 | ); | 677 | ); |
651 | 678 | ||
652 | check( | 679 | check( |
653 | r#" | 680 | r#" |
654 | enum Foo<|> { Variant } | 681 | enum Foo$0 { Variant } |
655 | //^^^ | 682 | //^^^ |
656 | "#, | 683 | "#, |
657 | ); | 684 | ); |
@@ -660,7 +687,7 @@ enum Foo<|> { Variant } | |||
660 | r#" | 687 | r#" |
661 | enum Foo { | 688 | enum Foo { |
662 | Variant1, | 689 | Variant1, |
663 | Variant2<|>, | 690 | Variant2$0, |
664 | //^^^^^^^^ | 691 | //^^^^^^^^ |
665 | Variant3, | 692 | Variant3, |
666 | } | 693 | } |
@@ -669,35 +696,35 @@ enum Foo { | |||
669 | 696 | ||
670 | check( | 697 | check( |
671 | r#" | 698 | r#" |
672 | static INNER<|>: &str = ""; | 699 | static INNER$0: &str = ""; |
673 | //^^^^^ | 700 | //^^^^^ |
674 | "#, | 701 | "#, |
675 | ); | 702 | ); |
676 | 703 | ||
677 | check( | 704 | check( |
678 | r#" | 705 | r#" |
679 | const INNER<|>: &str = ""; | 706 | const INNER$0: &str = ""; |
680 | //^^^^^ | 707 | //^^^^^ |
681 | "#, | 708 | "#, |
682 | ); | 709 | ); |
683 | 710 | ||
684 | check( | 711 | check( |
685 | r#" | 712 | r#" |
686 | type Thing<|> = Option<()>; | 713 | type Thing$0 = Option<()>; |
687 | //^^^^^ | 714 | //^^^^^ |
688 | "#, | 715 | "#, |
689 | ); | 716 | ); |
690 | 717 | ||
691 | check( | 718 | check( |
692 | r#" | 719 | r#" |
693 | trait Foo<|> { } | 720 | trait Foo$0 { } |
694 | //^^^ | 721 | //^^^ |
695 | "#, | 722 | "#, |
696 | ); | 723 | ); |
697 | 724 | ||
698 | check( | 725 | check( |
699 | r#" | 726 | r#" |
700 | mod bar<|> { } | 727 | mod bar$0 { } |
701 | //^^^ | 728 | //^^^ |
702 | "#, | 729 | "#, |
703 | ); | 730 | ); |
@@ -714,7 +741,7 @@ fn foo() {} | |||
714 | //^^^ | 741 | //^^^ |
715 | id! { | 742 | id! { |
716 | fn bar() { | 743 | fn bar() { |
717 | fo<|>o(); | 744 | fo$0o(); |
718 | } | 745 | } |
719 | } | 746 | } |
720 | mod confuse_index { fn foo(); } | 747 | mod confuse_index { fn foo(); } |
@@ -743,7 +770,7 @@ pub mod __export { | |||
743 | fn foo() -> i8 {} | 770 | fn foo() -> i8 {} |
744 | //^^^ | 771 | //^^^ |
745 | fn test() { | 772 | fn test() { |
746 | format!("{}", fo<|>o()) | 773 | format!("{}", fo$0o()) |
747 | } | 774 | } |
748 | "#, | 775 | "#, |
749 | ); | 776 | ); |
@@ -761,7 +788,7 @@ macro_rules! include {} | |||
761 | //^^^^^^^^^^^^^^^^^^^ | 788 | //^^^^^^^^^^^^^^^^^^^ |
762 | 789 | ||
763 | fn f() { | 790 | fn f() { |
764 | foo<|>(); | 791 | foo$0(); |
765 | } | 792 | } |
766 | 793 | ||
767 | mod confuse_index { | 794 | mod confuse_index { |
@@ -778,7 +805,7 @@ fn foo() {} | |||
778 | fn goto_for_type_param() { | 805 | fn goto_for_type_param() { |
779 | check( | 806 | check( |
780 | r#" | 807 | r#" |
781 | struct Foo<T: Clone> { t: <|>T } | 808 | struct Foo<T: Clone> { t: $0T } |
782 | //^ | 809 | //^ |
783 | "#, | 810 | "#, |
784 | ); | 811 | ); |
@@ -796,7 +823,7 @@ fn foo() { | |||
796 | let x = 1; | 823 | let x = 1; |
797 | //^ | 824 | //^ |
798 | id!({ | 825 | id!({ |
799 | let y = <|>x; | 826 | let y = $0x; |
800 | let z = y; | 827 | let z = y; |
801 | }); | 828 | }); |
802 | } | 829 | } |
@@ -814,7 +841,7 @@ fn foo() { | |||
814 | id!({ | 841 | id!({ |
815 | let y = x; | 842 | let y = x; |
816 | //^ | 843 | //^ |
817 | let z = <|>y; | 844 | let z = $0y; |
818 | }); | 845 | }); |
819 | } | 846 | } |
820 | "#, | 847 | "#, |
@@ -829,7 +856,7 @@ fn main() { | |||
829 | fn foo() { | 856 | fn foo() { |
830 | let x = 92; | 857 | let x = 92; |
831 | //^ | 858 | //^ |
832 | <|>x; | 859 | $0x; |
833 | } | 860 | } |
834 | } | 861 | } |
835 | "#, | 862 | "#, |
@@ -843,7 +870,7 @@ fn main() { | |||
843 | fn bar() { | 870 | fn bar() { |
844 | macro_rules! foo { () => { () } } | 871 | macro_rules! foo { () => { () } } |
845 | //^^^ | 872 | //^^^ |
846 | <|>foo!(); | 873 | $0foo!(); |
847 | } | 874 | } |
848 | "#, | 875 | "#, |
849 | ); | 876 | ); |
@@ -857,7 +884,7 @@ struct Foo { x: i32 } | |||
857 | fn main() { | 884 | fn main() { |
858 | let x = 92; | 885 | let x = 92; |
859 | //^ | 886 | //^ |
860 | Foo { x<|> }; | 887 | Foo { x$0 }; |
861 | } | 888 | } |
862 | "#, | 889 | "#, |
863 | ) | 890 | ) |
@@ -872,7 +899,7 @@ enum Foo { | |||
872 | } //^ | 899 | } //^ |
873 | fn baz(foo: Foo) { | 900 | fn baz(foo: Foo) { |
874 | match foo { | 901 | match foo { |
875 | Foo::Bar { x<|> } => x | 902 | Foo::Bar { x$0 } => x |
876 | }; | 903 | }; |
877 | } | 904 | } |
878 | "#, | 905 | "#, |
@@ -887,7 +914,7 @@ enum Foo { Bar } | |||
887 | //^^^ | 914 | //^^^ |
888 | impl Foo { | 915 | impl Foo { |
889 | fn baz(self) { | 916 | fn baz(self) { |
890 | match self { Self::Bar<|> => {} } | 917 | match self { Self::Bar$0 => {} } |
891 | } | 918 | } |
892 | } | 919 | } |
893 | "#, | 920 | "#, |
@@ -902,7 +929,7 @@ enum Foo { Bar { val: i32 } } | |||
902 | //^^^ | 929 | //^^^ |
903 | impl Foo { | 930 | impl Foo { |
904 | fn baz(self) -> i32 { | 931 | fn baz(self) -> i32 { |
905 | match self { Self::Bar<|> { val } => {} } | 932 | match self { Self::Bar$0 { val } => {} } |
906 | } | 933 | } |
907 | } | 934 | } |
908 | "#, | 935 | "#, |
@@ -916,7 +943,7 @@ impl Foo { | |||
916 | enum Foo { Bar } | 943 | enum Foo { Bar } |
917 | //^^^ | 944 | //^^^ |
918 | impl Foo { | 945 | impl Foo { |
919 | fn baz(self) { Self::Bar<|>; } | 946 | fn baz(self) { Self::Bar$0; } |
920 | } | 947 | } |
921 | "#, | 948 | "#, |
922 | ); | 949 | ); |
@@ -929,7 +956,7 @@ impl Foo { | |||
929 | enum Foo { Bar { val: i32 } } | 956 | enum Foo { Bar { val: i32 } } |
930 | //^^^ | 957 | //^^^ |
931 | impl Foo { | 958 | impl Foo { |
932 | fn baz(self) { Self::Bar<|> {val: 4}; } | 959 | fn baz(self) { Self::Bar$0 {val: 4}; } |
933 | } | 960 | } |
934 | "#, | 961 | "#, |
935 | ); | 962 | ); |
@@ -939,7 +966,7 @@ impl Foo { | |||
939 | fn goto_def_for_type_alias_generic_parameter() { | 966 | fn goto_def_for_type_alias_generic_parameter() { |
940 | check( | 967 | check( |
941 | r#" | 968 | r#" |
942 | type Alias<T> = T<|>; | 969 | type Alias<T> = T$0; |
943 | //^ | 970 | //^ |
944 | "#, | 971 | "#, |
945 | ) | 972 | ) |
@@ -950,7 +977,7 @@ type Alias<T> = T<|>; | |||
950 | check( | 977 | check( |
951 | r#" | 978 | r#" |
952 | //- /lib.rs | 979 | //- /lib.rs |
953 | foo::module<|>::mac!(); | 980 | foo::module$0::mac!(); |
954 | 981 | ||
955 | //- /foo/lib.rs | 982 | //- /foo/lib.rs |
956 | pub mod module { | 983 | pub mod module { |
@@ -972,7 +999,7 @@ trait Iterator { | |||
972 | //^^^^ | 999 | //^^^^ |
973 | } | 1000 | } |
974 | 1001 | ||
975 | fn f() -> impl Iterator<Item<|> = u8> {} | 1002 | fn f() -> impl Iterator<Item$0 = u8> {} |
976 | "#, | 1003 | "#, |
977 | ); | 1004 | ); |
978 | } | 1005 | } |
@@ -987,7 +1014,7 @@ trait Iterator { | |||
987 | type B; | 1014 | type B; |
988 | } | 1015 | } |
989 | 1016 | ||
990 | fn f() -> impl Iterator<A<|> = u8, B = ()> {} | 1017 | fn f() -> impl Iterator<A$0 = u8, B = ()> {} |
991 | "#, | 1018 | "#, |
992 | ); | 1019 | ); |
993 | check( | 1020 | check( |
@@ -998,7 +1025,7 @@ trait Iterator { | |||
998 | //^ | 1025 | //^ |
999 | } | 1026 | } |
1000 | 1027 | ||
1001 | fn f() -> impl Iterator<A = u8, B<|> = ()> {} | 1028 | fn f() -> impl Iterator<A = u8, B$0 = ()> {} |
1002 | "#, | 1029 | "#, |
1003 | ); | 1030 | ); |
1004 | } | 1031 | } |
@@ -1012,7 +1039,7 @@ trait Iterator { | |||
1012 | //^^^^ | 1039 | //^^^^ |
1013 | } | 1040 | } |
1014 | 1041 | ||
1015 | fn g() -> <() as Iterator<Item<|> = ()>>::Item {} | 1042 | fn g() -> <() as Iterator<Item$0 = ()>>::Item {} |
1016 | "#, | 1043 | "#, |
1017 | ); | 1044 | ); |
1018 | } | 1045 | } |
@@ -1027,7 +1054,7 @@ trait Iterator { | |||
1027 | type B; | 1054 | type B; |
1028 | } | 1055 | } |
1029 | 1056 | ||
1030 | fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {} | 1057 | fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {} |
1031 | "#, | 1058 | "#, |
1032 | ); | 1059 | ); |
1033 | check( | 1060 | check( |
@@ -1038,7 +1065,7 @@ trait Iterator { | |||
1038 | //^ | 1065 | //^ |
1039 | } | 1066 | } |
1040 | 1067 | ||
1041 | fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {} | 1068 | fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {} |
1042 | "#, | 1069 | "#, |
1043 | ); | 1070 | ); |
1044 | } | 1071 | } |
@@ -1052,7 +1079,7 @@ struct Foo {} | |||
1052 | impl Foo { | 1079 | impl Foo { |
1053 | fn bar(self: &Foo) { | 1080 | fn bar(self: &Foo) { |
1054 | //^^^^ | 1081 | //^^^^ |
1055 | let foo = sel<|>f; | 1082 | let foo = sel$0f; |
1056 | } | 1083 | } |
1057 | }"#, | 1084 | }"#, |
1058 | ) | 1085 | ) |
@@ -1065,7 +1092,7 @@ impl Foo { | |||
1065 | struct Foo {} | 1092 | struct Foo {} |
1066 | 1093 | ||
1067 | impl Foo { | 1094 | impl Foo { |
1068 | fn bar(&self<|>) { | 1095 | fn bar(&self$0) { |
1069 | //^^^^ | 1096 | //^^^^ |
1070 | } | 1097 | } |
1071 | }"#, | 1098 | }"#, |
@@ -1076,7 +1103,7 @@ impl Foo { | |||
1076 | fn goto_lifetime_param_on_decl() { | 1103 | fn goto_lifetime_param_on_decl() { |
1077 | check( | 1104 | check( |
1078 | r#" | 1105 | r#" |
1079 | fn foo<'foobar<|>>(_: &'foobar ()) { | 1106 | fn foo<'foobar$0>(_: &'foobar ()) { |
1080 | //^^^^^^^ | 1107 | //^^^^^^^ |
1081 | }"#, | 1108 | }"#, |
1082 | ) | 1109 | ) |
@@ -1086,7 +1113,7 @@ fn foo<'foobar<|>>(_: &'foobar ()) { | |||
1086 | fn goto_lifetime_param_decl() { | 1113 | fn goto_lifetime_param_decl() { |
1087 | check( | 1114 | check( |
1088 | r#" | 1115 | r#" |
1089 | fn foo<'foobar>(_: &'foobar<|> ()) { | 1116 | fn foo<'foobar>(_: &'foobar$0 ()) { |
1090 | //^^^^^^^ | 1117 | //^^^^^^^ |
1091 | }"#, | 1118 | }"#, |
1092 | ) | 1119 | ) |
@@ -1097,7 +1124,7 @@ fn foo<'foobar>(_: &'foobar<|> ()) { | |||
1097 | check( | 1124 | check( |
1098 | r#" | 1125 | r#" |
1099 | fn foo<'foobar>(_: &'foobar ()) { | 1126 | fn foo<'foobar>(_: &'foobar ()) { |
1100 | fn foo<'foobar>(_: &'foobar<|> ()) {} | 1127 | fn foo<'foobar>(_: &'foobar$0 ()) {} |
1101 | //^^^^^^^ | 1128 | //^^^^^^^ |
1102 | }"#, | 1129 | }"#, |
1103 | ) | 1130 | ) |
@@ -1108,13 +1135,13 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1108 | fn goto_lifetime_hrtb() { | 1135 | fn goto_lifetime_hrtb() { |
1109 | check( | 1136 | check( |
1110 | r#"trait Foo<T> {} | 1137 | r#"trait Foo<T> {} |
1111 | fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} | 1138 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} |
1112 | //^^ | 1139 | //^^ |
1113 | "#, | 1140 | "#, |
1114 | ); | 1141 | ); |
1115 | check( | 1142 | check( |
1116 | r#"trait Foo<T> {} | 1143 | r#"trait Foo<T> {} |
1117 | fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | 1144 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} |
1118 | //^^ | 1145 | //^^ |
1119 | "#, | 1146 | "#, |
1120 | ); | 1147 | ); |
@@ -1125,7 +1152,7 @@ fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | |||
1125 | fn goto_lifetime_hrtb_for_type() { | 1152 | fn goto_lifetime_hrtb_for_type() { |
1126 | check( | 1153 | check( |
1127 | r#"trait Foo<T> {} | 1154 | r#"trait Foo<T> {} |
1128 | fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} | 1155 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} |
1129 | //^^ | 1156 | //^^ |
1130 | "#, | 1157 | "#, |
1131 | ); | 1158 | ); |
@@ -1139,10 +1166,40 @@ fn foo<'foo>(_: &'foo ()) { | |||
1139 | 'foo: { | 1166 | 'foo: { |
1140 | //^^^^ | 1167 | //^^^^ |
1141 | 'bar: loop { | 1168 | 'bar: loop { |
1142 | break 'foo<|>; | 1169 | break 'foo$0; |
1143 | } | 1170 | } |
1144 | } | 1171 | } |
1145 | }"#, | 1172 | }"#, |
1146 | ) | 1173 | ) |
1147 | } | 1174 | } |
1175 | |||
1176 | #[test] | ||
1177 | fn goto_def_for_intra_doc_link_same_file() { | ||
1178 | check( | ||
1179 | r#" | ||
1180 | /// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar) | ||
1181 | pub fn bar() { } | ||
1182 | |||
1183 | /// You might want to see [`std::fs::read()`] too. | ||
1184 | pub fn foo() { } | ||
1185 | //^^^ | ||
1186 | |||
1187 | }"#, | ||
1188 | ) | ||
1189 | } | ||
1190 | |||
1191 | #[test] | ||
1192 | fn goto_def_for_intra_doc_link_inner() { | ||
1193 | check( | ||
1194 | r#" | ||
1195 | //- /main.rs | ||
1196 | mod m; | ||
1197 | struct S; | ||
1198 | //^ | ||
1199 | |||
1200 | //- /m.rs | ||
1201 | //! [`super::S$0`] | ||
1202 | "#, | ||
1203 | ) | ||
1204 | } | ||
1148 | } | 1205 | } |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index da9378a97..761a98b2c 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -107,7 +107,7 @@ mod tests { | |||
107 | fn goto_implementation_works() { | 107 | fn goto_implementation_works() { |
108 | check( | 108 | check( |
109 | r#" | 109 | r#" |
110 | struct Foo<|>; | 110 | struct Foo$0; |
111 | impl Foo {} | 111 | impl Foo {} |
112 | //^^^ | 112 | //^^^ |
113 | "#, | 113 | "#, |
@@ -118,7 +118,7 @@ impl Foo {} | |||
118 | fn goto_implementation_works_multiple_blocks() { | 118 | fn goto_implementation_works_multiple_blocks() { |
119 | check( | 119 | check( |
120 | r#" | 120 | r#" |
121 | struct Foo<|>; | 121 | struct Foo$0; |
122 | impl Foo {} | 122 | impl Foo {} |
123 | //^^^ | 123 | //^^^ |
124 | impl Foo {} | 124 | impl Foo {} |
@@ -131,7 +131,7 @@ impl Foo {} | |||
131 | fn goto_implementation_works_multiple_mods() { | 131 | fn goto_implementation_works_multiple_mods() { |
132 | check( | 132 | check( |
133 | r#" | 133 | r#" |
134 | struct Foo<|>; | 134 | struct Foo$0; |
135 | mod a { | 135 | mod a { |
136 | impl super::Foo {} | 136 | impl super::Foo {} |
137 | //^^^^^^^^^^ | 137 | //^^^^^^^^^^ |
@@ -149,7 +149,7 @@ mod b { | |||
149 | check( | 149 | check( |
150 | r#" | 150 | r#" |
151 | //- /lib.rs | 151 | //- /lib.rs |
152 | struct Foo<|>; | 152 | struct Foo$0; |
153 | mod a; | 153 | mod a; |
154 | mod b; | 154 | mod b; |
155 | //- /a.rs | 155 | //- /a.rs |
@@ -166,7 +166,7 @@ impl crate::Foo {} | |||
166 | fn goto_implementation_for_trait() { | 166 | fn goto_implementation_for_trait() { |
167 | check( | 167 | check( |
168 | r#" | 168 | r#" |
169 | trait T<|> {} | 169 | trait T$0 {} |
170 | struct Foo; | 170 | struct Foo; |
171 | impl T for Foo {} | 171 | impl T for Foo {} |
172 | //^^^ | 172 | //^^^ |
@@ -179,7 +179,7 @@ impl T for Foo {} | |||
179 | check( | 179 | check( |
180 | r#" | 180 | r#" |
181 | //- /lib.rs | 181 | //- /lib.rs |
182 | trait T<|> {}; | 182 | trait T$0 {}; |
183 | struct Foo; | 183 | struct Foo; |
184 | mod a; | 184 | mod a; |
185 | mod b; | 185 | mod b; |
@@ -199,7 +199,7 @@ impl crate::T for crate::Foo {} | |||
199 | r#" | 199 | r#" |
200 | //- /lib.rs | 200 | //- /lib.rs |
201 | trait T {} | 201 | trait T {} |
202 | struct Foo<|>; | 202 | struct Foo$0; |
203 | impl Foo {} | 203 | impl Foo {} |
204 | //^^^ | 204 | //^^^ |
205 | impl T for Foo {} | 205 | impl T for Foo {} |
@@ -216,7 +216,7 @@ impl T for &Foo {} | |||
216 | r#" | 216 | r#" |
217 | #[derive(Copy)] | 217 | #[derive(Copy)] |
218 | //^^^^^^^^^^^^^^^ | 218 | //^^^^^^^^^^^^^^^ |
219 | struct Foo<|>; | 219 | struct Foo$0; |
220 | 220 | ||
221 | mod marker { | 221 | mod marker { |
222 | trait Copy {} | 222 | trait Copy {} |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 7e84e06be..369a59820 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -76,7 +76,7 @@ mod tests { | |||
76 | struct Foo; | 76 | struct Foo; |
77 | //^^^ | 77 | //^^^ |
78 | fn foo() { | 78 | fn foo() { |
79 | let f: Foo; f<|> | 79 | let f: Foo; f$0 |
80 | } | 80 | } |
81 | "#, | 81 | "#, |
82 | ); | 82 | ); |
@@ -89,7 +89,7 @@ fn foo() { | |||
89 | struct Foo; | 89 | struct Foo; |
90 | //^^^ | 90 | //^^^ |
91 | fn foo() { | 91 | fn foo() { |
92 | let f: &Foo; f<|> | 92 | let f: &Foo; f$0 |
93 | } | 93 | } |
94 | "#, | 94 | "#, |
95 | ); | 95 | ); |
@@ -103,7 +103,7 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | |||
103 | struct Foo {} | 103 | struct Foo {} |
104 | //^^^ | 104 | //^^^ |
105 | id! { | 105 | id! { |
106 | fn bar() { let f<|> = Foo {}; } | 106 | fn bar() { let f$0 = Foo {}; } |
107 | } | 107 | } |
108 | "#, | 108 | "#, |
109 | ); | 109 | ); |
@@ -115,7 +115,7 @@ id! { | |||
115 | r#" | 115 | r#" |
116 | struct Foo; | 116 | struct Foo; |
117 | //^^^ | 117 | //^^^ |
118 | fn foo(<|>f: Foo) {} | 118 | fn foo($0f: Foo) {} |
119 | "#, | 119 | "#, |
120 | ); | 120 | ); |
121 | } | 121 | } |
@@ -129,7 +129,7 @@ struct Foo; | |||
129 | struct Bar(Foo); | 129 | struct Bar(Foo); |
130 | fn foo() { | 130 | fn foo() { |
131 | let bar = Bar(Foo); | 131 | let bar = Bar(Foo); |
132 | bar.<|>0; | 132 | bar.$00; |
133 | } | 133 | } |
134 | "#, | 134 | "#, |
135 | ); | 135 | ); |
@@ -142,7 +142,7 @@ fn foo() { | |||
142 | struct Foo; | 142 | struct Foo; |
143 | //^^^ | 143 | //^^^ |
144 | impl Foo { | 144 | impl Foo { |
145 | fn f(&self<|>) {} | 145 | fn f(&self$0) {} |
146 | } | 146 | } |
147 | "#, | 147 | "#, |
148 | ) | 148 | ) |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index a12a2475e..2024acd94 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use hir::{ | 1 | use hir::{ |
2 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module, | 2 | Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, |
3 | ModuleDef, ModuleSource, Semantics, | 3 | HirDisplay, Module, ModuleDef, ModuleSource, Semantics, |
4 | }; | 4 | }; |
5 | use ide_db::base_db::SourceDatabase; | 5 | use ide_db::base_db::SourceDatabase; |
6 | use ide_db::{ | 6 | use ide_db::{ |
@@ -17,7 +17,7 @@ use crate::{ | |||
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, |
20 | runnables::{runnable, runnable_fn}, | 20 | runnables::{runnable_fn, runnable_mod}, |
21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -134,17 +134,14 @@ pub(crate) fn hover( | |||
134 | return None; | 134 | return None; |
135 | } | 135 | } |
136 | 136 | ||
137 | let node = token.ancestors().find(|n| { | 137 | let node = token |
138 | ast::Expr::can_cast(n.kind()) | 138 | .ancestors() |
139 | || ast::Pat::can_cast(n.kind()) | 139 | .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?; |
140 | || ast::SelfParam::can_cast(n.kind()) | ||
141 | })?; | ||
142 | 140 | ||
143 | let ty = match_ast! { | 141 | let ty = match_ast! { |
144 | match node { | 142 | match node { |
145 | ast::Expr(it) => sema.type_of_expr(&it)?, | 143 | ast::Expr(it) => sema.type_of_expr(&it)?, |
146 | ast::Pat(it) => sema.type_of_pat(&it)?, | 144 | ast::Pat(it) => sema.type_of_pat(&it)?, |
147 | ast::SelfParam(self_param) => sema.type_of_self(&self_param)?, | ||
148 | // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. | 145 | // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. |
149 | // (e.g expanding a builtin macro). So we give up here. | 146 | // (e.g expanding a builtin macro). So we give up here. |
150 | ast::MacroCall(_it) => return None, | 147 | ast::MacroCall(_it) => return None, |
@@ -175,12 +172,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
175 | Definition::SelfType(it) => it.target_ty(db).as_adt(), | 172 | Definition::SelfType(it) => it.target_ty(db).as_adt(), |
176 | _ => None, | 173 | _ => None, |
177 | }?; | 174 | }?; |
178 | match adt { | 175 | adt.try_to_nav(db).map(to_action) |
179 | Adt::Struct(it) => it.try_to_nav(db), | ||
180 | Adt::Union(it) => it.try_to_nav(db), | ||
181 | Adt::Enum(it) => it.try_to_nav(db), | ||
182 | } | ||
183 | .map(to_action) | ||
184 | } | 176 | } |
185 | 177 | ||
186 | fn runnable_action( | 178 | fn runnable_action( |
@@ -192,7 +184,7 @@ fn runnable_action( | |||
192 | Definition::ModuleDef(it) => match it { | 184 | Definition::ModuleDef(it) => match it { |
193 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | 185 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { |
194 | ModuleSource::Module(it) => { | 186 | ModuleSource::Module(it) => { |
195 | runnable(&sema, it.syntax().clone()).map(|it| HoverAction::Runnable(it)) | 187 | runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)) |
196 | } | 188 | } |
197 | _ => None, | 189 | _ => None, |
198 | }, | 190 | }, |
@@ -220,12 +212,12 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
220 | } | 212 | } |
221 | }; | 213 | }; |
222 | 214 | ||
223 | if let Definition::TypeParam(it) = def { | 215 | if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { |
224 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | 216 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); |
225 | } else { | 217 | } else { |
226 | let ty = match def { | 218 | let ty = match def { |
227 | Definition::Local(it) => it.ty(db), | 219 | Definition::Local(it) => it.ty(db), |
228 | Definition::ConstParam(it) => it.ty(db), | 220 | Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), |
229 | _ => return None, | 221 | _ => return None, |
230 | }; | 222 | }; |
231 | 223 | ||
@@ -357,9 +349,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
357 | }) | 349 | }) |
358 | } | 350 | } |
359 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 351 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
360 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | 352 | Definition::GenericParam(it) => match it { |
361 | Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), | 353 | GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))), |
362 | Definition::ConstParam(it) => from_def_source(db, it, None), | 354 | GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), |
355 | GenericParam::ConstParam(it) => from_def_source(db, it, None), | ||
356 | }, | ||
363 | }; | 357 | }; |
364 | 358 | ||
365 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 359 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
@@ -389,7 +383,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
389 | return tokens.max_by_key(priority); | 383 | return tokens.max_by_key(priority); |
390 | fn priority(n: &SyntaxToken) -> usize { | 384 | fn priority(n: &SyntaxToken) -> usize { |
391 | match n.kind() { | 385 | match n.kind() { |
392 | IDENT | INT_NUMBER | LIFETIME_IDENT => 3, | 386 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 3, |
393 | T!['('] | T![')'] => 2, | 387 | T!['('] | T![')'] => 2, |
394 | kind if kind.is_trivia() => 0, | 388 | kind if kind.is_trivia() => 0, |
395 | _ => 1, | 389 | _ => 1, |
@@ -457,7 +451,7 @@ mod tests { | |||
457 | pub fn foo() -> u32 { 1 } | 451 | pub fn foo() -> u32 { 1 } |
458 | 452 | ||
459 | fn main() { | 453 | fn main() { |
460 | let foo_test = foo()<|>; | 454 | let foo_test = foo()$0; |
461 | } | 455 | } |
462 | "#, | 456 | "#, |
463 | expect![[r#" | 457 | expect![[r#" |
@@ -476,7 +470,7 @@ fn main() { | |||
476 | pub fn foo() -> u32 { 1 } | 470 | pub fn foo() -> u32 { 1 } |
477 | 471 | ||
478 | fn main() { | 472 | fn main() { |
479 | let foo_test = foo()<|>; | 473 | let foo_test = foo()$0; |
480 | } | 474 | } |
481 | "#, | 475 | "#, |
482 | expect![[r#" | 476 | expect![[r#" |
@@ -506,7 +500,7 @@ fn main() { | |||
506 | Option::Some(*memo + value) | 500 | Option::Some(*memo + value) |
507 | }; | 501 | }; |
508 | let number = 5u32; | 502 | let number = 5u32; |
509 | let mut iter<|> = scan(OtherStruct { i: num }, closure, number); | 503 | let mut iter$0 = scan(OtherStruct { i: num }, closure, number); |
510 | } | 504 | } |
511 | "#, | 505 | "#, |
512 | expect![[r#" | 506 | expect![[r#" |
@@ -526,7 +520,7 @@ fn main() { | |||
526 | r#" | 520 | r#" |
527 | pub fn foo() -> u32 { 1 } | 521 | pub fn foo() -> u32 { 1 } |
528 | 522 | ||
529 | fn main() { let foo_test = fo<|>o(); } | 523 | fn main() { let foo_test = fo$0o(); } |
530 | "#, | 524 | "#, |
531 | expect![[r#" | 525 | expect![[r#" |
532 | *foo* | 526 | *foo* |
@@ -558,7 +552,7 @@ mod a; | |||
558 | mod b; | 552 | mod b; |
559 | mod c; | 553 | mod c; |
560 | 554 | ||
561 | fn main() { let foo_test = fo<|>o(); } | 555 | fn main() { let foo_test = fo$0o(); } |
562 | "#, | 556 | "#, |
563 | expect![[r#" | 557 | expect![[r#" |
564 | *foo* | 558 | *foo* |
@@ -575,7 +569,7 @@ fn main() { let foo_test = fo<|>o(); } | |||
575 | r#" | 569 | r#" |
576 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } | 570 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } |
577 | 571 | ||
578 | fn main() { let foo_test = fo<|>o(); } | 572 | fn main() { let foo_test = fo$0o(); } |
579 | "#, | 573 | "#, |
580 | expect![[r#" | 574 | expect![[r#" |
581 | *foo* | 575 | *foo* |
@@ -595,7 +589,7 @@ fn main() { let foo_test = fo<|>o(); } | |||
595 | fn hover_shows_fn_signature_on_fn_name() { | 589 | fn hover_shows_fn_signature_on_fn_name() { |
596 | check( | 590 | check( |
597 | r#" | 591 | r#" |
598 | pub fn foo<|>(a: u32, b: u32) -> u32 {} | 592 | pub fn foo$0(a: u32, b: u32) -> u32 {} |
599 | 593 | ||
600 | fn main() { } | 594 | fn main() { } |
601 | "#, | 595 | "#, |
@@ -623,7 +617,7 @@ fn main() { } | |||
623 | /// # | 617 | /// # |
624 | /// foo(Path::new("hello, world!")) | 618 | /// foo(Path::new("hello, world!")) |
625 | /// ``` | 619 | /// ``` |
626 | pub fn foo<|>(_: &Path) {} | 620 | pub fn foo$0(_: &Path) {} |
627 | 621 | ||
628 | fn main() { } | 622 | fn main() { } |
629 | "#, | 623 | "#, |
@@ -656,7 +650,7 @@ fn main() { } | |||
656 | check( | 650 | check( |
657 | r##" | 651 | r##" |
658 | #[doc = r#"Raw string doc attr"#] | 652 | #[doc = r#"Raw string doc attr"#] |
659 | pub fn foo<|>(_: &Path) {} | 653 | pub fn foo$0(_: &Path) {} |
660 | 654 | ||
661 | fn main() { } | 655 | fn main() { } |
662 | "##, | 656 | "##, |
@@ -686,7 +680,7 @@ fn main() { } | |||
686 | struct Foo { field_a: u32 } | 680 | struct Foo { field_a: u32 } |
687 | 681 | ||
688 | fn main() { | 682 | fn main() { |
689 | let foo = Foo { field_a<|>: 0, }; | 683 | let foo = Foo { field_a$0: 0, }; |
690 | } | 684 | } |
691 | "#, | 685 | "#, |
692 | expect![[r#" | 686 | expect![[r#" |
@@ -705,7 +699,7 @@ fn main() { | |||
705 | // Hovering over the field in the definition | 699 | // Hovering over the field in the definition |
706 | check( | 700 | check( |
707 | r#" | 701 | r#" |
708 | struct Foo { field_a<|>: u32 } | 702 | struct Foo { field_a$0: u32 } |
709 | 703 | ||
710 | fn main() { | 704 | fn main() { |
711 | let foo = Foo { field_a: 0 }; | 705 | let foo = Foo { field_a: 0 }; |
@@ -728,7 +722,7 @@ fn main() { | |||
728 | #[test] | 722 | #[test] |
729 | fn hover_const_static() { | 723 | fn hover_const_static() { |
730 | check( | 724 | check( |
731 | r#"const foo<|>: u32 = 123;"#, | 725 | r#"const foo$0: u32 = 123;"#, |
732 | expect![[r#" | 726 | expect![[r#" |
733 | *foo* | 727 | *foo* |
734 | 728 | ||
@@ -742,7 +736,7 @@ fn main() { | |||
742 | "#]], | 736 | "#]], |
743 | ); | 737 | ); |
744 | check( | 738 | check( |
745 | r#"static foo<|>: u32 = 456;"#, | 739 | r#"static foo$0: u32 = 456;"#, |
746 | expect![[r#" | 740 | expect![[r#" |
747 | *foo* | 741 | *foo* |
748 | 742 | ||
@@ -764,7 +758,7 @@ fn main() { | |||
764 | struct Test<K, T = u8> { k: K, t: T } | 758 | struct Test<K, T = u8> { k: K, t: T } |
765 | 759 | ||
766 | fn main() { | 760 | fn main() { |
767 | let zz<|> = Test { t: 23u8, k: 33 }; | 761 | let zz$0 = Test { t: 23u8, k: 33 }; |
768 | }"#, | 762 | }"#, |
769 | expect![[r#" | 763 | expect![[r#" |
770 | *zz* | 764 | *zz* |
@@ -783,7 +777,7 @@ fn main() { | |||
783 | enum Option<T> { Some(T) } | 777 | enum Option<T> { Some(T) } |
784 | use Option::Some; | 778 | use Option::Some; |
785 | 779 | ||
786 | fn main() { So<|>me(12); } | 780 | fn main() { So$0me(12); } |
787 | "#, | 781 | "#, |
788 | expect![[r#" | 782 | expect![[r#" |
789 | *Some* | 783 | *Some* |
@@ -803,7 +797,7 @@ fn main() { So<|>me(12); } | |||
803 | enum Option<T> { Some(T) } | 797 | enum Option<T> { Some(T) } |
804 | use Option::Some; | 798 | use Option::Some; |
805 | 799 | ||
806 | fn main() { let b<|>ar = Some(12); } | 800 | fn main() { let b$0ar = Some(12); } |
807 | "#, | 801 | "#, |
808 | expect![[r#" | 802 | expect![[r#" |
809 | *bar* | 803 | *bar* |
@@ -821,7 +815,7 @@ fn main() { let b<|>ar = Some(12); } | |||
821 | r#" | 815 | r#" |
822 | enum Option<T> { | 816 | enum Option<T> { |
823 | /// The None variant | 817 | /// The None variant |
824 | Non<|>e | 818 | Non$0e |
825 | } | 819 | } |
826 | "#, | 820 | "#, |
827 | expect![[r#" | 821 | expect![[r#" |
@@ -848,7 +842,7 @@ enum Option<T> { | |||
848 | Some(T) | 842 | Some(T) |
849 | } | 843 | } |
850 | fn main() { | 844 | fn main() { |
851 | let s = Option::Som<|>e(12); | 845 | let s = Option::Som$0e(12); |
852 | } | 846 | } |
853 | "#, | 847 | "#, |
854 | expect![[r#" | 848 | expect![[r#" |
@@ -872,7 +866,7 @@ fn main() { | |||
872 | #[test] | 866 | #[test] |
873 | fn hover_for_local_variable() { | 867 | fn hover_for_local_variable() { |
874 | check( | 868 | check( |
875 | r#"fn func(foo: i32) { fo<|>o; }"#, | 869 | r#"fn func(foo: i32) { fo$0o; }"#, |
876 | expect![[r#" | 870 | expect![[r#" |
877 | *foo* | 871 | *foo* |
878 | 872 | ||
@@ -886,7 +880,7 @@ fn main() { | |||
886 | #[test] | 880 | #[test] |
887 | fn hover_for_local_variable_pat() { | 881 | fn hover_for_local_variable_pat() { |
888 | check( | 882 | check( |
889 | r#"fn func(fo<|>o: i32) {}"#, | 883 | r#"fn func(fo$0o: i32) {}"#, |
890 | expect![[r#" | 884 | expect![[r#" |
891 | *foo* | 885 | *foo* |
892 | 886 | ||
@@ -900,7 +894,7 @@ fn main() { | |||
900 | #[test] | 894 | #[test] |
901 | fn hover_local_var_edge() { | 895 | fn hover_local_var_edge() { |
902 | check( | 896 | check( |
903 | r#"fn func(foo: i32) { if true { <|>foo; }; }"#, | 897 | r#"fn func(foo: i32) { if true { $0foo; }; }"#, |
904 | expect![[r#" | 898 | expect![[r#" |
905 | *foo* | 899 | *foo* |
906 | 900 | ||
@@ -914,7 +908,7 @@ fn main() { | |||
914 | #[test] | 908 | #[test] |
915 | fn hover_for_param_edge() { | 909 | fn hover_for_param_edge() { |
916 | check( | 910 | check( |
917 | r#"fn func(<|>foo: i32) {}"#, | 911 | r#"fn func($0foo: i32) {}"#, |
918 | expect![[r#" | 912 | expect![[r#" |
919 | *foo* | 913 | *foo* |
920 | 914 | ||
@@ -934,7 +928,7 @@ fn main() { | |||
934 | trait DerefMut { | 928 | trait DerefMut { |
935 | type Target: ?Sized; | 929 | type Target: ?Sized; |
936 | } | 930 | } |
937 | fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, | 931 | fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, |
938 | expect![[r#" | 932 | expect![[r#" |
939 | *_x* | 933 | *_x* |
940 | 934 | ||
@@ -955,7 +949,7 @@ impl Thing { | |||
955 | fn new() -> Thing { Thing { x: 0 } } | 949 | fn new() -> Thing { Thing { x: 0 } } |
956 | } | 950 | } |
957 | 951 | ||
958 | fn main() { let foo_<|>test = Thing::new(); } | 952 | fn main() { let foo_$0test = Thing::new(); } |
959 | "#, | 953 | "#, |
960 | expect![[r#" | 954 | expect![[r#" |
961 | *foo_test* | 955 | *foo_test* |
@@ -979,7 +973,7 @@ mod wrapper { | |||
979 | } | 973 | } |
980 | } | 974 | } |
981 | 975 | ||
982 | fn main() { let foo_test = wrapper::Thing::new<|>(); } | 976 | fn main() { let foo_test = wrapper::Thing::new$0(); } |
983 | "#, | 977 | "#, |
984 | expect![[r#" | 978 | expect![[r#" |
985 | *new* | 979 | *new* |
@@ -1006,7 +1000,7 @@ impl X { | |||
1006 | 1000 | ||
1007 | fn main() { | 1001 | fn main() { |
1008 | match 1 { | 1002 | match 1 { |
1009 | X::C<|> => {}, | 1003 | X::C$0 => {}, |
1010 | 2 => {}, | 1004 | 2 => {}, |
1011 | _ => {} | 1005 | _ => {} |
1012 | }; | 1006 | }; |
@@ -1032,7 +1026,7 @@ fn main() { | |||
1032 | r#" | 1026 | r#" |
1033 | struct Thing { x: u32 } | 1027 | struct Thing { x: u32 } |
1034 | impl Thing { | 1028 | impl Thing { |
1035 | fn new() -> Self { Self<|> { x: 0 } } | 1029 | fn new() -> Self { Self$0 { x: 0 } } |
1036 | } | 1030 | } |
1037 | "#, | 1031 | "#, |
1038 | expect![[r#" | 1032 | expect![[r#" |
@@ -1051,7 +1045,7 @@ impl Thing { | |||
1051 | r#" | 1045 | r#" |
1052 | struct Thing { x: u32 } | 1046 | struct Thing { x: u32 } |
1053 | impl Thing { | 1047 | impl Thing { |
1054 | fn new() -> Self<|> { Self { x: 0 } } | 1048 | fn new() -> Self$0 { Self { x: 0 } } |
1055 | } | 1049 | } |
1056 | "#, | 1050 | "#, |
1057 | expect![[r#" | 1051 | expect![[r#" |
@@ -1070,7 +1064,7 @@ impl Thing { | |||
1070 | r#" | 1064 | r#" |
1071 | enum Thing { A } | 1065 | enum Thing { A } |
1072 | impl Thing { | 1066 | impl Thing { |
1073 | pub fn new() -> Self<|> { Thing::A } | 1067 | pub fn new() -> Self$0 { Thing::A } |
1074 | } | 1068 | } |
1075 | "#, | 1069 | "#, |
1076 | expect![[r#" | 1070 | expect![[r#" |
@@ -1089,7 +1083,7 @@ impl Thing { | |||
1089 | r#" | 1083 | r#" |
1090 | enum Thing { A } | 1084 | enum Thing { A } |
1091 | impl Thing { | 1085 | impl Thing { |
1092 | pub fn thing(a: Self<|>) {} | 1086 | pub fn thing(a: Self$0) {} |
1093 | } | 1087 | } |
1094 | "#, | 1088 | "#, |
1095 | expect![[r#" | 1089 | expect![[r#" |
@@ -1114,7 +1108,7 @@ fn x() {} | |||
1114 | 1108 | ||
1115 | fn y() { | 1109 | fn y() { |
1116 | let x = 0i32; | 1110 | let x = 0i32; |
1117 | x<|>; | 1111 | x$0; |
1118 | } | 1112 | } |
1119 | "#, | 1113 | "#, |
1120 | expect![[r#" | 1114 | expect![[r#" |
@@ -1133,7 +1127,7 @@ fn y() { | |||
1133 | r#" | 1127 | r#" |
1134 | macro_rules! foo { () => {} } | 1128 | macro_rules! foo { () => {} } |
1135 | 1129 | ||
1136 | fn f() { fo<|>o!(); } | 1130 | fn f() { fo$0o!(); } |
1137 | "#, | 1131 | "#, |
1138 | expect![[r#" | 1132 | expect![[r#" |
1139 | *foo* | 1133 | *foo* |
@@ -1152,7 +1146,7 @@ fn f() { fo<|>o!(); } | |||
1152 | #[test] | 1146 | #[test] |
1153 | fn test_hover_tuple_field() { | 1147 | fn test_hover_tuple_field() { |
1154 | check( | 1148 | check( |
1155 | r#"struct TS(String, i32<|>);"#, | 1149 | r#"struct TS(String, i32$0);"#, |
1156 | expect![[r#" | 1150 | expect![[r#" |
1157 | *i32* | 1151 | *i32* |
1158 | 1152 | ||
@@ -1170,7 +1164,7 @@ fn f() { fo<|>o!(); } | |||
1170 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 1164 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
1171 | fn foo() {} | 1165 | fn foo() {} |
1172 | id! { | 1166 | id! { |
1173 | fn bar() { fo<|>o(); } | 1167 | fn bar() { fo$0o(); } |
1174 | } | 1168 | } |
1175 | "#, | 1169 | "#, |
1176 | expect![[r#" | 1170 | expect![[r#" |
@@ -1192,7 +1186,7 @@ id! { | |||
1192 | check( | 1186 | check( |
1193 | r#" | 1187 | r#" |
1194 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 1188 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
1195 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 1189 | fn foo(bar:u32) { let a = id!(ba$0r); } |
1196 | "#, | 1190 | "#, |
1197 | expect![[r#" | 1191 | expect![[r#" |
1198 | *bar* | 1192 | *bar* |
@@ -1210,7 +1204,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); } | |||
1210 | r#" | 1204 | r#" |
1211 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } | 1205 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } |
1212 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } | 1206 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } |
1213 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 1207 | fn foo(bar:u32) { let a = id!(ba$0r); } |
1214 | "#, | 1208 | "#, |
1215 | expect![[r#" | 1209 | expect![[r#" |
1216 | *bar* | 1210 | *bar* |
@@ -1229,7 +1223,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); } | |||
1229 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } | 1223 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } |
1230 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } | 1224 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } |
1231 | fn bar() -> u32 { 0 } | 1225 | fn bar() -> u32 { 0 } |
1232 | fn foo() { let a = id!([0u32, bar(<|>)] ); } | 1226 | fn foo() { let a = id!([0u32, bar($0)] ); } |
1233 | "#, | 1227 | "#, |
1234 | expect![[r#" | 1228 | expect![[r#" |
1235 | *bar()* | 1229 | *bar()* |
@@ -1247,7 +1241,7 @@ fn foo() { let a = id!([0u32, bar(<|>)] ); } | |||
1247 | macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } | 1241 | macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } |
1248 | fn foo() { | 1242 | fn foo() { |
1249 | let mastered_for_itunes = ""; | 1243 | let mastered_for_itunes = ""; |
1250 | let _ = arr!("Tr<|>acks", &mastered_for_itunes); | 1244 | let _ = arr!("Tr$0acks", &mastered_for_itunes); |
1251 | } | 1245 | } |
1252 | "#, | 1246 | "#, |
1253 | expect![[r#" | 1247 | expect![[r#" |
@@ -1268,7 +1262,7 @@ macro_rules! assert {} | |||
1268 | 1262 | ||
1269 | fn bar() -> bool { true } | 1263 | fn bar() -> bool { true } |
1270 | fn foo() { | 1264 | fn foo() { |
1271 | assert!(ba<|>r()); | 1265 | assert!(ba$0r()); |
1272 | } | 1266 | } |
1273 | "#, | 1267 | "#, |
1274 | expect![[r#" | 1268 | expect![[r#" |
@@ -1293,7 +1287,7 @@ fn foo() { | |||
1293 | macro_rules! format {} | 1287 | macro_rules! format {} |
1294 | 1288 | ||
1295 | fn foo() { | 1289 | fn foo() { |
1296 | format!("hel<|>lo {}", 0); | 1290 | format!("hel$0lo {}", 0); |
1297 | } | 1291 | } |
1298 | "#, | 1292 | "#, |
1299 | ); | 1293 | ); |
@@ -1306,7 +1300,7 @@ fn foo() { | |||
1306 | /// <- `\u{3000}` here | 1300 | /// <- `\u{3000}` here |
1307 | fn foo() { } | 1301 | fn foo() { } |
1308 | 1302 | ||
1309 | fn bar() { fo<|>o(); } | 1303 | fn bar() { fo$0o(); } |
1310 | ", | 1304 | ", |
1311 | expect![[r#" | 1305 | expect![[r#" |
1312 | *foo* | 1306 | *foo* |
@@ -1329,7 +1323,7 @@ fn bar() { fo<|>o(); } | |||
1329 | #[test] | 1323 | #[test] |
1330 | fn test_hover_function_show_qualifiers() { | 1324 | fn test_hover_function_show_qualifiers() { |
1331 | check( | 1325 | check( |
1332 | r#"async fn foo<|>() {}"#, | 1326 | r#"async fn foo$0() {}"#, |
1333 | expect![[r#" | 1327 | expect![[r#" |
1334 | *foo* | 1328 | *foo* |
1335 | 1329 | ||
@@ -1343,7 +1337,7 @@ fn bar() { fo<|>o(); } | |||
1343 | "#]], | 1337 | "#]], |
1344 | ); | 1338 | ); |
1345 | check( | 1339 | check( |
1346 | r#"pub const unsafe fn foo<|>() {}"#, | 1340 | r#"pub const unsafe fn foo$0() {}"#, |
1347 | expect![[r#" | 1341 | expect![[r#" |
1348 | *foo* | 1342 | *foo* |
1349 | 1343 | ||
@@ -1357,7 +1351,7 @@ fn bar() { fo<|>o(); } | |||
1357 | "#]], | 1351 | "#]], |
1358 | ); | 1352 | ); |
1359 | check( | 1353 | check( |
1360 | r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, | 1354 | r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#, |
1361 | expect![[r#" | 1355 | expect![[r#" |
1362 | *foo* | 1356 | *foo* |
1363 | 1357 | ||
@@ -1375,7 +1369,7 @@ fn bar() { fo<|>o(); } | |||
1375 | #[test] | 1369 | #[test] |
1376 | fn test_hover_trait_show_qualifiers() { | 1370 | fn test_hover_trait_show_qualifiers() { |
1377 | check_actions( | 1371 | check_actions( |
1378 | r"unsafe trait foo<|>() {}", | 1372 | r"unsafe trait foo$0() {}", |
1379 | expect![[r#" | 1373 | expect![[r#" |
1380 | [ | 1374 | [ |
1381 | Implementation( | 1375 | Implementation( |
@@ -1396,7 +1390,7 @@ fn bar() { fo<|>o(); } | |||
1396 | check( | 1390 | check( |
1397 | r#" | 1391 | r#" |
1398 | //- /main.rs crate:main deps:std | 1392 | //- /main.rs crate:main deps:std |
1399 | extern crate st<|>d; | 1393 | extern crate st$0d; |
1400 | //- /std/lib.rs crate:std | 1394 | //- /std/lib.rs crate:std |
1401 | //! Standard library for this test | 1395 | //! Standard library for this test |
1402 | //! | 1396 | //! |
@@ -1414,7 +1408,7 @@ extern crate st<|>d; | |||
1414 | check( | 1408 | check( |
1415 | r#" | 1409 | r#" |
1416 | //- /main.rs crate:main deps:std | 1410 | //- /main.rs crate:main deps:std |
1417 | extern crate std as ab<|>c; | 1411 | extern crate std as ab$0c; |
1418 | //- /std/lib.rs crate:std | 1412 | //- /std/lib.rs crate:std |
1419 | //! Standard library for this test | 1413 | //! Standard library for this test |
1420 | //! | 1414 | //! |
@@ -1435,7 +1429,7 @@ extern crate std as ab<|>c; | |||
1435 | fn test_hover_mod_with_same_name_as_function() { | 1429 | fn test_hover_mod_with_same_name_as_function() { |
1436 | check( | 1430 | check( |
1437 | r#" | 1431 | r#" |
1438 | use self::m<|>y::Bar; | 1432 | use self::m$0y::Bar; |
1439 | mod my { pub struct Bar; } | 1433 | mod my { pub struct Bar; } |
1440 | 1434 | ||
1441 | fn my() {} | 1435 | fn my() {} |
@@ -1461,7 +1455,7 @@ fn my() {} | |||
1461 | /// bar docs | 1455 | /// bar docs |
1462 | struct Bar; | 1456 | struct Bar; |
1463 | 1457 | ||
1464 | fn foo() { let bar = Ba<|>r; } | 1458 | fn foo() { let bar = Ba$0r; } |
1465 | "#, | 1459 | "#, |
1466 | expect![[r#" | 1460 | expect![[r#" |
1467 | *Bar* | 1461 | *Bar* |
@@ -1488,7 +1482,7 @@ fn foo() { let bar = Ba<|>r; } | |||
1488 | #[doc = "bar docs"] | 1482 | #[doc = "bar docs"] |
1489 | struct Bar; | 1483 | struct Bar; |
1490 | 1484 | ||
1491 | fn foo() { let bar = Ba<|>r; } | 1485 | fn foo() { let bar = Ba$0r; } |
1492 | "#, | 1486 | "#, |
1493 | expect![[r#" | 1487 | expect![[r#" |
1494 | *Bar* | 1488 | *Bar* |
@@ -1517,7 +1511,7 @@ fn foo() { let bar = Ba<|>r; } | |||
1517 | #[doc = "bar docs 2"] | 1511 | #[doc = "bar docs 2"] |
1518 | struct Bar; | 1512 | struct Bar; |
1519 | 1513 | ||
1520 | fn foo() { let bar = Ba<|>r; } | 1514 | fn foo() { let bar = Ba$0r; } |
1521 | "#, | 1515 | "#, |
1522 | expect | 1541 | /// [Foo](struct.Foo.html) |
1548 | pub struct B<|>ar | 1542 | pub struct B$0ar |
1549 | "#, | 1543 | "#, |
1550 | expect | 1567 | /// [struct Foo](struct.Foo.html) |
1574 | pub struct B<|>ar | 1568 | pub struct B$0ar |
1575 | "#, | 1569 | "#, |
1576 | expect | 1595 | /// [Foo](struct.Foo.html) |
1602 | fie<|>ld: () | 1596 | fie$0ld: () |
1603 | } | 1597 | } |
1604 | "#, | 1598 | "#, |
1605 | expect | 1624 | /// [Foo](foo::Foo) |
1631 | pub struct B<|>ar | 1625 | pub struct B$0ar |
1632 | "#, | 1626 | "#, |
1633 | expect | 1654 | /// [Foo](foo::Foo) |
1661 | pub struct B<|>ar | 1655 | pub struct B$0ar |
1662 | "#, | 1656 | "#, |
1663 | expect![[r#" | 1657 | expect![[r#" |
1664 | *Bar* | 1658 | *Bar* |
@@ -1684,7 +1678,7 @@ pub struct B<|>ar | |||
1684 | r#" | 1678 | r#" |
1685 | pub struct Foo; | 1679 | pub struct Foo; |
1686 | /// [Foo] | 1680 | /// [Foo] |
1687 | pub struct B<|>ar | 1681 | pub struct B$0ar |
1688 | "#, | 1682 | "#, |
1689 | expect![[r#" | 1683 | expect![[r#" |
1690 | *Bar* | 1684 | *Bar* |
@@ -1710,7 +1704,7 @@ pub struct B<|>ar | |||
1710 | r#" | 1704 | r#" |
1711 | pub struct Foo; | 1705 | pub struct Foo; |
1712 | /// [`Foo`] | 1706 | /// [`Foo`] |
1713 | pub struct B<|>ar | 1707 | pub struct B$0ar |
1714 | "#, | 1708 | "#, |
1715 | expect![[r#" | 1709 | expect![[r#" |
1716 | *Bar* | 1710 | *Bar* |
@@ -1737,7 +1731,7 @@ pub struct B<|>ar | |||
1737 | pub struct Foo; | 1731 | pub struct Foo; |
1738 | fn Foo() {} | 1732 | fn Foo() {} |
1739 | /// [Foo()] | 1733 | /// [Foo()] |
1740 | pub struct B<|>ar | 1734 | pub struct B$0ar |
1741 | "#, | 1735 | "#, |
1742 | expect![[r#" | 1736 | expect![[r#" |
1743 | *Bar* | 1737 | *Bar* |
@@ -1763,7 +1757,7 @@ pub struct B<|>ar | |||
1763 | r#" | 1757 | r#" |
1764 | pub struct Foo; | 1758 | pub struct Foo; |
1765 | /// [`struct Foo`] | 1759 | /// [`struct Foo`] |
1766 | pub struct B<|>ar | 1760 | pub struct B$0ar |
1767 | "#, | 1761 | "#, |
1768 | expect![[r#" | 1762 | expect![[r#" |
1769 | *Bar* | 1763 | *Bar* |
@@ -1789,7 +1783,7 @@ pub struct B<|>ar | |||
1789 | r#" | 1783 | r#" |
1790 | pub struct Foo; | 1784 | pub struct Foo; |
1791 | /// [`struct@Foo`] | 1785 | /// [`struct@Foo`] |
1792 | pub struct B<|>ar | 1786 | pub struct B$0ar |
1793 | "#, | 1787 | "#, |
1794 | expect![[r#" | 1788 | expect![[r#" |
1795 | *Bar* | 1789 | *Bar* |
@@ -1817,7 +1811,7 @@ pub struct Foo; | |||
1817 | /// [my Foo][foo] | 1811 | /// [my Foo][foo] |
1818 | /// | 1812 | /// |
1819 | /// [foo]: Foo | 1813 | /// [foo]: Foo |
1820 | pub struct B<|>ar | 1814 | pub struct B$0ar |
1821 | "#, | 1815 | "#, |
1822 | expect | 1839 | /// [external](https://www.google.com) |
1846 | pub struct B<|>ar | 1840 | pub struct B$0ar |
1847 | "#, | 1841 | "#, |
1848 | expect | 1866 | /// [baz](Baz) |
1873 | pub struct B<|>ar | 1867 | pub struct B$0ar |
1874 | "#, | 1868 | "#, |
1875 | expect![[r#" | 1869 | expect![[r#" |
1876 | *Bar* | 1870 | *Bar* |
@@ -1896,7 +1890,7 @@ pub struct B<|>ar | |||
1896 | r#" | 1890 | r#" |
1897 | enum E { | 1891 | enum E { |
1898 | /// [E] | 1892 | /// [E] |
1899 | V<|> { field: i32 } | 1893 | V$0 { field: i32 } |
1900 | } | 1894 | } |
1901 | "#, | 1895 | "#, |
1902 | expect![[r#" | 1896 | expect![[r#" |
@@ -1923,7 +1917,7 @@ enum E { | |||
1923 | r#" | 1917 | r#" |
1924 | struct S { | 1918 | struct S { |
1925 | /// [`S`] | 1919 | /// [`S`] |
1926 | field<|>: i32 | 1920 | field$0: i32 |
1927 | } | 1921 | } |
1928 | "#, | 1922 | "#, |
1929 | expect | 1947 | /// case 2. inline URL with title: [example](https://www.example.com/) |
1954 | /// case 3. code refrence: [`Result`] | 1948 | /// case 3. code reference: [`Result`] |
1955 | /// case 4. code refrence but miss footnote: [`String`] | 1949 | /// case 4. code reference but miss footnote: [`String`] |
1956 | /// case 5. autolink: <http://www.example.com/> | 1950 | /// case 5. autolink: <http://www.example.com/> |
1957 | /// case 6. email address: <[email protected]> | 1951 | /// case 6. email address: <[email protected]> |
1958 | /// case 7. refrence: [example][example] | 1952 | /// case 7. reference: [example][example] |
1959 | /// case 8. collapsed link: [example][] | 1953 | /// case 8. collapsed link: [example][] |
1960 | /// case 9. shortcut link: [example] | 1954 | /// case 9. shortcut link: [example] |
1961 | /// case 10. inline without URL: [example]() | 1955 | /// case 10. inline without URL: [example]() |
1962 | /// case 11. refrence: [foo][foo] | 1956 | /// case 11. reference: [foo][foo] |
1963 | /// case 12. refrence: [foo][bar] | 1957 | /// case 12. reference: [foo][bar] |
1964 | /// case 13. collapsed link: [foo][] | 1958 | /// case 13. collapsed link: [foo][] |
1965 | /// case 14. shortcut link: [foo] | 1959 | /// case 14. shortcut link: [foo] |
1966 | /// case 15. inline without URL: [foo]() | 1960 | /// case 15. inline without URL: [foo]() |
@@ -1969,7 +1963,7 @@ struct S { | |||
1969 | /// | 1963 | /// |
1970 | /// [`Result`]: ../../std/result/enum.Result.html | 1964 | /// [`Result`]: ../../std/result/enum.Result.html |
1971 | /// [^example]: https://www.example.com/ | 1965 | /// [^example]: https://www.example.com/ |
1972 | pub fn fo<|>o() {} | 1966 | pub fn fo$0o() {} |
1973 | "#, | 1967 | "#, |
1974 | expect | 1983 | case 2. inline URL with title: [example](https://www.example.com/) |
1990 | case 3. code refrence: `Result` | 1984 | case 3. code reference: `Result` |
1991 | case 4. code refrence but miss footnote: `String` | 1985 | case 4. code reference but miss footnote: `String` |
1992 | case 5. autolink: http://www.example.com/ | 1986 | case 5. autolink: http://www.example.com/ |
1993 | case 6. email address: [email protected] | 1987 | case 6. email address: [email protected] |
1994 | case 7. refrence: example | 1988 | case 7. reference: example |
1995 | case 8. collapsed link: example | 1989 | case 8. collapsed link: example |
1996 | case 9. shortcut link: example | 1990 | case 9. shortcut link: example |
1997 | case 10. inline without URL: example | 1991 | case 10. inline without URL: example |
1998 | case 11. refrence: foo | 1992 | case 11. reference: foo |
1999 | case 12. refrence: foo | 1993 | case 12. reference: foo |
2000 | case 13. collapsed link: foo | 1994 | case 13. collapsed link: foo |
2001 | case 14. shortcut link: foo | 1995 | case 14. shortcut link: foo |
2002 | case 15. inline without URL: foo | 1996 | case 15. inline without URL: foo |
@@ -2026,7 +2020,7 @@ macro_rules! bar { | |||
2026 | 2020 | ||
2027 | bar!(); | 2021 | bar!(); |
2028 | 2022 | ||
2029 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 2023 | fn foo() { let bar = Bar; bar.fo$0o(); } |
2030 | "#, | 2024 | "#, |
2031 | expect![[r#" | 2025 | expect![[r#" |
2032 | *foo* | 2026 | *foo* |
@@ -2064,7 +2058,7 @@ macro_rules! bar { | |||
2064 | 2058 | ||
2065 | bar!(); | 2059 | bar!(); |
2066 | 2060 | ||
2067 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 2061 | fn foo() { let bar = Bar; bar.fo$0o(); } |
2068 | "#, | 2062 | "#, |
2069 | expect![[r#" | 2063 | expect![[r#" |
2070 | *foo* | 2064 | *foo* |
@@ -2087,7 +2081,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2087 | #[test] | 2081 | #[test] |
2088 | fn test_hover_trait_has_impl_action() { | 2082 | fn test_hover_trait_has_impl_action() { |
2089 | check_actions( | 2083 | check_actions( |
2090 | r#"trait foo<|>() {}"#, | 2084 | r#"trait foo$0() {}"#, |
2091 | expect![[r#" | 2085 | expect![[r#" |
2092 | [ | 2086 | [ |
2093 | Implementation( | 2087 | Implementation( |
@@ -2106,7 +2100,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2106 | #[test] | 2100 | #[test] |
2107 | fn test_hover_struct_has_impl_action() { | 2101 | fn test_hover_struct_has_impl_action() { |
2108 | check_actions( | 2102 | check_actions( |
2109 | r"struct foo<|>() {}", | 2103 | r"struct foo$0() {}", |
2110 | expect![[r#" | 2104 | expect![[r#" |
2111 | [ | 2105 | [ |
2112 | Implementation( | 2106 | Implementation( |
@@ -2125,7 +2119,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2125 | #[test] | 2119 | #[test] |
2126 | fn test_hover_union_has_impl_action() { | 2120 | fn test_hover_union_has_impl_action() { |
2127 | check_actions( | 2121 | check_actions( |
2128 | r#"union foo<|>() {}"#, | 2122 | r#"union foo$0() {}"#, |
2129 | expect![[r#" | 2123 | expect![[r#" |
2130 | [ | 2124 | [ |
2131 | Implementation( | 2125 | Implementation( |
@@ -2144,7 +2138,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2144 | #[test] | 2138 | #[test] |
2145 | fn test_hover_enum_has_impl_action() { | 2139 | fn test_hover_enum_has_impl_action() { |
2146 | check_actions( | 2140 | check_actions( |
2147 | r"enum foo<|>() { A, B }", | 2141 | r"enum foo$0() { A, B }", |
2148 | expect![[r#" | 2142 | expect![[r#" |
2149 | [ | 2143 | [ |
2150 | Implementation( | 2144 | Implementation( |
@@ -2163,7 +2157,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2163 | #[test] | 2157 | #[test] |
2164 | fn test_hover_self_has_impl_action() { | 2158 | fn test_hover_self_has_impl_action() { |
2165 | check_actions( | 2159 | check_actions( |
2166 | r#"struct foo where Self<|>:;"#, | 2160 | r#"struct foo where Self$0:;"#, |
2167 | expect![[r#" | 2161 | expect![[r#" |
2168 | [ | 2162 | [ |
2169 | Implementation( | 2163 | Implementation( |
@@ -2184,7 +2178,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2184 | check_actions( | 2178 | check_actions( |
2185 | r#" | 2179 | r#" |
2186 | #[test] | 2180 | #[test] |
2187 | fn foo_<|>test() {} | 2181 | fn foo_$0test() {} |
2188 | "#, | 2182 | "#, |
2189 | expect![[r#" | 2183 | expect![[r#" |
2190 | [ | 2184 | [ |
@@ -2219,7 +2213,7 @@ fn foo_<|>test() {} | |||
2219 | fn test_hover_test_mod_has_action() { | 2213 | fn test_hover_test_mod_has_action() { |
2220 | check_actions( | 2214 | check_actions( |
2221 | r#" | 2215 | r#" |
2222 | mod tests<|> { | 2216 | mod tests$0 { |
2223 | #[test] | 2217 | #[test] |
2224 | fn foo_test() {} | 2218 | fn foo_test() {} |
2225 | } | 2219 | } |
@@ -2254,7 +2248,7 @@ mod tests<|> { | |||
2254 | r#" | 2248 | r#" |
2255 | struct S{ f1: u32 } | 2249 | struct S{ f1: u32 } |
2256 | 2250 | ||
2257 | fn main() { let s<|>t = S{ f1:0 }; } | 2251 | fn main() { let s$0t = S{ f1:0 }; } |
2258 | "#, | 2252 | "#, |
2259 | expect![[r#" | 2253 | expect![[r#" |
2260 | [ | 2254 | [ |
@@ -2287,7 +2281,7 @@ fn main() { let s<|>t = S{ f1:0 }; } | |||
2287 | struct Arg(u32); | 2281 | struct Arg(u32); |
2288 | struct S<T>{ f1: T } | 2282 | struct S<T>{ f1: T } |
2289 | 2283 | ||
2290 | fn main() { let s<|>t = S{ f1:Arg(0) }; } | 2284 | fn main() { let s$0t = S{ f1:Arg(0) }; } |
2291 | "#, | 2285 | "#, |
2292 | expect![[r#" | 2286 | expect![[r#" |
2293 | [ | 2287 | [ |
@@ -2333,7 +2327,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
2333 | struct Arg(u32); | 2327 | struct Arg(u32); |
2334 | struct S<T>{ f1: T } | 2328 | struct S<T>{ f1: T } |
2335 | 2329 | ||
2336 | fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | 2330 | fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } |
2337 | "#, | 2331 | "#, |
2338 | expect![[r#" | 2332 | expect![[r#" |
2339 | [ | 2333 | [ |
@@ -2382,7 +2376,7 @@ mod M { | |||
2382 | pub struct C(u32); | 2376 | pub struct C(u32); |
2383 | } | 2377 | } |
2384 | 2378 | ||
2385 | fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | 2379 | fn main() { let s$0t = (A(1), B(2), M::C(3) ); } |
2386 | "#, | 2380 | "#, |
2387 | expect![[r#" | 2381 | expect![[r#" |
2388 | [ | 2382 | [ |
@@ -2441,7 +2435,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
2441 | trait Foo {} | 2435 | trait Foo {} |
2442 | fn foo() -> impl Foo {} | 2436 | fn foo() -> impl Foo {} |
2443 | 2437 | ||
2444 | fn main() { let s<|>t = foo(); } | 2438 | fn main() { let s$0t = foo(); } |
2445 | "#, | 2439 | "#, |
2446 | expect![[r#" | 2440 | expect![[r#" |
2447 | [ | 2441 | [ |
@@ -2475,7 +2469,7 @@ trait Foo<T> {} | |||
2475 | struct S; | 2469 | struct S; |
2476 | fn foo() -> impl Foo<S> {} | 2470 | fn foo() -> impl Foo<S> {} |
2477 | 2471 | ||
2478 | fn main() { let s<|>t = foo(); } | 2472 | fn main() { let s$0t = foo(); } |
2479 | "#, | 2473 | "#, |
2480 | expect![[r#" | 2474 | expect![[r#" |
2481 | [ | 2475 | [ |
@@ -2522,7 +2516,7 @@ trait Foo {} | |||
2522 | trait Bar {} | 2516 | trait Bar {} |
2523 | fn foo() -> impl Foo + Bar {} | 2517 | fn foo() -> impl Foo + Bar {} |
2524 | 2518 | ||
2525 | fn main() { let s<|>t = foo(); } | 2519 | fn main() { let s$0t = foo(); } |
2526 | "#, | 2520 | "#, |
2527 | expect![[r#" | 2521 | expect![[r#" |
2528 | [ | 2522 | [ |
@@ -2572,7 +2566,7 @@ struct S2 {} | |||
2572 | 2566 | ||
2573 | fn foo() -> impl Foo<S1> + Bar<S2> {} | 2567 | fn foo() -> impl Foo<S1> + Bar<S2> {} |
2574 | 2568 | ||
2575 | fn main() { let s<|>t = foo(); } | 2569 | fn main() { let s$0t = foo(); } |
2576 | "#, | 2570 | "#, |
2577 | expect![[r#" | 2571 | expect![[r#" |
2578 | [ | 2572 | [ |
@@ -2642,7 +2636,7 @@ fn main() { let s<|>t = foo(); } | |||
2642 | check_actions( | 2636 | check_actions( |
2643 | r#" | 2637 | r#" |
2644 | trait Foo {} | 2638 | trait Foo {} |
2645 | fn foo(ar<|>g: &impl Foo) {} | 2639 | fn foo(ar$0g: &impl Foo) {} |
2646 | "#, | 2640 | "#, |
2647 | expect![[r#" | 2641 | expect![[r#" |
2648 | [ | 2642 | [ |
@@ -2676,7 +2670,7 @@ trait Foo {} | |||
2676 | trait Bar<T> {} | 2670 | trait Bar<T> {} |
2677 | struct S{} | 2671 | struct S{} |
2678 | 2672 | ||
2679 | fn foo(ar<|>g: &impl Foo + Bar<S>) {} | 2673 | fn foo(ar$0g: &impl Foo + Bar<S>) {} |
2680 | "#, | 2674 | "#, |
2681 | expect![[r#" | 2675 | expect![[r#" |
2682 | [ | 2676 | [ |
@@ -2734,7 +2728,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2734 | r#" | 2728 | r#" |
2735 | struct S; | 2729 | struct S; |
2736 | fn foo() { | 2730 | fn foo() { |
2737 | let fo<|>o = async { S }; | 2731 | let fo$0o = async { S }; |
2738 | } | 2732 | } |
2739 | 2733 | ||
2740 | #[prelude_import] use future::*; | 2734 | #[prelude_import] use future::*; |
@@ -2786,7 +2780,7 @@ mod future { | |||
2786 | r#" | 2780 | r#" |
2787 | trait Foo<T> {} | 2781 | trait Foo<T> {} |
2788 | struct S {} | 2782 | struct S {} |
2789 | fn foo(ar<|>g: &impl Foo<S>) {} | 2783 | fn foo(ar$0g: &impl Foo<S>) {} |
2790 | "#, | 2784 | "#, |
2791 | expect![[r#" | 2785 | expect![[r#" |
2792 | [ | 2786 | [ |
@@ -2836,7 +2830,7 @@ impl Foo for S {} | |||
2836 | struct B<T>{} | 2830 | struct B<T>{} |
2837 | fn foo() -> B<dyn Foo> {} | 2831 | fn foo() -> B<dyn Foo> {} |
2838 | 2832 | ||
2839 | fn main() { let s<|>t = foo(); } | 2833 | fn main() { let s$0t = foo(); } |
2840 | "#, | 2834 | "#, |
2841 | expect![[r#" | 2835 | expect![[r#" |
2842 | [ | 2836 | [ |
@@ -2880,7 +2874,7 @@ fn main() { let s<|>t = foo(); } | |||
2880 | check_actions( | 2874 | check_actions( |
2881 | r#" | 2875 | r#" |
2882 | trait Foo {} | 2876 | trait Foo {} |
2883 | fn foo(ar<|>g: &dyn Foo) {} | 2877 | fn foo(ar$0g: &dyn Foo) {} |
2884 | "#, | 2878 | "#, |
2885 | expect![[r#" | 2879 | expect![[r#" |
2886 | [ | 2880 | [ |
@@ -2912,7 +2906,7 @@ fn foo(ar<|>g: &dyn Foo) {} | |||
2912 | r#" | 2906 | r#" |
2913 | trait Foo<T> {} | 2907 | trait Foo<T> {} |
2914 | struct S {} | 2908 | struct S {} |
2915 | fn foo(ar<|>g: &dyn Foo<S>) {} | 2909 | fn foo(ar$0g: &dyn Foo<S>) {} |
2916 | "#, | 2910 | "#, |
2917 | expect![[r#" | 2911 | expect![[r#" |
2918 | [ | 2912 | [ |
@@ -2960,7 +2954,7 @@ trait DynTrait<T> {} | |||
2960 | struct B<T> {} | 2954 | struct B<T> {} |
2961 | struct S {} | 2955 | struct S {} |
2962 | 2956 | ||
2963 | fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | 2957 | fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} |
2964 | "#, | 2958 | "#, |
2965 | expect![[r#" | 2959 | expect![[r#" |
2966 | [ | 2960 | [ |
@@ -3041,7 +3035,7 @@ impl Foo for S { type Item = Bar; } | |||
3041 | 3035 | ||
3042 | fn test() -> impl Foo { S {} } | 3036 | fn test() -> impl Foo { S {} } |
3043 | 3037 | ||
3044 | fn main() { let s<|>t = test().get(); } | 3038 | fn main() { let s$0t = test().get(); } |
3045 | "#, | 3039 | "#, |
3046 | expect![[r#" | 3040 | expect![[r#" |
3047 | [ | 3041 | [ |
@@ -3074,7 +3068,7 @@ fn main() { let s<|>t = test().get(); } | |||
3074 | struct Bar; | 3068 | struct Bar; |
3075 | struct Foo<const BAR: Bar>; | 3069 | struct Foo<const BAR: Bar>; |
3076 | 3070 | ||
3077 | impl<const BAR: Bar> Foo<BAR<|>> {} | 3071 | impl<const BAR: Bar> Foo<BAR$0> {} |
3078 | "#, | 3072 | "#, |
3079 | expect![[r#" | 3073 | expect![[r#" |
3080 | [ | 3074 | [ |
@@ -3106,7 +3100,7 @@ impl<const BAR: Bar> Foo<BAR<|>> {} | |||
3106 | r#" | 3100 | r#" |
3107 | trait Foo {} | 3101 | trait Foo {} |
3108 | 3102 | ||
3109 | fn foo<T: Foo>(t: T<|>){} | 3103 | fn foo<T: Foo>(t: T$0){} |
3110 | "#, | 3104 | "#, |
3111 | expect![[r#" | 3105 | expect![[r#" |
3112 | [ | 3106 | [ |
@@ -3133,6 +3127,39 @@ fn foo<T: Foo>(t: T<|>){} | |||
3133 | } | 3127 | } |
3134 | 3128 | ||
3135 | #[test] | 3129 | #[test] |
3130 | fn test_hover_self_has_go_to_type() { | ||
3131 | check_actions( | ||
3132 | r#" | ||
3133 | struct Foo; | ||
3134 | impl Foo { | ||
3135 | fn foo(&self$0) {} | ||
3136 | } | ||
3137 | "#, | ||
3138 | expect![[r#" | ||
3139 | [ | ||
3140 | GoToType( | ||
3141 | [ | ||
3142 | HoverGotoTypeData { | ||
3143 | mod_path: "test::Foo", | ||
3144 | nav: NavigationTarget { | ||
3145 | file_id: FileId( | ||
3146 | 0, | ||
3147 | ), | ||
3148 | full_range: 0..11, | ||
3149 | focus_range: 7..10, | ||
3150 | name: "Foo", | ||
3151 | kind: Struct, | ||
3152 | description: "struct Foo", | ||
3153 | }, | ||
3154 | }, | ||
3155 | ], | ||
3156 | ), | ||
3157 | ] | ||
3158 | "#]], | ||
3159 | ); | ||
3160 | } | ||
3161 | |||
3162 | #[test] | ||
3136 | fn hover_displays_normalized_crate_names() { | 3163 | fn hover_displays_normalized_crate_names() { |
3137 | check( | 3164 | check( |
3138 | r#" | 3165 | r#" |
@@ -3146,7 +3173,7 @@ pub mod wrapper { | |||
3146 | } | 3173 | } |
3147 | 3174 | ||
3148 | //- /main.rs crate:main deps:name-with-dashes | 3175 | //- /main.rs crate:main deps:name-with-dashes |
3149 | fn main() { let foo_test = name_with_dashes::wrapper::Thing::new<|>(); } | 3176 | fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } |
3150 | "#, | 3177 | "#, |
3151 | expect![[r#" | 3178 | expect![[r#" |
3152 | *new* | 3179 | *new* |
@@ -3172,7 +3199,7 @@ struct S { | |||
3172 | 3199 | ||
3173 | fn main() { | 3200 | fn main() { |
3174 | let s = S { f: 0 }; | 3201 | let s = S { f: 0 }; |
3175 | let S { f<|> } = &s; | 3202 | let S { f$0 } = &s; |
3176 | } | 3203 | } |
3177 | "#, | 3204 | "#, |
3178 | expect![[r#" | 3205 | expect![[r#" |
@@ -3191,11 +3218,12 @@ fn main() { | |||
3191 | r#" | 3218 | r#" |
3192 | struct Foo {} | 3219 | struct Foo {} |
3193 | impl Foo { | 3220 | impl Foo { |
3194 | fn bar(&sel<|>f) {} | 3221 | fn bar(&sel$0f) {} |
3195 | } | 3222 | } |
3196 | "#, | 3223 | "#, |
3197 | expect![[r#" | 3224 | expect![[r#" |
3198 | *&self* | 3225 | *self* |
3226 | |||
3199 | ```rust | 3227 | ```rust |
3200 | &Foo | 3228 | &Foo |
3201 | ``` | 3229 | ``` |
@@ -3210,11 +3238,12 @@ impl Foo { | |||
3210 | struct Arc<T>(T); | 3238 | struct Arc<T>(T); |
3211 | struct Foo {} | 3239 | struct Foo {} |
3212 | impl Foo { | 3240 | impl Foo { |
3213 | fn bar(sel<|>f: Arc<Foo>) {} | 3241 | fn bar(sel$0f: Arc<Foo>) {} |
3214 | } | 3242 | } |
3215 | "#, | 3243 | "#, |
3216 | expect![[r#" | 3244 | expect![[r#" |
3217 | *self: Arc<Foo>* | 3245 | *self* |
3246 | |||
3218 | ```rust | 3247 | ```rust |
3219 | Arc<Foo> | 3248 | Arc<Foo> |
3220 | ``` | 3249 | ``` |
@@ -3227,7 +3256,7 @@ impl Foo { | |||
3227 | check( | 3256 | check( |
3228 | r#" | 3257 | r#" |
3229 | /// Be quick; | 3258 | /// Be quick; |
3230 | mod Foo<|> { | 3259 | mod Foo$0 { |
3231 | //! time is mana | 3260 | //! time is mana |
3232 | 3261 | ||
3233 | /// This comment belongs to the function | 3262 | /// This comment belongs to the function |
@@ -3258,7 +3287,7 @@ mod Foo<|> { | |||
3258 | check( | 3287 | check( |
3259 | r#" | 3288 | r#" |
3260 | #[doc = "Be quick;"] | 3289 | #[doc = "Be quick;"] |
3261 | mod Foo<|> { | 3290 | mod Foo$0 { |
3262 | #![doc = "time is mana"] | 3291 | #![doc = "time is mana"] |
3263 | 3292 | ||
3264 | #[doc = "This comment belongs to the function"] | 3293 | #[doc = "This comment belongs to the function"] |
@@ -3289,7 +3318,7 @@ mod Foo<|> { | |||
3289 | check_hover_no_result( | 3318 | check_hover_no_result( |
3290 | r#" | 3319 | r#" |
3291 | fn no_hover() { | 3320 | fn no_hover() { |
3292 | // no<|>hover | 3321 | // no$0hover |
3293 | } | 3322 | } |
3294 | "#, | 3323 | "#, |
3295 | ); | 3324 | ); |
@@ -3300,7 +3329,7 @@ fn no_hover() { | |||
3300 | check( | 3329 | check( |
3301 | r#" | 3330 | r#" |
3302 | fn foo() { | 3331 | fn foo() { |
3303 | 'label<|>: loop {} | 3332 | 'label$0: loop {} |
3304 | } | 3333 | } |
3305 | "#, | 3334 | "#, |
3306 | expect![[r#" | 3335 | expect![[r#" |
@@ -3316,7 +3345,7 @@ fn foo() { | |||
3316 | #[test] | 3345 | #[test] |
3317 | fn hover_lifetime() { | 3346 | fn hover_lifetime() { |
3318 | check( | 3347 | check( |
3319 | r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, | 3348 | r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#, |
3320 | expect![[r#" | 3349 | expect![[r#" |
3321 | *'lifetime* | 3350 | *'lifetime* |
3322 | 3351 | ||
@@ -3335,7 +3364,7 @@ struct Foo<T>(T); | |||
3335 | trait Copy {} | 3364 | trait Copy {} |
3336 | trait Clone {} | 3365 | trait Clone {} |
3337 | trait Sized {} | 3366 | trait Sized {} |
3338 | impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} | 3367 | impl<T: Copy + Clone> Foo<T$0> where T: Sized {} |
3339 | "#, | 3368 | "#, |
3340 | expect![[r#" | 3369 | expect![[r#" |
3341 | *T* | 3370 | *T* |
@@ -3348,7 +3377,7 @@ impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} | |||
3348 | check( | 3377 | check( |
3349 | r#" | 3378 | r#" |
3350 | struct Foo<T>(T); | 3379 | struct Foo<T>(T); |
3351 | impl<T> Foo<T<|>> {} | 3380 | impl<T> Foo<T$0> {} |
3352 | "#, | 3381 | "#, |
3353 | expect![[r#" | 3382 | expect![[r#" |
3354 | *T* | 3383 | *T* |
@@ -3362,7 +3391,7 @@ impl<T> Foo<T<|>> {} | |||
3362 | check( | 3391 | check( |
3363 | r#" | 3392 | r#" |
3364 | struct Foo<T>(T); | 3393 | struct Foo<T>(T); |
3365 | impl<T: 'static> Foo<T<|>> {} | 3394 | impl<T: 'static> Foo<T$0> {} |
3366 | "#, | 3395 | "#, |
3367 | expect![[r#" | 3396 | expect![[r#" |
3368 | *T* | 3397 | *T* |
@@ -3379,7 +3408,7 @@ impl<T: 'static> Foo<T<|>> {} | |||
3379 | check( | 3408 | check( |
3380 | r#" | 3409 | r#" |
3381 | struct Foo<const LEN: usize>; | 3410 | struct Foo<const LEN: usize>; |
3382 | impl<const LEN: usize> Foo<LEN<|>> {} | 3411 | impl<const LEN: usize> Foo<LEN$0> {} |
3383 | "#, | 3412 | "#, |
3384 | expect![[r#" | 3413 | expect![[r#" |
3385 | *LEN* | 3414 | *LEN* |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index fe60abfc8..a2039fcc7 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -353,9 +353,25 @@ fn is_argument_similar_to_param_name( | |||
353 | } | 353 | } |
354 | match get_string_representation(argument) { | 354 | match get_string_representation(argument) { |
355 | None => false, | 355 | None => false, |
356 | Some(repr) => { | 356 | Some(argument_string) => { |
357 | let argument_string = repr.trim_start_matches('_'); | 357 | let num_leading_underscores = |
358 | argument_string.starts_with(param_name) || argument_string.ends_with(param_name) | 358 | argument_string.bytes().take_while(|&c| c == b'_').count(); |
359 | |||
360 | // Does the argument name begin with the parameter name? Ignore leading underscores. | ||
361 | let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores); | ||
362 | let starts_with_pattern = param_name.bytes().all( | ||
363 | |expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)), | ||
364 | ); | ||
365 | |||
366 | if starts_with_pattern { | ||
367 | return true; | ||
368 | } | ||
369 | |||
370 | // Does the argument name end with the parameter name? | ||
371 | let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores); | ||
372 | param_name.bytes().rev().all( | ||
373 | |expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)), | ||
374 | ) | ||
359 | } | 375 | } |
360 | } | 376 | } |
361 | } | 377 | } |
@@ -901,6 +917,9 @@ fn main() { | |||
901 | twiddle(true); | 917 | twiddle(true); |
902 | doo(true); | 918 | doo(true); |
903 | 919 | ||
920 | const TWIDDLE_UPPERCASE: bool = true; | ||
921 | twiddle(TWIDDLE_UPPERCASE); | ||
922 | |||
904 | let mut param_begin: Param = Param {}; | 923 | let mut param_begin: Param = Param {}; |
905 | different_order(¶m_begin); | 924 | different_order(¶m_begin); |
906 | different_order(&mut param_begin); | 925 | different_order(&mut param_begin); |
@@ -1382,4 +1401,41 @@ fn main() { | |||
1382 | "#, | 1401 | "#, |
1383 | ) | 1402 | ) |
1384 | } | 1403 | } |
1404 | |||
1405 | #[test] | ||
1406 | fn fn_hints() { | ||
1407 | check( | ||
1408 | r#" | ||
1409 | trait Sized {} | ||
1410 | |||
1411 | fn foo() -> impl Fn() { loop {} } | ||
1412 | fn foo1() -> impl Fn(f64) { loop {} } | ||
1413 | fn foo2() -> impl Fn(f64, f64) { loop {} } | ||
1414 | fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } | ||
1415 | fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } | ||
1416 | fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } | ||
1417 | fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } | ||
1418 | fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } | ||
1419 | |||
1420 | fn main() { | ||
1421 | let foo = foo(); | ||
1422 | // ^^^ impl Fn() | ||
1423 | let foo = foo1(); | ||
1424 | // ^^^ impl Fn(f64) | ||
1425 | let foo = foo2(); | ||
1426 | // ^^^ impl Fn(f64, f64) | ||
1427 | let foo = foo3(); | ||
1428 | // ^^^ impl Fn(f64, f64) -> u32 | ||
1429 | let foo = foo4(); | ||
1430 | // ^^^ &dyn Fn(f64, f64) -> u32 | ||
1431 | let foo = foo5(); | ||
1432 | // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 | ||
1433 | let foo = foo6(); | ||
1434 | // ^^^ impl Fn(f64, f64) -> u32 + Sized | ||
1435 | let foo = foo7(); | ||
1436 | // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized) | ||
1437 | } | ||
1438 | "#, | ||
1439 | ) | ||
1440 | } | ||
1385 | } | 1441 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index b5a6f66fd..981467c8d 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use assists::utils::extract_trivial_expression; | 1 | use assists::utils::extract_trivial_expression; |
2 | use itertools::Itertools; | 2 | use itertools::Itertools; |
3 | use syntax::{ | 3 | use syntax::{ |
4 | algo::{find_covering_element, non_trivia_sibling}, | 4 | algo::non_trivia_sibling, |
5 | ast::{self, AstNode, AstToken}, | 5 | ast::{self, AstNode, AstToken}, |
6 | Direction, NodeOrToken, SourceFile, | 6 | Direction, NodeOrToken, SourceFile, |
7 | SyntaxKind::{self, USE_TREE, WHITESPACE}, | 7 | SyntaxKind::{self, USE_TREE, WHITESPACE}, |
@@ -31,7 +31,7 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | |||
31 | range | 31 | range |
32 | }; | 32 | }; |
33 | 33 | ||
34 | let node = match find_covering_element(file.syntax(), range) { | 34 | let node = match file.syntax().covering_element(range) { |
35 | NodeOrToken::Node(node) => node, | 35 | NodeOrToken::Node(node) => node, |
36 | NodeOrToken::Token(token) => token.parent(), | 36 | NodeOrToken::Token(token) => token.parent(), |
37 | }; | 37 | }; |
@@ -104,7 +104,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
104 | // Special case that turns something like: | 104 | // Special case that turns something like: |
105 | // | 105 | // |
106 | // ``` | 106 | // ``` |
107 | // my_function({<|> | 107 | // my_function({$0 |
108 | // <some-expr> | 108 | // <some-expr> |
109 | // }) | 109 | // }) |
110 | // ``` | 110 | // ``` |
@@ -116,7 +116,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
116 | // ditto for | 116 | // ditto for |
117 | // | 117 | // |
118 | // ``` | 118 | // ``` |
119 | // use foo::{<|> | 119 | // use foo::{$0 |
120 | // bar | 120 | // bar |
121 | // }; | 121 | // }; |
122 | // ``` | 122 | // ``` |
@@ -198,8 +198,8 @@ mod tests { | |||
198 | 198 | ||
199 | use super::*; | 199 | use super::*; |
200 | 200 | ||
201 | fn check_join_lines(before: &str, after: &str) { | 201 | fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { |
202 | let (before_cursor_pos, before) = extract_offset(before); | 202 | let (before_cursor_pos, before) = extract_offset(ra_fixture_before); |
203 | let file = SourceFile::parse(&before).ok().unwrap(); | 203 | let file = SourceFile::parse(&before).ok().unwrap(); |
204 | 204 | ||
205 | let range = TextRange::empty(before_cursor_pos); | 205 | let range = TextRange::empty(before_cursor_pos); |
@@ -214,7 +214,7 @@ mod tests { | |||
214 | .apply_to_offset(before_cursor_pos) | 214 | .apply_to_offset(before_cursor_pos) |
215 | .expect("cursor position is affected by the edit"); | 215 | .expect("cursor position is affected by the edit"); |
216 | let actual = add_cursor(&actual, actual_cursor_pos); | 216 | let actual = add_cursor(&actual, actual_cursor_pos); |
217 | assert_eq_text!(after, &actual); | 217 | assert_eq_text!(ra_fixture_after, &actual); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
@@ -222,13 +222,13 @@ mod tests { | |||
222 | check_join_lines( | 222 | check_join_lines( |
223 | r" | 223 | r" |
224 | fn foo() { | 224 | fn foo() { |
225 | <|>foo(1, | 225 | $0foo(1, |
226 | ) | 226 | ) |
227 | } | 227 | } |
228 | ", | 228 | ", |
229 | r" | 229 | r" |
230 | fn foo() { | 230 | fn foo() { |
231 | <|>foo(1) | 231 | $0foo(1) |
232 | } | 232 | } |
233 | ", | 233 | ", |
234 | ); | 234 | ); |
@@ -239,14 +239,14 @@ fn foo() { | |||
239 | check_join_lines( | 239 | check_join_lines( |
240 | r" | 240 | r" |
241 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { | 241 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { |
242 | <|>self.incremental_reparse(edit).unwrap_or_else(|| { | 242 | $0self.incremental_reparse(edit).unwrap_or_else(|| { |
243 | self.full_reparse(edit) | 243 | self.full_reparse(edit) |
244 | }) | 244 | }) |
245 | } | 245 | } |
246 | ", | 246 | ", |
247 | r" | 247 | r" |
248 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { | 248 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { |
249 | <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 249 | $0self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) |
250 | } | 250 | } |
251 | ", | 251 | ", |
252 | ); | 252 | ); |
@@ -257,13 +257,13 @@ pub fn reparse(&self, edit: &AtomTextEdit) -> File { | |||
257 | check_join_lines( | 257 | check_join_lines( |
258 | r" | 258 | r" |
259 | fn foo() { | 259 | fn foo() { |
260 | foo(<|>{ | 260 | foo($0{ |
261 | 92 | 261 | 92 |
262 | }) | 262 | }) |
263 | }", | 263 | }", |
264 | r" | 264 | r" |
265 | fn foo() { | 265 | fn foo() { |
266 | foo(<|>92) | 266 | foo($092) |
267 | }", | 267 | }", |
268 | ); | 268 | ); |
269 | } | 269 | } |
@@ -274,7 +274,7 @@ fn foo() { | |||
274 | fn foo() { | 274 | fn foo() { |
275 | loop { | 275 | loop { |
276 | match x { | 276 | match x { |
277 | 92 => <|>{ | 277 | 92 => $0{ |
278 | continue; | 278 | continue; |
279 | } | 279 | } |
280 | } | 280 | } |
@@ -285,7 +285,7 @@ fn foo() { | |||
285 | fn foo() { | 285 | fn foo() { |
286 | loop { | 286 | loop { |
287 | match x { | 287 | match x { |
288 | 92 => <|>continue, | 288 | 92 => $0continue, |
289 | } | 289 | } |
290 | } | 290 | } |
291 | } | 291 | } |
@@ -299,7 +299,7 @@ fn foo() { | |||
299 | r" | 299 | r" |
300 | fn foo(e: Result<U, V>) { | 300 | fn foo(e: Result<U, V>) { |
301 | match e { | 301 | match e { |
302 | Ok(u) => <|>{ | 302 | Ok(u) => $0{ |
303 | u.foo() | 303 | u.foo() |
304 | } | 304 | } |
305 | Err(v) => v, | 305 | Err(v) => v, |
@@ -308,7 +308,7 @@ fn foo(e: Result<U, V>) { | |||
308 | r" | 308 | r" |
309 | fn foo(e: Result<U, V>) { | 309 | fn foo(e: Result<U, V>) { |
310 | match e { | 310 | match e { |
311 | Ok(u) => <|>u.foo(), | 311 | Ok(u) => $0u.foo(), |
312 | Err(v) => v, | 312 | Err(v) => v, |
313 | } | 313 | } |
314 | }", | 314 | }", |
@@ -321,7 +321,7 @@ fn foo(e: Result<U, V>) { | |||
321 | r" | 321 | r" |
322 | fn foo() { | 322 | fn foo() { |
323 | match ty { | 323 | match ty { |
324 | <|> Some(ty) => { | 324 | $0 Some(ty) => { |
325 | match ty { | 325 | match ty { |
326 | _ => false, | 326 | _ => false, |
327 | } | 327 | } |
@@ -333,7 +333,7 @@ fn foo() { | |||
333 | r" | 333 | r" |
334 | fn foo() { | 334 | fn foo() { |
335 | match ty { | 335 | match ty { |
336 | <|> Some(ty) => match ty { | 336 | $0 Some(ty) => match ty { |
337 | _ => false, | 337 | _ => false, |
338 | }, | 338 | }, |
339 | _ => true, | 339 | _ => true, |
@@ -350,7 +350,7 @@ fn foo() { | |||
350 | r" | 350 | r" |
351 | fn foo(e: Result<U, V>) { | 351 | fn foo(e: Result<U, V>) { |
352 | match e { | 352 | match e { |
353 | Ok(u) => <|>{ | 353 | Ok(u) => $0{ |
354 | u.foo() | 354 | u.foo() |
355 | }, | 355 | }, |
356 | Err(v) => v, | 356 | Err(v) => v, |
@@ -359,7 +359,7 @@ fn foo(e: Result<U, V>) { | |||
359 | r" | 359 | r" |
360 | fn foo(e: Result<U, V>) { | 360 | fn foo(e: Result<U, V>) { |
361 | match e { | 361 | match e { |
362 | Ok(u) => <|>u.foo(), | 362 | Ok(u) => $0u.foo(), |
363 | Err(v) => v, | 363 | Err(v) => v, |
364 | } | 364 | } |
365 | }", | 365 | }", |
@@ -370,7 +370,7 @@ fn foo(e: Result<U, V>) { | |||
370 | r" | 370 | r" |
371 | fn foo(e: Result<U, V>) { | 371 | fn foo(e: Result<U, V>) { |
372 | match e { | 372 | match e { |
373 | Ok(u) => <|>{ | 373 | Ok(u) => $0{ |
374 | u.foo() | 374 | u.foo() |
375 | } , | 375 | } , |
376 | Err(v) => v, | 376 | Err(v) => v, |
@@ -379,7 +379,7 @@ fn foo(e: Result<U, V>) { | |||
379 | r" | 379 | r" |
380 | fn foo(e: Result<U, V>) { | 380 | fn foo(e: Result<U, V>) { |
381 | match e { | 381 | match e { |
382 | Ok(u) => <|>u.foo() , | 382 | Ok(u) => $0u.foo() , |
383 | Err(v) => v, | 383 | Err(v) => v, |
384 | } | 384 | } |
385 | }", | 385 | }", |
@@ -390,7 +390,7 @@ fn foo(e: Result<U, V>) { | |||
390 | r" | 390 | r" |
391 | fn foo(e: Result<U, V>) { | 391 | fn foo(e: Result<U, V>) { |
392 | match e { | 392 | match e { |
393 | Ok(u) => <|>{ | 393 | Ok(u) => $0{ |
394 | u.foo() | 394 | u.foo() |
395 | } | 395 | } |
396 | , | 396 | , |
@@ -400,7 +400,7 @@ fn foo(e: Result<U, V>) { | |||
400 | r" | 400 | r" |
401 | fn foo(e: Result<U, V>) { | 401 | fn foo(e: Result<U, V>) { |
402 | match e { | 402 | match e { |
403 | Ok(u) => <|>u.foo() | 403 | Ok(u) => $0u.foo() |
404 | , | 404 | , |
405 | Err(v) => v, | 405 | Err(v) => v, |
406 | } | 406 | } |
@@ -414,13 +414,13 @@ fn foo(e: Result<U, V>) { | |||
414 | check_join_lines( | 414 | check_join_lines( |
415 | r" | 415 | r" |
416 | fn foo() { | 416 | fn foo() { |
417 | let x = (<|>{ | 417 | let x = ($0{ |
418 | 4 | 418 | 4 |
419 | },); | 419 | },); |
420 | }", | 420 | }", |
421 | r" | 421 | r" |
422 | fn foo() { | 422 | fn foo() { |
423 | let x = (<|>4,); | 423 | let x = ($04,); |
424 | }", | 424 | }", |
425 | ); | 425 | ); |
426 | 426 | ||
@@ -428,13 +428,13 @@ fn foo() { | |||
428 | check_join_lines( | 428 | check_join_lines( |
429 | r" | 429 | r" |
430 | fn foo() { | 430 | fn foo() { |
431 | let x = (<|>{ | 431 | let x = ($0{ |
432 | 4 | 432 | 4 |
433 | } ,); | 433 | } ,); |
434 | }", | 434 | }", |
435 | r" | 435 | r" |
436 | fn foo() { | 436 | fn foo() { |
437 | let x = (<|>4 ,); | 437 | let x = ($04 ,); |
438 | }", | 438 | }", |
439 | ); | 439 | ); |
440 | 440 | ||
@@ -442,14 +442,14 @@ fn foo() { | |||
442 | check_join_lines( | 442 | check_join_lines( |
443 | r" | 443 | r" |
444 | fn foo() { | 444 | fn foo() { |
445 | let x = (<|>{ | 445 | let x = ($0{ |
446 | 4 | 446 | 4 |
447 | } | 447 | } |
448 | ,); | 448 | ,); |
449 | }", | 449 | }", |
450 | r" | 450 | r" |
451 | fn foo() { | 451 | fn foo() { |
452 | let x = (<|>4 | 452 | let x = ($04 |
453 | ,); | 453 | ,); |
454 | }", | 454 | }", |
455 | ); | 455 | ); |
@@ -460,11 +460,11 @@ fn foo() { | |||
460 | // No space after the '{' | 460 | // No space after the '{' |
461 | check_join_lines( | 461 | check_join_lines( |
462 | r" | 462 | r" |
463 | <|>use syntax::{ | 463 | $0use syntax::{ |
464 | TextSize, TextRange, | 464 | TextSize, TextRange, |
465 | };", | 465 | };", |
466 | r" | 466 | r" |
467 | <|>use syntax::{TextSize, TextRange, | 467 | $0use syntax::{TextSize, TextRange, |
468 | };", | 468 | };", |
469 | ); | 469 | ); |
470 | } | 470 | } |
@@ -475,11 +475,11 @@ fn foo() { | |||
475 | check_join_lines( | 475 | check_join_lines( |
476 | r" | 476 | r" |
477 | use syntax::{ | 477 | use syntax::{ |
478 | <|> TextSize, TextRange | 478 | $0 TextSize, TextRange |
479 | };", | 479 | };", |
480 | r" | 480 | r" |
481 | use syntax::{ | 481 | use syntax::{ |
482 | <|> TextSize, TextRange};", | 482 | $0 TextSize, TextRange};", |
483 | ); | 483 | ); |
484 | } | 484 | } |
485 | 485 | ||
@@ -489,11 +489,11 @@ use syntax::{ | |||
489 | check_join_lines( | 489 | check_join_lines( |
490 | r" | 490 | r" |
491 | use syntax::{ | 491 | use syntax::{ |
492 | <|> TextSize, TextRange, | 492 | $0 TextSize, TextRange, |
493 | };", | 493 | };", |
494 | r" | 494 | r" |
495 | use syntax::{ | 495 | use syntax::{ |
496 | <|> TextSize, TextRange};", | 496 | $0 TextSize, TextRange};", |
497 | ); | 497 | ); |
498 | } | 498 | } |
499 | 499 | ||
@@ -502,14 +502,14 @@ use syntax::{ | |||
502 | check_join_lines( | 502 | check_join_lines( |
503 | r" | 503 | r" |
504 | use syntax::{ | 504 | use syntax::{ |
505 | algo::<|>{ | 505 | algo::$0{ |
506 | find_token_at_offset, | 506 | find_token_at_offset, |
507 | }, | 507 | }, |
508 | ast, | 508 | ast, |
509 | };", | 509 | };", |
510 | r" | 510 | r" |
511 | use syntax::{ | 511 | use syntax::{ |
512 | algo::<|>find_token_at_offset, | 512 | algo::$0find_token_at_offset, |
513 | ast, | 513 | ast, |
514 | };", | 514 | };", |
515 | ); | 515 | ); |
@@ -520,13 +520,13 @@ use syntax::{ | |||
520 | check_join_lines( | 520 | check_join_lines( |
521 | r" | 521 | r" |
522 | fn foo() { | 522 | fn foo() { |
523 | // Hello<|> | 523 | // Hello$0 |
524 | // world! | 524 | // world! |
525 | } | 525 | } |
526 | ", | 526 | ", |
527 | r" | 527 | r" |
528 | fn foo() { | 528 | fn foo() { |
529 | // Hello<|> world! | 529 | // Hello$0 world! |
530 | } | 530 | } |
531 | ", | 531 | ", |
532 | ); | 532 | ); |
@@ -537,13 +537,13 @@ fn foo() { | |||
537 | check_join_lines( | 537 | check_join_lines( |
538 | r" | 538 | r" |
539 | fn foo() { | 539 | fn foo() { |
540 | /// Hello<|> | 540 | /// Hello$0 |
541 | /// world! | 541 | /// world! |
542 | } | 542 | } |
543 | ", | 543 | ", |
544 | r" | 544 | r" |
545 | fn foo() { | 545 | fn foo() { |
546 | /// Hello<|> world! | 546 | /// Hello$0 world! |
547 | } | 547 | } |
548 | ", | 548 | ", |
549 | ); | 549 | ); |
@@ -554,13 +554,13 @@ fn foo() { | |||
554 | check_join_lines( | 554 | check_join_lines( |
555 | r" | 555 | r" |
556 | fn foo() { | 556 | fn foo() { |
557 | //! Hello<|> | 557 | //! Hello$0 |
558 | //! world! | 558 | //! world! |
559 | } | 559 | } |
560 | ", | 560 | ", |
561 | r" | 561 | r" |
562 | fn foo() { | 562 | fn foo() { |
563 | //! Hello<|> world! | 563 | //! Hello$0 world! |
564 | } | 564 | } |
565 | ", | 565 | ", |
566 | ); | 566 | ); |
@@ -571,13 +571,13 @@ fn foo() { | |||
571 | check_join_lines( | 571 | check_join_lines( |
572 | r" | 572 | r" |
573 | fn foo() { | 573 | fn foo() { |
574 | // Hello<|> | 574 | // Hello$0 |
575 | /* world! */ | 575 | /* world! */ |
576 | } | 576 | } |
577 | ", | 577 | ", |
578 | r" | 578 | r" |
579 | fn foo() { | 579 | fn foo() { |
580 | // Hello<|> world! */ | 580 | // Hello$0 world! */ |
581 | } | 581 | } |
582 | ", | 582 | ", |
583 | ); | 583 | ); |
@@ -588,7 +588,7 @@ fn foo() { | |||
588 | check_join_lines( | 588 | check_join_lines( |
589 | r" | 589 | r" |
590 | fn foo() { | 590 | fn foo() { |
591 | // The<|> | 591 | // The$0 |
592 | /* quick | 592 | /* quick |
593 | brown | 593 | brown |
594 | fox! */ | 594 | fox! */ |
@@ -596,7 +596,7 @@ fn foo() { | |||
596 | ", | 596 | ", |
597 | r" | 597 | r" |
598 | fn foo() { | 598 | fn foo() { |
599 | // The<|> quick | 599 | // The$0 quick |
600 | brown | 600 | brown |
601 | fox! */ | 601 | fox! */ |
602 | } | 602 | } |
@@ -604,8 +604,8 @@ fn foo() { | |||
604 | ); | 604 | ); |
605 | } | 605 | } |
606 | 606 | ||
607 | fn check_join_lines_sel(before: &str, after: &str) { | 607 | fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { |
608 | let (sel, before) = extract_range(before); | 608 | let (sel, before) = extract_range(ra_fixture_before); |
609 | let parse = SourceFile::parse(&before); | 609 | let parse = SourceFile::parse(&before); |
610 | let result = join_lines(&parse.tree(), sel); | 610 | let result = join_lines(&parse.tree(), sel); |
611 | let actual = { | 611 | let actual = { |
@@ -613,7 +613,7 @@ fn foo() { | |||
613 | result.apply(&mut actual); | 613 | result.apply(&mut actual); |
614 | actual | 614 | actual |
615 | }; | 615 | }; |
616 | assert_eq_text!(after, &actual); | 616 | assert_eq_text!(ra_fixture_after, &actual); |
617 | } | 617 | } |
618 | 618 | ||
619 | #[test] | 619 | #[test] |
@@ -621,10 +621,10 @@ fn foo() { | |||
621 | check_join_lines_sel( | 621 | check_join_lines_sel( |
622 | r" | 622 | r" |
623 | fn foo() { | 623 | fn foo() { |
624 | <|>foo(1, | 624 | $0foo(1, |
625 | 2, | 625 | 2, |
626 | 3, | 626 | 3, |
627 | <|>) | 627 | $0) |
628 | } | 628 | } |
629 | ", | 629 | ", |
630 | r" | 630 | r" |
@@ -639,9 +639,9 @@ fn foo() { | |||
639 | fn test_join_lines_selection_struct() { | 639 | fn test_join_lines_selection_struct() { |
640 | check_join_lines_sel( | 640 | check_join_lines_sel( |
641 | r" | 641 | r" |
642 | struct Foo <|>{ | 642 | struct Foo $0{ |
643 | f: u32, | 643 | f: u32, |
644 | }<|> | 644 | }$0 |
645 | ", | 645 | ", |
646 | r" | 646 | r" |
647 | struct Foo { f: u32 } | 647 | struct Foo { f: u32 } |
@@ -654,9 +654,9 @@ struct Foo { f: u32 } | |||
654 | check_join_lines_sel( | 654 | check_join_lines_sel( |
655 | r" | 655 | r" |
656 | fn foo() { | 656 | fn foo() { |
657 | join(<|>type_params.type_params() | 657 | join($0type_params.type_params() |
658 | .filter_map(|it| it.name()) | 658 | .filter_map(|it| it.name()) |
659 | .map(|it| it.text())<|>) | 659 | .map(|it| it.text())$0) |
660 | }", | 660 | }", |
661 | r" | 661 | r" |
662 | fn foo() { | 662 | fn foo() { |
@@ -671,9 +671,9 @@ fn foo() { | |||
671 | r" | 671 | r" |
672 | pub fn handle_find_matching_brace() { | 672 | pub fn handle_find_matching_brace() { |
673 | params.offsets | 673 | params.offsets |
674 | .map(|offset| <|>{ | 674 | .map(|offset| $0{ |
675 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) | 675 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) |
676 | }<|>) | 676 | }$0) |
677 | .collect(); | 677 | .collect(); |
678 | }", | 678 | }", |
679 | r" | 679 | r" |
@@ -691,7 +691,7 @@ pub fn handle_find_matching_brace() { | |||
691 | r" | 691 | r" |
692 | fn main() { | 692 | fn main() { |
693 | let _ = { | 693 | let _ = { |
694 | // <|>foo | 694 | // $0foo |
695 | // bar | 695 | // bar |
696 | 92 | 696 | 92 |
697 | }; | 697 | }; |
@@ -700,7 +700,7 @@ fn main() { | |||
700 | r" | 700 | r" |
701 | fn main() { | 701 | fn main() { |
702 | let _ = { | 702 | let _ = { |
703 | // <|>foo bar | 703 | // $0foo bar |
704 | 92 | 704 | 92 |
705 | }; | 705 | }; |
706 | } | 706 | } |
@@ -712,12 +712,12 @@ fn main() { | |||
712 | fn join_lines_mandatory_blocks_block() { | 712 | fn join_lines_mandatory_blocks_block() { |
713 | check_join_lines( | 713 | check_join_lines( |
714 | r" | 714 | r" |
715 | <|>fn foo() { | 715 | $0fn foo() { |
716 | 92 | 716 | 92 |
717 | } | 717 | } |
718 | ", | 718 | ", |
719 | r" | 719 | r" |
720 | <|>fn foo() { 92 | 720 | $0fn foo() { 92 |
721 | } | 721 | } |
722 | ", | 722 | ", |
723 | ); | 723 | ); |
@@ -725,14 +725,14 @@ fn main() { | |||
725 | check_join_lines( | 725 | check_join_lines( |
726 | r" | 726 | r" |
727 | fn foo() { | 727 | fn foo() { |
728 | <|>if true { | 728 | $0if true { |
729 | 92 | 729 | 92 |
730 | } | 730 | } |
731 | } | 731 | } |
732 | ", | 732 | ", |
733 | r" | 733 | r" |
734 | fn foo() { | 734 | fn foo() { |
735 | <|>if true { 92 | 735 | $0if true { 92 |
736 | } | 736 | } |
737 | } | 737 | } |
738 | ", | 738 | ", |
@@ -741,14 +741,14 @@ fn foo() { | |||
741 | check_join_lines( | 741 | check_join_lines( |
742 | r" | 742 | r" |
743 | fn foo() { | 743 | fn foo() { |
744 | <|>loop { | 744 | $0loop { |
745 | 92 | 745 | 92 |
746 | } | 746 | } |
747 | } | 747 | } |
748 | ", | 748 | ", |
749 | r" | 749 | r" |
750 | fn foo() { | 750 | fn foo() { |
751 | <|>loop { 92 | 751 | $0loop { 92 |
752 | } | 752 | } |
753 | } | 753 | } |
754 | ", | 754 | ", |
@@ -757,14 +757,14 @@ fn foo() { | |||
757 | check_join_lines( | 757 | check_join_lines( |
758 | r" | 758 | r" |
759 | fn foo() { | 759 | fn foo() { |
760 | <|>unsafe { | 760 | $0unsafe { |
761 | 92 | 761 | 92 |
762 | } | 762 | } |
763 | } | 763 | } |
764 | ", | 764 | ", |
765 | r" | 765 | r" |
766 | fn foo() { | 766 | fn foo() { |
767 | <|>unsafe { 92 | 767 | $0unsafe { 92 |
768 | } | 768 | } |
769 | } | 769 | } |
770 | ", | 770 | ", |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index cea2a13c8..6c94c26b5 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -76,29 +76,26 @@ pub use crate::{ | |||
76 | references::{rename::RenameError, Declaration, ReferenceSearchResult}, | 76 | references::{rename::RenameError, Declaration, ReferenceSearchResult}, |
77 | runnables::{Runnable, RunnableKind, TestId}, | 77 | runnables::{Runnable, RunnableKind, TestId}, |
78 | syntax_highlighting::{ | 78 | syntax_highlighting::{ |
79 | tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}, | 79 | tags::{Highlight, HlMod, HlMods, HlPunct, HlTag}, |
80 | HighlightedRange, | 80 | HlRange, |
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; | 83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; |
84 | pub use completion::{ | 84 | pub use completion::{ |
85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, | 85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, |
86 | InsertTextFormat, | 86 | InsertTextFormat, |
87 | }; | 87 | }; |
88 | pub use hir::{Documentation, Semantics}; | 88 | pub use hir::{Documentation, Semantics}; |
89 | pub use ide_db::base_db::{ | ||
90 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, | ||
91 | SourceRootId, | ||
92 | }; | ||
93 | pub use ide_db::{ | 89 | pub use ide_db::{ |
90 | base_db::{ | ||
91 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, | ||
92 | SourceRoot, SourceRootId, | ||
93 | }, | ||
94 | call_info::CallInfo, | 94 | call_info::CallInfo, |
95 | search::{Reference, ReferenceAccess, ReferenceKind}, | ||
96 | }; | ||
97 | pub use ide_db::{ | ||
98 | label::Label, | 95 | label::Label, |
99 | line_index::{LineCol, LineIndex}, | 96 | line_index::{LineCol, LineIndex}, |
100 | search::SearchScope, | 97 | search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope}, |
101 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 98 | source_change::{FileSystemEdit, SourceChange}, |
102 | symbol_index::Query, | 99 | symbol_index::Query, |
103 | RootDatabase, | 100 | RootDatabase, |
104 | }; | 101 | }; |
@@ -449,12 +446,12 @@ impl Analysis { | |||
449 | } | 446 | } |
450 | 447 | ||
451 | /// Computes syntax highlighting for the given file | 448 | /// Computes syntax highlighting for the given file |
452 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 449 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HlRange>> { |
453 | self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) | 450 | self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) |
454 | } | 451 | } |
455 | 452 | ||
456 | /// Computes syntax highlighting for the given file range. | 453 | /// Computes syntax highlighting for the given file range. |
457 | pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> { | 454 | pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HlRange>> { |
458 | self.with_db(|db| { | 455 | self.with_db(|db| { |
459 | syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) | 456 | syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) |
460 | }) | 457 | }) |
@@ -553,7 +550,7 @@ impl Analysis { | |||
553 | let rule: ssr::SsrRule = query.parse()?; | 550 | let rule: ssr::SsrRule = query.parse()?; |
554 | let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections); | 551 | let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections); |
555 | match_finder.add_rule(rule)?; | 552 | match_finder.add_rule(rule)?; |
556 | let edits = if parse_only { Vec::new() } else { match_finder.edits() }; | 553 | let edits = if parse_only { Default::default() } else { match_finder.edits() }; |
557 | Ok(SourceChange::from(edits)) | 554 | Ok(SourceChange::from(edits)) |
558 | }) | 555 | }) |
559 | } | 556 | } |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index d70248afe..1bfa1439d 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -58,15 +58,15 @@ mod tests { | |||
58 | assert_eq_text!(after, &actual); | 58 | assert_eq_text!(after, &actual); |
59 | } | 59 | } |
60 | 60 | ||
61 | do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); | 61 | do_check("struct Foo { a: i32, }$0", "struct Foo $0{ a: i32, }"); |
62 | do_check("fn main() { |x: i32|<|> x * 2;}", "fn main() { <|>|x: i32| x * 2;}"); | 62 | do_check("fn main() { |x: i32|$0 x * 2;}", "fn main() { $0|x: i32| x * 2;}"); |
63 | do_check("fn main() { <|>|x: i32| x * 2;}", "fn main() { |x: i32<|>| x * 2;}"); | 63 | do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); |
64 | 64 | ||
65 | { | 65 | { |
66 | mark::check!(pipes_not_braces); | 66 | mark::check!(pipes_not_braces); |
67 | do_check( | 67 | do_check( |
68 | "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", | 68 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
69 | "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", | 69 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
70 | ); | 70 | ); |
71 | } | 71 | } |
72 | } | 72 | } |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index be344a09b..d343638fb 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -74,7 +74,7 @@ mod tests { | |||
74 | //- /lib.rs | 74 | //- /lib.rs |
75 | mod foo; | 75 | mod foo; |
76 | //- /foo.rs | 76 | //- /foo.rs |
77 | <|>// empty | 77 | $0// empty |
78 | ", | 78 | ", |
79 | ); | 79 | ); |
80 | let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); | 80 | let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); |
@@ -90,7 +90,7 @@ mod tests { | |||
90 | mod foo; | 90 | mod foo; |
91 | 91 | ||
92 | //- /foo.rs | 92 | //- /foo.rs |
93 | mod <|>bar; | 93 | mod $0bar; |
94 | 94 | ||
95 | //- /foo/bar.rs | 95 | //- /foo/bar.rs |
96 | // empty | 96 | // empty |
@@ -107,7 +107,7 @@ mod tests { | |||
107 | //- /lib.rs | 107 | //- /lib.rs |
108 | mod foo { | 108 | mod foo { |
109 | mod bar { | 109 | mod bar { |
110 | mod baz { <|> } | 110 | mod baz { $0 } |
111 | } | 111 | } |
112 | } | 112 | } |
113 | ", | 113 | ", |
@@ -123,7 +123,7 @@ mod tests { | |||
123 | //- /main.rs | 123 | //- /main.rs |
124 | mod foo; | 124 | mod foo; |
125 | //- /foo.rs | 125 | //- /foo.rs |
126 | <|> | 126 | $0 |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); | 129 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index fa58fc319..df9c31aef 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | //! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we | 3 | //! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we |
4 | //! try to resolve the direct tree parent of this element, otherwise we | 4 | //! try to resolve the direct tree parent of this element, otherwise we |
5 | //! already have a definition and just need to get its HIR together with | 5 | //! already have a definition and just need to get its HIR together with |
6 | //! some information that is needed for futher steps of searching. | 6 | //! some information that is needed for further steps of searching. |
7 | //! After that, we collect files that might contain references and look | 7 | //! After that, we collect files that might contain references and look |
8 | //! for text occurrences of the identifier. If there's an `ast::NameRef` | 8 | //! for text occurrences of the identifier. If there's an `ast::NameRef` |
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
@@ -11,25 +11,26 @@ | |||
11 | 11 | ||
12 | pub(crate) mod rename; | 12 | pub(crate) mod rename; |
13 | 13 | ||
14 | use either::Either; | ||
14 | use hir::Semantics; | 15 | use hir::Semantics; |
15 | use ide_db::{ | 16 | use ide_db::{ |
17 | base_db::FileId, | ||
16 | defs::{Definition, NameClass, NameRefClass}, | 18 | defs::{Definition, NameClass, NameRefClass}, |
17 | search::Reference, | 19 | search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult}, |
18 | search::{ReferenceAccess, ReferenceKind, SearchScope}, | ||
19 | RootDatabase, | 20 | RootDatabase, |
20 | }; | 21 | }; |
21 | use syntax::{ | 22 | use syntax::{ |
22 | algo::find_node_at_offset, | 23 | algo::find_node_at_offset, |
23 | ast::{self, NameOwner}, | 24 | ast::{self, NameOwner}, |
24 | match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, | 25 | AstNode, SyntaxNode, TextRange, TokenAtOffset, T, |
25 | }; | 26 | }; |
26 | 27 | ||
27 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; | 28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
28 | 29 | ||
29 | #[derive(Debug, Clone)] | 30 | #[derive(Debug, Clone)] |
30 | pub struct ReferenceSearchResult { | 31 | pub struct ReferenceSearchResult { |
31 | declaration: Declaration, | 32 | declaration: Declaration, |
32 | references: Vec<Reference>, | 33 | references: UsageSearchResult, |
33 | } | 34 | } |
34 | 35 | ||
35 | #[derive(Debug, Clone)] | 36 | #[derive(Debug, Clone)] |
@@ -48,10 +49,21 @@ impl ReferenceSearchResult { | |||
48 | &self.declaration.nav | 49 | &self.declaration.nav |
49 | } | 50 | } |
50 | 51 | ||
51 | pub fn references(&self) -> &[Reference] { | 52 | pub fn references(&self) -> &UsageSearchResult { |
52 | &self.references | 53 | &self.references |
53 | } | 54 | } |
54 | 55 | ||
56 | pub fn references_with_declaration(mut self) -> UsageSearchResult { | ||
57 | let decl_ref = FileReference { | ||
58 | range: self.declaration.nav.focus_or_full_range(), | ||
59 | kind: self.declaration.kind, | ||
60 | access: self.declaration.access, | ||
61 | }; | ||
62 | let file_id = self.declaration.nav.file_id; | ||
63 | self.references.references.entry(file_id).or_default().push(decl_ref); | ||
64 | self.references | ||
65 | } | ||
66 | |||
55 | /// Total number of references | 67 | /// Total number of references |
56 | /// At least 1 since all valid references should | 68 | /// At least 1 since all valid references should |
57 | /// Have a declaration | 69 | /// Have a declaration |
@@ -63,21 +75,11 @@ impl ReferenceSearchResult { | |||
63 | // allow turning ReferenceSearchResult into an iterator | 75 | // allow turning ReferenceSearchResult into an iterator |
64 | // over References | 76 | // over References |
65 | impl IntoIterator for ReferenceSearchResult { | 77 | impl IntoIterator for ReferenceSearchResult { |
66 | type Item = Reference; | 78 | type Item = (FileId, Vec<FileReference>); |
67 | type IntoIter = std::vec::IntoIter<Reference>; | 79 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>; |
68 | 80 | ||
69 | fn into_iter(mut self) -> Self::IntoIter { | 81 | fn into_iter(self) -> Self::IntoIter { |
70 | let mut v = Vec::with_capacity(self.len()); | 82 | self.references_with_declaration().into_iter() |
71 | v.push(Reference { | ||
72 | file_range: FileRange { | ||
73 | file_id: self.declaration.nav.file_id, | ||
74 | range: self.declaration.nav.focus_or_full_range(), | ||
75 | }, | ||
76 | kind: self.declaration.kind, | ||
77 | access: self.declaration.access, | ||
78 | }); | ||
79 | v.append(&mut self.references); | ||
80 | v.into_iter() | ||
81 | } | 83 | } |
82 | } | 84 | } |
83 | 85 | ||
@@ -89,10 +91,6 @@ pub(crate) fn find_all_refs( | |||
89 | let _p = profile::span("find_all_refs"); | 91 | let _p = profile::span("find_all_refs"); |
90 | let syntax = sema.parse(position.file_id).syntax().clone(); | 92 | let syntax = sema.parse(position.file_id).syntax().clone(); |
91 | 93 | ||
92 | if let Some(res) = try_find_self_references(&syntax, position) { | ||
93 | return Some(res); | ||
94 | } | ||
95 | |||
96 | let (opt_name, search_kind) = if let Some(name) = | 94 | let (opt_name, search_kind) = if let Some(name) = |
97 | get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) | 95 | get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) |
98 | { | 96 | { |
@@ -109,34 +107,39 @@ pub(crate) fn find_all_refs( | |||
109 | 107 | ||
110 | let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; | 108 | let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; |
111 | 109 | ||
112 | let references = def | 110 | let mut usages = def.usages(sema).set_scope(search_scope).all(); |
113 | .usages(sema) | 111 | usages |
114 | .set_scope(search_scope) | 112 | .references |
115 | .all() | 113 | .values_mut() |
116 | .into_iter() | 114 | .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)); |
117 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) | 115 | usages.references.retain(|_, it| !it.is_empty()); |
118 | .collect(); | ||
119 | 116 | ||
120 | let nav = def.try_to_nav(sema.db)?; | 117 | let nav = def.try_to_nav(sema.db)?; |
121 | let decl_range = nav.focus_or_full_range(); | 118 | let decl_range = nav.focus_or_full_range(); |
122 | 119 | ||
123 | let mut kind = ReferenceKind::Other; | 120 | let mut kind = ReferenceKind::Other; |
124 | if let Definition::Local(local) = def { | 121 | if let Definition::Local(local) = def { |
125 | if let either::Either::Left(pat) = local.source(sema.db).value { | 122 | match local.source(sema.db).value { |
126 | if matches!( | 123 | Either::Left(pat) => { |
127 | pat.syntax().parent().and_then(ast::RecordPatField::cast), | 124 | if matches!( |
128 | Some(pat_field) if pat_field.name_ref().is_none() | 125 | pat.syntax().parent().and_then(ast::RecordPatField::cast), |
129 | ) { | 126 | Some(pat_field) if pat_field.name_ref().is_none() |
130 | kind = ReferenceKind::FieldShorthandForLocal; | 127 | ) { |
128 | kind = ReferenceKind::FieldShorthandForLocal; | ||
129 | } | ||
131 | } | 130 | } |
131 | Either::Right(_) => kind = ReferenceKind::SelfParam, | ||
132 | } | 132 | } |
133 | } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { | 133 | } else if matches!( |
134 | def, | ||
135 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
136 | ) { | ||
134 | kind = ReferenceKind::Lifetime; | 137 | kind = ReferenceKind::Lifetime; |
135 | }; | 138 | }; |
136 | 139 | ||
137 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; | 140 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; |
138 | 141 | ||
139 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) | 142 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages })) |
140 | } | 143 | } |
141 | 144 | ||
142 | fn find_name( | 145 | fn find_name( |
@@ -200,7 +203,7 @@ fn get_struct_def_name_for_struct_literal_search( | |||
200 | position: FilePosition, | 203 | position: FilePosition, |
201 | ) -> Option<ast::Name> { | 204 | ) -> Option<ast::Name> { |
202 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 205 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { |
203 | if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { | 206 | if right.kind() != T!['{'] && right.kind() != T!['('] { |
204 | return None; | 207 | return None; |
205 | } | 208 | } |
206 | if let Some(name) = | 209 | if let Some(name) = |
@@ -227,7 +230,7 @@ fn get_enum_def_name_for_struct_literal_search( | |||
227 | position: FilePosition, | 230 | position: FilePosition, |
228 | ) -> Option<ast::Name> { | 231 | ) -> Option<ast::Name> { |
229 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 232 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { |
230 | if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { | 233 | if right.kind() != T!['{'] && right.kind() != T!['('] { |
231 | return None; | 234 | return None; |
232 | } | 235 | } |
233 | if let Some(name) = | 236 | if let Some(name) = |
@@ -248,77 +251,6 @@ fn get_enum_def_name_for_struct_literal_search( | |||
248 | None | 251 | None |
249 | } | 252 | } |
250 | 253 | ||
251 | fn try_find_self_references( | ||
252 | syntax: &SyntaxNode, | ||
253 | position: FilePosition, | ||
254 | ) -> Option<RangeInfo<ReferenceSearchResult>> { | ||
255 | let self_token = | ||
256 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?; | ||
257 | let parent = self_token.parent(); | ||
258 | match_ast! { | ||
259 | match parent { | ||
260 | ast::SelfParam(it) => (), | ||
261 | ast::PathSegment(segment) => { | ||
262 | segment.self_token()?; | ||
263 | let path = segment.parent_path(); | ||
264 | if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) { | ||
265 | return None; | ||
266 | } | ||
267 | }, | ||
268 | _ => return None, | ||
269 | } | ||
270 | }; | ||
271 | let function = parent.ancestors().find_map(ast::Fn::cast)?; | ||
272 | let self_param = function.param_list()?.self_param()?; | ||
273 | let param_self_token = self_param.self_token()?; | ||
274 | |||
275 | let declaration = Declaration { | ||
276 | nav: NavigationTarget { | ||
277 | file_id: position.file_id, | ||
278 | full_range: self_param.syntax().text_range(), | ||
279 | focus_range: Some(param_self_token.text_range()), | ||
280 | name: param_self_token.text().clone(), | ||
281 | kind: Some(SymbolKind::SelfParam), | ||
282 | container_name: None, | ||
283 | description: None, | ||
284 | docs: None, | ||
285 | }, | ||
286 | kind: ReferenceKind::SelfKw, | ||
287 | access: Some(if self_param.mut_token().is_some() { | ||
288 | ReferenceAccess::Write | ||
289 | } else { | ||
290 | ReferenceAccess::Read | ||
291 | }), | ||
292 | }; | ||
293 | let references = function | ||
294 | .body() | ||
295 | .map(|body| { | ||
296 | body.syntax() | ||
297 | .descendants() | ||
298 | .filter_map(ast::PathExpr::cast) | ||
299 | .filter_map(|expr| { | ||
300 | let path = expr.path()?; | ||
301 | if path.qualifier().is_none() { | ||
302 | path.segment()?.self_token() | ||
303 | } else { | ||
304 | None | ||
305 | } | ||
306 | }) | ||
307 | .map(|token| Reference { | ||
308 | file_range: FileRange { file_id: position.file_id, range: token.text_range() }, | ||
309 | kind: ReferenceKind::SelfKw, | ||
310 | access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration | ||
311 | }) | ||
312 | .collect() | ||
313 | }) | ||
314 | .unwrap_or_default(); | ||
315 | |||
316 | Some(RangeInfo::new( | ||
317 | param_self_token.text_range(), | ||
318 | ReferenceSearchResult { declaration, references }, | ||
319 | )) | ||
320 | } | ||
321 | |||
322 | #[cfg(test)] | 254 | #[cfg(test)] |
323 | mod tests { | 255 | mod tests { |
324 | use expect_test::{expect, Expect}; | 256 | use expect_test::{expect, Expect}; |
@@ -331,7 +263,7 @@ mod tests { | |||
331 | fn test_struct_literal_after_space() { | 263 | fn test_struct_literal_after_space() { |
332 | check( | 264 | check( |
333 | r#" | 265 | r#" |
334 | struct Foo <|>{ | 266 | struct Foo $0{ |
335 | a: i32, | 267 | a: i32, |
336 | } | 268 | } |
337 | impl Foo { | 269 | impl Foo { |
@@ -354,7 +286,7 @@ fn main() { | |||
354 | fn test_struct_literal_before_space() { | 286 | fn test_struct_literal_before_space() { |
355 | check( | 287 | check( |
356 | r#" | 288 | r#" |
357 | struct Foo<|> {} | 289 | struct Foo$0 {} |
358 | fn main() { | 290 | fn main() { |
359 | let f: Foo; | 291 | let f: Foo; |
360 | f = Foo {}; | 292 | f = Foo {}; |
@@ -373,7 +305,7 @@ struct Foo<|> {} | |||
373 | fn test_struct_literal_with_generic_type() { | 305 | fn test_struct_literal_with_generic_type() { |
374 | check( | 306 | check( |
375 | r#" | 307 | r#" |
376 | struct Foo<T> <|>{} | 308 | struct Foo<T> $0{} |
377 | fn main() { | 309 | fn main() { |
378 | let f: Foo::<i32>; | 310 | let f: Foo::<i32>; |
379 | f = Foo {}; | 311 | f = Foo {}; |
@@ -391,7 +323,7 @@ struct Foo<T> <|>{} | |||
391 | fn test_struct_literal_for_tuple() { | 323 | fn test_struct_literal_for_tuple() { |
392 | check( | 324 | check( |
393 | r#" | 325 | r#" |
394 | struct Foo<|>(i32); | 326 | struct Foo$0(i32); |
395 | 327 | ||
396 | fn main() { | 328 | fn main() { |
397 | let f: Foo; | 329 | let f: Foo; |
@@ -410,7 +342,7 @@ fn main() { | |||
410 | fn test_enum_after_space() { | 342 | fn test_enum_after_space() { |
411 | check( | 343 | check( |
412 | r#" | 344 | r#" |
413 | enum Foo <|>{ | 345 | enum Foo $0{ |
414 | A, | 346 | A, |
415 | B, | 347 | B, |
416 | } | 348 | } |
@@ -431,7 +363,7 @@ fn main() { | |||
431 | fn test_enum_before_space() { | 363 | fn test_enum_before_space() { |
432 | check( | 364 | check( |
433 | r#" | 365 | r#" |
434 | enum Foo<|> { | 366 | enum Foo$0 { |
435 | A, | 367 | A, |
436 | B, | 368 | B, |
437 | } | 369 | } |
@@ -453,7 +385,7 @@ fn main() { | |||
453 | fn test_enum_with_generic_type() { | 385 | fn test_enum_with_generic_type() { |
454 | check( | 386 | check( |
455 | r#" | 387 | r#" |
456 | enum Foo<T> <|>{ | 388 | enum Foo<T> $0{ |
457 | A(T), | 389 | A(T), |
458 | B, | 390 | B, |
459 | } | 391 | } |
@@ -474,7 +406,7 @@ fn main() { | |||
474 | fn test_enum_for_tuple() { | 406 | fn test_enum_for_tuple() { |
475 | check( | 407 | check( |
476 | r#" | 408 | r#" |
477 | enum Foo<|>{ | 409 | enum Foo$0{ |
478 | A(i8), | 410 | A(i8), |
479 | B(i8), | 411 | B(i8), |
480 | } | 412 | } |
@@ -498,7 +430,7 @@ fn main() { | |||
498 | fn main() { | 430 | fn main() { |
499 | let mut i = 1; | 431 | let mut i = 1; |
500 | let j = 1; | 432 | let j = 1; |
501 | i = i<|> + j; | 433 | i = i$0 + j; |
502 | 434 | ||
503 | { | 435 | { |
504 | i = 0; | 436 | i = 0; |
@@ -507,7 +439,7 @@ fn main() { | |||
507 | i = 5; | 439 | i = 5; |
508 | }"#, | 440 | }"#, |
509 | expect![[r#" | 441 | expect![[r#" |
510 | i Local FileId(0) 24..25 Other Write | 442 | i Local FileId(0) 20..25 24..25 Other Write |
511 | 443 | ||
512 | FileId(0) 50..51 Other Write | 444 | FileId(0) 50..51 Other Write |
513 | FileId(0) 54..55 Other Read | 445 | FileId(0) 54..55 Other Read |
@@ -522,7 +454,7 @@ fn main() { | |||
522 | check( | 454 | check( |
523 | r#" | 455 | r#" |
524 | fn foo() { | 456 | fn foo() { |
525 | let spam<|> = 92; | 457 | let spam$0 = 92; |
526 | spam + spam | 458 | spam + spam |
527 | } | 459 | } |
528 | fn bar() { | 460 | fn bar() { |
@@ -531,7 +463,7 @@ fn bar() { | |||
531 | } | 463 | } |
532 | "#, | 464 | "#, |
533 | expect![[r#" | 465 | expect![[r#" |
534 | spam Local FileId(0) 19..23 Other | 466 | spam Local FileId(0) 19..23 19..23 Other |
535 | 467 | ||
536 | FileId(0) 34..38 Other Read | 468 | FileId(0) 34..38 Other Read |
537 | FileId(0) 41..45 Other Read | 469 | FileId(0) 41..45 Other Read |
@@ -543,10 +475,10 @@ fn bar() { | |||
543 | fn test_find_all_refs_for_param_inside() { | 475 | fn test_find_all_refs_for_param_inside() { |
544 | check( | 476 | check( |
545 | r#" | 477 | r#" |
546 | fn foo(i : u32) -> u32 { i<|> } | 478 | fn foo(i : u32) -> u32 { i$0 } |
547 | "#, | 479 | "#, |
548 | expect![[r#" | 480 | expect![[r#" |
549 | i ValueParam FileId(0) 7..8 Other | 481 | i ValueParam FileId(0) 7..8 7..8 Other |
550 | 482 | ||
551 | FileId(0) 25..26 Other Read | 483 | FileId(0) 25..26 Other Read |
552 | "#]], | 484 | "#]], |
@@ -557,10 +489,10 @@ fn foo(i : u32) -> u32 { i<|> } | |||
557 | fn test_find_all_refs_for_fn_param() { | 489 | fn test_find_all_refs_for_fn_param() { |
558 | check( | 490 | check( |
559 | r#" | 491 | r#" |
560 | fn foo(i<|> : u32) -> u32 { i } | 492 | fn foo(i$0 : u32) -> u32 { i } |
561 | "#, | 493 | "#, |
562 | expect![[r#" | 494 | expect![[r#" |
563 | i ValueParam FileId(0) 7..8 Other | 495 | i ValueParam FileId(0) 7..8 7..8 Other |
564 | 496 | ||
565 | FileId(0) 25..26 Other Read | 497 | FileId(0) 25..26 Other Read |
566 | "#]], | 498 | "#]], |
@@ -573,7 +505,7 @@ fn foo(i<|> : u32) -> u32 { i } | |||
573 | r#" | 505 | r#" |
574 | //- /lib.rs | 506 | //- /lib.rs |
575 | struct Foo { | 507 | struct Foo { |
576 | pub spam<|>: u32, | 508 | pub spam$0: u32, |
577 | } | 509 | } |
578 | 510 | ||
579 | fn main(s: Foo) { | 511 | fn main(s: Foo) { |
@@ -594,7 +526,7 @@ fn main(s: Foo) { | |||
594 | r#" | 526 | r#" |
595 | struct Foo; | 527 | struct Foo; |
596 | impl Foo { | 528 | impl Foo { |
597 | fn f<|>(&self) { } | 529 | fn f$0(&self) { } |
598 | } | 530 | } |
599 | "#, | 531 | "#, |
600 | expect![[r#" | 532 | expect![[r#" |
@@ -610,7 +542,7 @@ impl Foo { | |||
610 | r#" | 542 | r#" |
611 | enum Foo { | 543 | enum Foo { |
612 | A, | 544 | A, |
613 | B<|>, | 545 | B$0, |
614 | C, | 546 | C, |
615 | } | 547 | } |
616 | "#, | 548 | "#, |
@@ -627,7 +559,7 @@ enum Foo { | |||
627 | r#" | 559 | r#" |
628 | enum Foo { | 560 | enum Foo { |
629 | A, | 561 | A, |
630 | B { field<|>: u8 }, | 562 | B { field$0: u8 }, |
631 | C, | 563 | C, |
632 | } | 564 | } |
633 | "#, | 565 | "#, |
@@ -669,7 +601,7 @@ pub struct Bar { | |||
669 | } | 601 | } |
670 | 602 | ||
671 | fn f() { | 603 | fn f() { |
672 | let i = foo::Foo<|> { n: 5 }; | 604 | let i = foo::Foo$0 { n: 5 }; |
673 | } | 605 | } |
674 | "#, | 606 | "#, |
675 | expect![[r#" | 607 | expect![[r#" |
@@ -689,7 +621,7 @@ fn f() { | |||
689 | check( | 621 | check( |
690 | r#" | 622 | r#" |
691 | //- /lib.rs | 623 | //- /lib.rs |
692 | mod foo<|>; | 624 | mod foo$0; |
693 | 625 | ||
694 | use foo::Foo; | 626 | use foo::Foo; |
695 | 627 | ||
@@ -726,7 +658,7 @@ fn f() { | |||
726 | } | 658 | } |
727 | 659 | ||
728 | //- /foo/some.rs | 660 | //- /foo/some.rs |
729 | pub(super) struct Foo<|> { | 661 | pub(super) struct Foo$0 { |
730 | pub n: u32, | 662 | pub n: u32, |
731 | } | 663 | } |
732 | "#, | 664 | "#, |
@@ -746,7 +678,7 @@ pub(super) struct Foo<|> { | |||
746 | mod foo; | 678 | mod foo; |
747 | mod bar; | 679 | mod bar; |
748 | 680 | ||
749 | pub fn quux<|>() {} | 681 | pub fn quux$0() {} |
750 | 682 | ||
751 | //- /foo.rs | 683 | //- /foo.rs |
752 | fn f() { super::quux(); } | 684 | fn f() { super::quux(); } |
@@ -782,7 +714,7 @@ pub(super) struct Foo<|> { | |||
782 | check( | 714 | check( |
783 | r#" | 715 | r#" |
784 | #[macro_export] | 716 | #[macro_export] |
785 | macro_rules! m1<|> { () => (()) } | 717 | macro_rules! m1$0 { () => (()) } |
786 | 718 | ||
787 | fn foo() { | 719 | fn foo() { |
788 | m1(); | 720 | m1(); |
@@ -803,12 +735,12 @@ fn foo() { | |||
803 | check( | 735 | check( |
804 | r#" | 736 | r#" |
805 | fn foo() { | 737 | fn foo() { |
806 | let mut i<|> = 0; | 738 | let mut i$0 = 0; |
807 | i = i + 1; | 739 | i = i + 1; |
808 | } | 740 | } |
809 | "#, | 741 | "#, |
810 | expect![[r#" | 742 | expect![[r#" |
811 | i Local FileId(0) 23..24 Other Write | 743 | i Local FileId(0) 19..24 23..24 Other Write |
812 | 744 | ||
813 | FileId(0) 34..35 Other Write | 745 | FileId(0) 34..35 Other Write |
814 | FileId(0) 38..39 Other Read | 746 | FileId(0) 38..39 Other Read |
@@ -826,7 +758,7 @@ struct S { | |||
826 | 758 | ||
827 | fn foo() { | 759 | fn foo() { |
828 | let mut s = S{f: 0}; | 760 | let mut s = S{f: 0}; |
829 | s.f<|> = 0; | 761 | s.f$0 = 0; |
830 | } | 762 | } |
831 | "#, | 763 | "#, |
832 | expect![[r#" | 764 | expect![[r#" |
@@ -843,12 +775,12 @@ fn foo() { | |||
843 | check( | 775 | check( |
844 | r#" | 776 | r#" |
845 | fn foo() { | 777 | fn foo() { |
846 | let i<|>; | 778 | let i$0; |
847 | i = 1; | 779 | i = 1; |
848 | } | 780 | } |
849 | "#, | 781 | "#, |
850 | expect![[r#" | 782 | expect![[r#" |
851 | i Local FileId(0) 19..20 Other | 783 | i Local FileId(0) 19..20 19..20 Other |
852 | 784 | ||
853 | FileId(0) 26..27 Other Write | 785 | FileId(0) 26..27 Other Write |
854 | "#]], | 786 | "#]], |
@@ -863,7 +795,7 @@ mod foo { | |||
863 | pub struct Foo; | 795 | pub struct Foo; |
864 | 796 | ||
865 | impl Foo { | 797 | impl Foo { |
866 | pub fn new<|>() -> Foo { Foo } | 798 | pub fn new$0() -> Foo { Foo } |
867 | } | 799 | } |
868 | } | 800 | } |
869 | 801 | ||
@@ -886,7 +818,7 @@ fn main() { | |||
886 | //- /lib.rs | 818 | //- /lib.rs |
887 | mod foo { mod bar; } | 819 | mod foo { mod bar; } |
888 | 820 | ||
889 | fn f<|>() {} | 821 | fn f$0() {} |
890 | 822 | ||
891 | //- /foo/bar.rs | 823 | //- /foo/bar.rs |
892 | use crate::f; | 824 | use crate::f; |
@@ -907,7 +839,7 @@ fn g() { f(); } | |||
907 | check( | 839 | check( |
908 | r#" | 840 | r#" |
909 | struct S { | 841 | struct S { |
910 | field<|>: u8, | 842 | field$0: u8, |
911 | } | 843 | } |
912 | 844 | ||
913 | fn f(s: S) { | 845 | fn f(s: S) { |
@@ -930,7 +862,7 @@ fn f(s: S) { | |||
930 | r#" | 862 | r#" |
931 | enum En { | 863 | enum En { |
932 | Variant { | 864 | Variant { |
933 | field<|>: u8, | 865 | field$0: u8, |
934 | } | 866 | } |
935 | } | 867 | } |
936 | 868 | ||
@@ -955,7 +887,7 @@ fn f(e: En) { | |||
955 | mod m { | 887 | mod m { |
956 | pub enum En { | 888 | pub enum En { |
957 | Variant { | 889 | Variant { |
958 | field<|>: u8, | 890 | field$0: u8, |
959 | } | 891 | } |
960 | } | 892 | } |
961 | } | 893 | } |
@@ -980,7 +912,7 @@ struct Foo { bar: i32 } | |||
980 | 912 | ||
981 | impl Foo { | 913 | impl Foo { |
982 | fn foo(self) { | 914 | fn foo(self) { |
983 | let x = self<|>.bar; | 915 | let x = self$0.bar; |
984 | if true { | 916 | if true { |
985 | let _ = match () { | 917 | let _ = match () { |
986 | () => self, | 918 | () => self, |
@@ -990,10 +922,30 @@ impl Foo { | |||
990 | } | 922 | } |
991 | "#, | 923 | "#, |
992 | expect![[r#" | 924 | expect![[r#" |
993 | self SelfParam FileId(0) 47..51 47..51 SelfKw Read | 925 | self SelfParam FileId(0) 47..51 47..51 SelfParam |
926 | |||
927 | FileId(0) 71..75 Other Read | ||
928 | FileId(0) 152..156 Other Read | ||
929 | "#]], | ||
930 | ); | ||
931 | } | ||
932 | |||
933 | #[test] | ||
934 | fn test_find_self_refs_decl() { | ||
935 | check( | ||
936 | r#" | ||
937 | struct Foo { bar: i32 } | ||
938 | |||
939 | impl Foo { | ||
940 | fn foo(self$0) { | ||
941 | self; | ||
942 | } | ||
943 | } | ||
944 | "#, | ||
945 | expect![[r#" | ||
946 | self SelfParam FileId(0) 47..51 47..51 SelfParam | ||
994 | 947 | ||
995 | FileId(0) 71..75 SelfKw Read | 948 | FileId(0) 63..67 Other Read |
996 | FileId(0) 152..156 SelfKw Read | ||
997 | "#]], | 949 | "#]], |
998 | ); | 950 | ); |
999 | } | 951 | } |
@@ -1016,12 +968,14 @@ impl Foo { | |||
1016 | actual += "\n\n"; | 968 | actual += "\n\n"; |
1017 | } | 969 | } |
1018 | 970 | ||
1019 | for r in &refs.references { | 971 | for (file_id, references) in refs.references { |
1020 | format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); | 972 | for r in references { |
1021 | if let Some(access) = r.access { | 973 | format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); |
1022 | format_to!(actual, " {:?}", access); | 974 | if let Some(access) = r.access { |
975 | format_to!(actual, " {:?}", access); | ||
976 | } | ||
977 | actual += "\n"; | ||
1023 | } | 978 | } |
1024 | actual += "\n"; | ||
1025 | } | 979 | } |
1026 | expect.assert_eq(&actual) | 980 | expect.assert_eq(&actual) |
1027 | } | 981 | } |
@@ -1032,7 +986,7 @@ impl Foo { | |||
1032 | r#" | 986 | r#" |
1033 | trait Foo<'a> {} | 987 | trait Foo<'a> {} |
1034 | impl<'a> Foo<'a> for &'a () {} | 988 | impl<'a> Foo<'a> for &'a () {} |
1035 | fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { | 989 | fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> { |
1036 | fn bar<'a>(_: &'a ()) {} | 990 | fn bar<'a>(_: &'a ()) {} |
1037 | x | 991 | x |
1038 | } | 992 | } |
@@ -1053,7 +1007,7 @@ fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { | |||
1053 | fn test_find_lifetimes_type_alias() { | 1007 | fn test_find_lifetimes_type_alias() { |
1054 | check( | 1008 | check( |
1055 | r#" | 1009 | r#" |
1056 | type Foo<'a, T> where T: 'a<|> = &'a T; | 1010 | type Foo<'a, T> where T: 'a$0 = &'a T; |
1057 | "#, | 1011 | "#, |
1058 | expect![[r#" | 1012 | expect![[r#" |
1059 | 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime | 1013 | 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime |
@@ -1072,7 +1026,7 @@ trait Foo<'a> { | |||
1072 | fn foo() -> &'a (); | 1026 | fn foo() -> &'a (); |
1073 | } | 1027 | } |
1074 | impl<'a> Foo<'a> for &'a () { | 1028 | impl<'a> Foo<'a> for &'a () { |
1075 | fn foo() -> &'a<|> () { | 1029 | fn foo() -> &'a$0 () { |
1076 | unimplemented!() | 1030 | unimplemented!() |
1077 | } | 1031 | } |
1078 | } | 1032 | } |
@@ -1093,12 +1047,12 @@ impl<'a> Foo<'a> for &'a () { | |||
1093 | r#" | 1047 | r#" |
1094 | macro_rules! foo {($i:ident) => {$i} } | 1048 | macro_rules! foo {($i:ident) => {$i} } |
1095 | fn main() { | 1049 | fn main() { |
1096 | let a<|> = "test"; | 1050 | let a$0 = "test"; |
1097 | foo!(a); | 1051 | foo!(a); |
1098 | } | 1052 | } |
1099 | "#, | 1053 | "#, |
1100 | expect![[r#" | 1054 | expect![[r#" |
1101 | a Local FileId(0) 59..60 Other | 1055 | a Local FileId(0) 59..60 59..60 Other |
1102 | 1056 | ||
1103 | FileId(0) 80..81 Other Read | 1057 | FileId(0) 80..81 Other Read |
1104 | "#]], | 1058 | "#]], |
@@ -1112,11 +1066,11 @@ fn main() { | |||
1112 | macro_rules! foo {($i:ident) => {$i} } | 1066 | macro_rules! foo {($i:ident) => {$i} } |
1113 | fn main() { | 1067 | fn main() { |
1114 | let a = "test"; | 1068 | let a = "test"; |
1115 | foo!(a<|>); | 1069 | foo!(a$0); |
1116 | } | 1070 | } |
1117 | "#, | 1071 | "#, |
1118 | expect![[r#" | 1072 | expect![[r#" |
1119 | a Local FileId(0) 59..60 Other | 1073 | a Local FileId(0) 59..60 59..60 Other |
1120 | 1074 | ||
1121 | FileId(0) 80..81 Other Read | 1075 | FileId(0) 80..81 Other Read |
1122 | "#]], | 1076 | "#]], |
@@ -1130,7 +1084,7 @@ fn main() { | |||
1130 | fn foo<'a>() -> &'a () { | 1084 | fn foo<'a>() -> &'a () { |
1131 | 'a: loop { | 1085 | 'a: loop { |
1132 | 'b: loop { | 1086 | 'b: loop { |
1133 | continue 'a<|>; | 1087 | continue 'a$0; |
1134 | } | 1088 | } |
1135 | break 'a; | 1089 | break 'a; |
1136 | } | 1090 | } |
@@ -1149,7 +1103,7 @@ fn foo<'a>() -> &'a () { | |||
1149 | fn test_find_const_param() { | 1103 | fn test_find_const_param() { |
1150 | check( | 1104 | check( |
1151 | r#" | 1105 | r#" |
1152 | fn foo<const FOO<|>: usize>() -> usize { | 1106 | fn foo<const FOO$0: usize>() -> usize { |
1153 | FOO | 1107 | FOO |
1154 | } | 1108 | } |
1155 | "#, | 1109 | "#, |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 854bf194e..4df189c98 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -1,29 +1,27 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::{ | 2 | use std::fmt::{self, Display}; |
3 | convert::TryInto, | ||
4 | error::Error, | ||
5 | fmt::{self, Display}, | ||
6 | }; | ||
7 | 3 | ||
8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 4 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
9 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; | ||
10 | use ide_db::{ | 5 | use ide_db::{ |
6 | base_db::{AnchoredPathBuf, FileId, FileRange}, | ||
11 | defs::{Definition, NameClass, NameRefClass}, | 7 | defs::{Definition, NameClass, NameRefClass}, |
8 | search::FileReference, | ||
12 | RootDatabase, | 9 | RootDatabase, |
13 | }; | 10 | }; |
14 | use syntax::{ | 11 | use syntax::{ |
15 | algo::find_node_at_offset, | 12 | algo::find_node_at_offset, |
16 | ast::{self, NameOwner}, | 13 | ast::{self, NameOwner}, |
17 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, | 14 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, T, |
18 | }; | 15 | }; |
19 | use test_utils::mark; | 16 | use test_utils::mark; |
20 | use text_edit::TextEdit; | 17 | use text_edit::TextEdit; |
21 | 18 | ||
22 | use crate::{ | 19 | use crate::{ |
23 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, | 20 | FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, |
24 | SourceChange, SourceFileEdit, TextRange, TextSize, | 21 | TextRange, |
25 | }; | 22 | }; |
26 | 23 | ||
24 | type RenameResult<T> = Result<T, RenameError>; | ||
27 | #[derive(Debug)] | 25 | #[derive(Debug)] |
28 | pub struct RenameError(pub(crate) String); | 26 | pub struct RenameError(pub(crate) String); |
29 | 27 | ||
@@ -33,27 +31,27 @@ impl fmt::Display for RenameError { | |||
33 | } | 31 | } |
34 | } | 32 | } |
35 | 33 | ||
36 | impl Error for RenameError {} | 34 | macro_rules! format_err { |
35 | ($fmt:expr) => {RenameError(format!($fmt))}; | ||
36 | ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} | ||
37 | } | ||
38 | |||
39 | macro_rules! bail { | ||
40 | ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))} | ||
41 | } | ||
37 | 42 | ||
38 | pub(crate) fn prepare_rename( | 43 | pub(crate) fn prepare_rename( |
39 | db: &RootDatabase, | 44 | db: &RootDatabase, |
40 | position: FilePosition, | 45 | position: FilePosition, |
41 | ) -> Result<RangeInfo<()>, RenameError> { | 46 | ) -> RenameResult<RangeInfo<()>> { |
42 | let sema = Semantics::new(db); | 47 | let sema = Semantics::new(db); |
43 | let source_file = sema.parse(position.file_id); | 48 | let source_file = sema.parse(position.file_id); |
44 | let syntax = source_file.syntax(); | 49 | let syntax = source_file.syntax(); |
45 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { | 50 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
46 | rename_mod(&sema, position, module, "dummy") | 51 | rename_mod(&sema, position, module, "dummy") |
47 | } else if let Some(self_token) = | ||
48 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
49 | { | ||
50 | rename_self_to_param(&sema, position, self_token, "dummy") | ||
51 | } else { | 52 | } else { |
52 | let range = match find_all_refs(&sema, position, None) { | 53 | let RangeInfo { range, .. } = find_all_refs(&sema, position)?; |
53 | Some(RangeInfo { range, .. }) => range, | 54 | Ok(RangeInfo::new(range, SourceChange::default())) |
54 | None => return Err(RenameError("No references found at position".to_string())), | ||
55 | }; | ||
56 | Ok(RangeInfo::new(range, SourceChange::from(vec![]))) | ||
57 | } | 55 | } |
58 | .map(|info| RangeInfo::new(info.range, ())) | 56 | .map(|info| RangeInfo::new(info.range, ())) |
59 | } | 57 | } |
@@ -62,7 +60,7 @@ pub(crate) fn rename( | |||
62 | db: &RootDatabase, | 60 | db: &RootDatabase, |
63 | position: FilePosition, | 61 | position: FilePosition, |
64 | new_name: &str, | 62 | new_name: &str, |
65 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 63 | ) -> RenameResult<RangeInfo<SourceChange>> { |
66 | let sema = Semantics::new(db); | 64 | let sema = Semantics::new(db); |
67 | rename_with_semantics(&sema, position, new_name) | 65 | rename_with_semantics(&sema, position, new_name) |
68 | } | 66 | } |
@@ -71,42 +69,14 @@ pub(crate) fn rename_with_semantics( | |||
71 | sema: &Semantics<RootDatabase>, | 69 | sema: &Semantics<RootDatabase>, |
72 | position: FilePosition, | 70 | position: FilePosition, |
73 | new_name: &str, | 71 | new_name: &str, |
74 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 72 | ) -> RenameResult<RangeInfo<SourceChange>> { |
75 | let is_lifetime_name = match lex_single_syntax_kind(new_name) { | ||
76 | Some(res) => match res { | ||
77 | (SyntaxKind::IDENT, _) => false, | ||
78 | (SyntaxKind::UNDERSCORE, _) => false, | ||
79 | (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position), | ||
80 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true, | ||
81 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
82 | return Err(RenameError(format!( | ||
83 | "Invalid name `{0}`: Cannot rename lifetime to {0}", | ||
84 | new_name | ||
85 | ))) | ||
86 | } | ||
87 | (_, Some(syntax_error)) => { | ||
88 | return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error))) | ||
89 | } | ||
90 | (_, None) => { | ||
91 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | ||
92 | } | ||
93 | }, | ||
94 | None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))), | ||
95 | }; | ||
96 | |||
97 | let source_file = sema.parse(position.file_id); | 73 | let source_file = sema.parse(position.file_id); |
98 | let syntax = source_file.syntax(); | 74 | let syntax = source_file.syntax(); |
99 | // this is here to prevent lifetime renames from happening on modules and self | 75 | |
100 | if is_lifetime_name { | 76 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
101 | rename_reference(&sema, position, new_name, is_lifetime_name) | ||
102 | } else if let Some(module) = find_module_at_offset(&sema, position, syntax) { | ||
103 | rename_mod(&sema, position, module, new_name) | 77 | rename_mod(&sema, position, module, new_name) |
104 | } else if let Some(self_token) = | ||
105 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
106 | { | ||
107 | rename_self_to_param(&sema, position, self_token, new_name) | ||
108 | } else { | 78 | } else { |
109 | rename_reference(&sema, position, new_name, is_lifetime_name) | 79 | rename_reference(&sema, position, new_name) |
110 | } | 80 | } |
111 | } | 81 | } |
112 | 82 | ||
@@ -127,6 +97,33 @@ pub(crate) fn will_rename_file( | |||
127 | Some(change) | 97 | Some(change) |
128 | } | 98 | } |
129 | 99 | ||
100 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
101 | enum IdentifierKind { | ||
102 | Ident, | ||
103 | Lifetime, | ||
104 | ToSelf, | ||
105 | Underscore, | ||
106 | } | ||
107 | |||
108 | fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> { | ||
109 | match lex_single_syntax_kind(new_name) { | ||
110 | Some(res) => match res { | ||
111 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
112 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
113 | (T![self], _) => Ok(IdentifierKind::ToSelf), | ||
114 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
115 | Ok(IdentifierKind::Lifetime) | ||
116 | } | ||
117 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
118 | bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name) | ||
119 | } | ||
120 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
121 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
122 | }, | ||
123 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
124 | } | ||
125 | } | ||
126 | |||
130 | fn find_module_at_offset( | 127 | fn find_module_at_offset( |
131 | sema: &Semantics<RootDatabase>, | 128 | sema: &Semantics<RootDatabase>, |
132 | position: FilePosition, | 129 | position: FilePosition, |
@@ -155,39 +152,53 @@ fn find_module_at_offset( | |||
155 | Some(module) | 152 | Some(module) |
156 | } | 153 | } |
157 | 154 | ||
158 | fn source_edit_from_reference( | 155 | fn find_all_refs( |
156 | sema: &Semantics<RootDatabase>, | ||
157 | position: FilePosition, | ||
158 | ) -> RenameResult<RangeInfo<ReferenceSearchResult>> { | ||
159 | crate::references::find_all_refs(sema, position, None) | ||
160 | .ok_or_else(|| format_err!("No references found at position")) | ||
161 | } | ||
162 | |||
163 | fn source_edit_from_references( | ||
159 | sema: &Semantics<RootDatabase>, | 164 | sema: &Semantics<RootDatabase>, |
160 | reference: Reference, | 165 | file_id: FileId, |
166 | references: &[FileReference], | ||
161 | new_name: &str, | 167 | new_name: &str, |
162 | ) -> SourceFileEdit { | 168 | ) -> (FileId, TextEdit) { |
163 | let mut replacement_text = String::new(); | 169 | let mut edit = TextEdit::builder(); |
164 | let range = match reference.kind { | 170 | for reference in references { |
165 | ReferenceKind::FieldShorthandForField => { | 171 | let mut replacement_text = String::new(); |
166 | mark::hit!(test_rename_struct_field_for_shorthand); | 172 | let range = match reference.kind { |
167 | replacement_text.push_str(new_name); | 173 | ReferenceKind::FieldShorthandForField => { |
168 | replacement_text.push_str(": "); | 174 | mark::hit!(test_rename_struct_field_for_shorthand); |
169 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) | 175 | replacement_text.push_str(new_name); |
170 | } | 176 | replacement_text.push_str(": "); |
171 | ReferenceKind::FieldShorthandForLocal => { | 177 | TextRange::new(reference.range.start(), reference.range.start()) |
172 | mark::hit!(test_rename_local_for_field_shorthand); | 178 | } |
173 | replacement_text.push_str(": "); | 179 | ReferenceKind::FieldShorthandForLocal => { |
174 | replacement_text.push_str(new_name); | 180 | mark::hit!(test_rename_local_for_field_shorthand); |
175 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) | 181 | replacement_text.push_str(": "); |
176 | } | 182 | replacement_text.push_str(new_name); |
177 | ReferenceKind::RecordFieldExprOrPat => { | 183 | TextRange::new(reference.range.end(), reference.range.end()) |
178 | mark::hit!(test_rename_field_expr_pat); | 184 | } |
179 | replacement_text.push_str(new_name); | 185 | ReferenceKind::RecordFieldExprOrPat => { |
180 | edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) | 186 | mark::hit!(test_rename_field_expr_pat); |
181 | } | 187 | replacement_text.push_str(new_name); |
182 | _ => { | 188 | edit_text_range_for_record_field_expr_or_pat( |
183 | replacement_text.push_str(new_name); | 189 | sema, |
184 | reference.file_range.range | 190 | FileRange { file_id, range: reference.range }, |
185 | } | 191 | new_name, |
186 | }; | 192 | ) |
187 | SourceFileEdit { | 193 | } |
188 | file_id: reference.file_range.file_id, | 194 | _ => { |
189 | edit: TextEdit::replace(range, replacement_text), | 195 | replacement_text.push_str(new_name); |
196 | reference.range | ||
197 | } | ||
198 | }; | ||
199 | edit.replace(range, replacement_text); | ||
190 | } | 200 | } |
201 | (file_id, edit.finish()) | ||
191 | } | 202 | } |
192 | 203 | ||
193 | fn edit_text_range_for_record_field_expr_or_pat( | 204 | fn edit_text_range_for_record_field_expr_or_pat( |
@@ -223,9 +234,12 @@ fn rename_mod( | |||
223 | position: FilePosition, | 234 | position: FilePosition, |
224 | module: Module, | 235 | module: Module, |
225 | new_name: &str, | 236 | new_name: &str, |
226 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 237 | ) -> RenameResult<RangeInfo<SourceChange>> { |
227 | let mut source_file_edits = Vec::new(); | 238 | if IdentifierKind::Ident != check_identifier(new_name)? { |
228 | let mut file_system_edits = Vec::new(); | 239 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); |
240 | } | ||
241 | |||
242 | let mut source_change = SourceChange::default(); | ||
229 | 243 | ||
230 | let src = module.definition_source(sema.db); | 244 | let src = module.definition_source(sema.db); |
231 | let file_id = src.file_id.original_file(sema.db); | 245 | let file_id = src.file_id.original_file(sema.db); |
@@ -239,7 +253,7 @@ fn rename_mod( | |||
239 | }; | 253 | }; |
240 | let dst = AnchoredPathBuf { anchor: file_id, path }; | 254 | let dst = AnchoredPathBuf { anchor: file_id, path }; |
241 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | 255 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; |
242 | file_system_edits.push(move_file); | 256 | source_change.push_file_system_edit(move_file); |
243 | } | 257 | } |
244 | ModuleSource::Module(..) => {} | 258 | ModuleSource::Module(..) => {} |
245 | } | 259 | } |
@@ -247,22 +261,19 @@ fn rename_mod( | |||
247 | if let Some(src) = module.declaration_source(sema.db) { | 261 | if let Some(src) = module.declaration_source(sema.db) { |
248 | let file_id = src.file_id.original_file(sema.db); | 262 | let file_id = src.file_id.original_file(sema.db); |
249 | let name = src.value.name().unwrap(); | 263 | let name = src.value.name().unwrap(); |
250 | let edit = SourceFileEdit { | 264 | source_change.insert_source_edit( |
251 | file_id, | 265 | file_id, |
252 | edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), | 266 | TextEdit::replace(name.syntax().text_range(), new_name.into()), |
253 | }; | 267 | ); |
254 | source_file_edits.push(edit); | ||
255 | } | 268 | } |
256 | 269 | ||
257 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | 270 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
258 | .ok_or_else(|| RenameError("No references found at position".to_string()))?; | 271 | let ref_edits = refs.references().iter().map(|(&file_id, references)| { |
259 | let ref_edits = refs | 272 | source_edit_from_references(sema, file_id, references, new_name) |
260 | .references | 273 | }); |
261 | .into_iter() | 274 | source_change.extend(ref_edits); |
262 | .map(|reference| source_edit_from_reference(sema, reference, new_name)); | ||
263 | source_file_edits.extend(ref_edits); | ||
264 | 275 | ||
265 | Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) | 276 | Ok(RangeInfo::new(range, source_change)) |
266 | } | 277 | } |
267 | 278 | ||
268 | fn rename_to_self( | 279 | fn rename_to_self( |
@@ -274,27 +285,26 @@ fn rename_to_self( | |||
274 | 285 | ||
275 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) | 286 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) |
276 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) | 287 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) |
277 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 288 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
278 | let param_range = fn_ast | 289 | let param_range = fn_ast |
279 | .param_list() | 290 | .param_list() |
280 | .and_then(|p| p.params().next()) | 291 | .and_then(|p| p.params().next()) |
281 | .ok_or_else(|| RenameError("Method has no parameters".to_string()))? | 292 | .ok_or_else(|| format_err!("Method has no parameters"))? |
282 | .syntax() | 293 | .syntax() |
283 | .text_range(); | 294 | .text_range(); |
284 | if !param_range.contains(position.offset) { | 295 | if !param_range.contains(position.offset) { |
285 | return Err(RenameError("Only the first parameter can be self".to_string())); | 296 | bail!("Only the first parameter can be self"); |
286 | } | 297 | } |
287 | 298 | ||
288 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) | 299 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) |
289 | .and_then(|def| sema.to_def(&def)) | 300 | .and_then(|def| sema.to_def(&def)) |
290 | .ok_or_else(|| RenameError("No impl block found for function".to_string()))?; | 301 | .ok_or_else(|| format_err!("No impl block found for function"))?; |
291 | if fn_def.self_param(sema.db).is_some() { | 302 | if fn_def.self_param(sema.db).is_some() { |
292 | return Err(RenameError("Method already has a self parameter".to_string())); | 303 | bail!("Method already has a self parameter"); |
293 | } | 304 | } |
294 | 305 | ||
295 | let params = fn_def.assoc_fn_params(sema.db); | 306 | let params = fn_def.assoc_fn_params(sema.db); |
296 | let first_param = | 307 | let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?; |
297 | params.first().ok_or_else(|| RenameError("Method has no parameters".into()))?; | ||
298 | let first_param_ty = first_param.ty(); | 308 | let first_param_ty = first_param.ty(); |
299 | let impl_ty = impl_block.target_ty(sema.db); | 309 | let impl_ty = impl_block.target_ty(sema.db); |
300 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | 310 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { |
@@ -307,31 +317,21 @@ fn rename_to_self( | |||
307 | }; | 317 | }; |
308 | 318 | ||
309 | if ty != impl_ty { | 319 | if ty != impl_ty { |
310 | return Err(RenameError("Parameter type differs from impl block type".to_string())); | 320 | bail!("Parameter type differs from impl block type"); |
311 | } | ||
312 | |||
313 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | ||
314 | .ok_or_else(|| RenameError("No reference found at position".to_string()))?; | ||
315 | |||
316 | let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs | ||
317 | .into_iter() | ||
318 | .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); | ||
319 | |||
320 | if param_ref.is_empty() { | ||
321 | return Err(RenameError("Parameter to rename not found".to_string())); | ||
322 | } | 321 | } |
323 | 322 | ||
324 | let mut edits = usages | 323 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
325 | .into_iter() | ||
326 | .map(|reference| source_edit_from_reference(sema, reference, "self")) | ||
327 | .collect::<Vec<_>>(); | ||
328 | 324 | ||
329 | edits.push(SourceFileEdit { | 325 | let mut source_change = SourceChange::default(); |
330 | file_id: position.file_id, | 326 | source_change.extend(refs.references().iter().map(|(&file_id, references)| { |
331 | edit: TextEdit::replace(param_range, String::from(self_param)), | 327 | source_edit_from_references(sema, file_id, references, "self") |
332 | }); | 328 | })); |
329 | source_change.insert_source_edit( | ||
330 | position.file_id, | ||
331 | TextEdit::replace(param_range, String::from(self_param)), | ||
332 | ); | ||
333 | 333 | ||
334 | Ok(RangeInfo::new(range, SourceChange::from(edits))) | 334 | Ok(RangeInfo::new(range, source_change)) |
335 | } | 335 | } |
336 | 336 | ||
337 | fn text_edit_from_self_param( | 337 | fn text_edit_from_self_param( |
@@ -364,77 +364,93 @@ fn text_edit_from_self_param( | |||
364 | fn rename_self_to_param( | 364 | fn rename_self_to_param( |
365 | sema: &Semantics<RootDatabase>, | 365 | sema: &Semantics<RootDatabase>, |
366 | position: FilePosition, | 366 | position: FilePosition, |
367 | self_token: SyntaxToken, | ||
368 | new_name: &str, | 367 | new_name: &str, |
368 | ident_kind: IdentifierKind, | ||
369 | range: TextRange, | ||
370 | refs: ReferenceSearchResult, | ||
369 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 371 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
372 | match ident_kind { | ||
373 | IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name), | ||
374 | IdentifierKind::ToSelf => { | ||
375 | // no-op | ||
376 | mark::hit!(rename_self_to_self); | ||
377 | return Ok(RangeInfo::new(range, SourceChange::default())); | ||
378 | } | ||
379 | _ => (), | ||
380 | } | ||
370 | let source_file = sema.parse(position.file_id); | 381 | let source_file = sema.parse(position.file_id); |
371 | let syn = source_file.syntax(); | 382 | let syn = source_file.syntax(); |
372 | 383 | ||
373 | let text = sema.db.file_text(position.file_id); | ||
374 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) | 384 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) |
375 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 385 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
376 | let search_range = fn_def.syntax().text_range(); | 386 | |
387 | let mut source_change = SourceChange::default(); | ||
388 | if let Some(self_param) = fn_def.param_list().and_then(|it| it.self_param()) { | ||
389 | if self_param | ||
390 | .syntax() | ||
391 | .text_range() | ||
392 | .contains_range(refs.declaration().nav.focus_or_full_range()) | ||
393 | { | ||
394 | let edit = text_edit_from_self_param(syn, &self_param, new_name) | ||
395 | .ok_or_else(|| format_err!("No target type found"))?; | ||
396 | source_change.insert_source_edit(position.file_id, edit); | ||
377 | 397 | ||
378 | let mut edits: Vec<SourceFileEdit> = vec![]; | 398 | source_change.extend(refs.references().iter().map(|(&file_id, references)| { |
399 | source_edit_from_references(sema, file_id, &references, new_name) | ||
400 | })); | ||
379 | 401 | ||
380 | for (idx, _) in text.match_indices("self") { | 402 | if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore |
381 | let offset: TextSize = idx.try_into().unwrap(); | 403 | { |
382 | if !search_range.contains_inclusive(offset) { | 404 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); |
383 | continue; | 405 | } |
384 | } | 406 | |
385 | if let Some(ref usage) = | 407 | return Ok(RangeInfo::new(range, source_change)); |
386 | syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
387 | { | ||
388 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { | ||
389 | text_edit_from_self_param(syn, self_param, new_name) | ||
390 | .ok_or_else(|| RenameError("No target type found".to_string()))? | ||
391 | } else { | ||
392 | TextEdit::replace(usage.text_range(), String::from(new_name)) | ||
393 | }; | ||
394 | edits.push(SourceFileEdit { file_id: position.file_id, edit }); | ||
395 | } | 408 | } |
396 | } | 409 | } |
397 | 410 | Err(format_err!("Method has no self param")) | |
398 | let range = ast::SelfParam::cast(self_token.parent()) | ||
399 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | ||
400 | |||
401 | Ok(RangeInfo::new(range, SourceChange::from(edits))) | ||
402 | } | 411 | } |
403 | 412 | ||
404 | fn rename_reference( | 413 | fn rename_reference( |
405 | sema: &Semantics<RootDatabase>, | 414 | sema: &Semantics<RootDatabase>, |
406 | position: FilePosition, | 415 | position: FilePosition, |
407 | new_name: &str, | 416 | new_name: &str, |
408 | is_lifetime_name: bool, | ||
409 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 417 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
410 | let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { | 418 | let ident_kind = check_identifier(new_name)?; |
411 | Some(range_info) => range_info, | 419 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
412 | None => return Err(RenameError("No references found at position".to_string())), | 420 | |
413 | }; | 421 | match (ident_kind, &refs.declaration.kind) { |
414 | 422 | (IdentifierKind::ToSelf, ReferenceKind::Lifetime) | |
415 | match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) { | 423 | | (IdentifierKind::Underscore, ReferenceKind::Lifetime) |
416 | (true, false) => { | 424 | | (IdentifierKind::Ident, ReferenceKind::Lifetime) => { |
417 | return Err(RenameError(format!( | 425 | mark::hit!(rename_not_a_lifetime_ident_ref); |
418 | "Invalid name `{}`: not a lifetime identifier", | 426 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) |
419 | new_name | ||
420 | ))) | ||
421 | } | 427 | } |
422 | (false, true) => { | 428 | (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime), |
423 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | 429 | (IdentifierKind::Lifetime, _) => { |
430 | mark::hit!(rename_not_an_ident_ref); | ||
431 | bail!("Invalid name `{}`: not an identifier", new_name) | ||
424 | } | 432 | } |
425 | _ => (), | 433 | (_, ReferenceKind::SelfParam) => { |
434 | mark::hit!(rename_self_to_param); | ||
435 | return rename_self_to_param(sema, position, new_name, ident_kind, range, refs); | ||
436 | } | ||
437 | (IdentifierKind::ToSelf, _) => { | ||
438 | mark::hit!(rename_to_self); | ||
439 | return rename_to_self(sema, position); | ||
440 | } | ||
441 | (IdentifierKind::Underscore, _) if !refs.references.is_empty() => { | ||
442 | mark::hit!(rename_underscore_multiple); | ||
443 | bail!("Cannot rename reference to `_` as it is being referenced multiple times") | ||
444 | } | ||
445 | (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), | ||
426 | } | 446 | } |
427 | 447 | ||
428 | let edit = refs | 448 | let mut source_change = SourceChange::default(); |
429 | .into_iter() | 449 | source_change.extend(refs.into_iter().map(|(file_id, references)| { |
430 | .map(|reference| source_edit_from_reference(sema, reference, new_name)) | 450 | source_edit_from_references(sema, file_id, &references, new_name) |
431 | .collect::<Vec<_>>(); | 451 | })); |
432 | |||
433 | if edit.is_empty() { | ||
434 | return Err(RenameError("No references found at position".to_string())); | ||
435 | } | ||
436 | 452 | ||
437 | Ok(RangeInfo::new(range, SourceChange::from(edit))) | 453 | Ok(RangeInfo::new(range, source_change)) |
438 | } | 454 | } |
439 | 455 | ||
440 | #[cfg(test)] | 456 | #[cfg(test)] |
@@ -457,14 +473,16 @@ mod tests { | |||
457 | let mut text_edit_builder = TextEdit::builder(); | 473 | let mut text_edit_builder = TextEdit::builder(); |
458 | let mut file_id: Option<FileId> = None; | 474 | let mut file_id: Option<FileId> = None; |
459 | for edit in source_change.info.source_file_edits { | 475 | for edit in source_change.info.source_file_edits { |
460 | file_id = Some(edit.file_id); | 476 | file_id = Some(edit.0); |
461 | for indel in edit.edit.into_iter() { | 477 | for indel in edit.1.into_iter() { |
462 | text_edit_builder.replace(indel.delete, indel.insert); | 478 | text_edit_builder.replace(indel.delete, indel.insert); |
463 | } | 479 | } |
464 | } | 480 | } |
465 | let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); | 481 | if let Some(file_id) = file_id { |
466 | text_edit_builder.finish().apply(&mut result); | 482 | let mut result = analysis.file_text(file_id).unwrap().to_string(); |
467 | assert_eq_text!(ra_fixture_after, &*result); | 483 | text_edit_builder.finish().apply(&mut result); |
484 | assert_eq_text!(ra_fixture_after, &*result); | ||
485 | } | ||
468 | } | 486 | } |
469 | Err(err) => { | 487 | Err(err) => { |
470 | if ra_fixture_after.starts_with("error:") { | 488 | if ra_fixture_after.starts_with("error:") { |
@@ -493,19 +511,19 @@ mod tests { | |||
493 | 511 | ||
494 | #[test] | 512 | #[test] |
495 | fn test_rename_to_underscore() { | 513 | fn test_rename_to_underscore() { |
496 | check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#); | 514 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); |
497 | } | 515 | } |
498 | 516 | ||
499 | #[test] | 517 | #[test] |
500 | fn test_rename_to_raw_identifier() { | 518 | fn test_rename_to_raw_identifier() { |
501 | check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#); | 519 | check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#); |
502 | } | 520 | } |
503 | 521 | ||
504 | #[test] | 522 | #[test] |
505 | fn test_rename_to_invalid_identifier1() { | 523 | fn test_rename_to_invalid_identifier1() { |
506 | check( | 524 | check( |
507 | "invalid!", | 525 | "invalid!", |
508 | r#"fn main() { let i<|> = 1; }"#, | 526 | r#"fn main() { let i$0 = 1; }"#, |
509 | "error: Invalid name `invalid!`: not an identifier", | 527 | "error: Invalid name `invalid!`: not an identifier", |
510 | ); | 528 | ); |
511 | } | 529 | } |
@@ -514,7 +532,7 @@ mod tests { | |||
514 | fn test_rename_to_invalid_identifier2() { | 532 | fn test_rename_to_invalid_identifier2() { |
515 | check( | 533 | check( |
516 | "multiple tokens", | 534 | "multiple tokens", |
517 | r#"fn main() { let i<|> = 1; }"#, | 535 | r#"fn main() { let i$0 = 1; }"#, |
518 | "error: Invalid name `multiple tokens`: not an identifier", | 536 | "error: Invalid name `multiple tokens`: not an identifier", |
519 | ); | 537 | ); |
520 | } | 538 | } |
@@ -523,38 +541,60 @@ mod tests { | |||
523 | fn test_rename_to_invalid_identifier3() { | 541 | fn test_rename_to_invalid_identifier3() { |
524 | check( | 542 | check( |
525 | "let", | 543 | "let", |
526 | r#"fn main() { let i<|> = 1; }"#, | 544 | r#"fn main() { let i$0 = 1; }"#, |
527 | "error: Invalid name `let`: not an identifier", | 545 | "error: Invalid name `let`: not an identifier", |
528 | ); | 546 | ); |
529 | } | 547 | } |
530 | 548 | ||
531 | #[test] | 549 | #[test] |
532 | fn test_rename_to_invalid_identifier_lifetime() { | 550 | fn test_rename_to_invalid_identifier_lifetime() { |
551 | mark::check!(rename_not_an_ident_ref); | ||
533 | check( | 552 | check( |
534 | "'foo", | 553 | "'foo", |
535 | r#"fn main() { let i<|> = 1; }"#, | 554 | r#"fn main() { let i$0 = 1; }"#, |
536 | "error: Invalid name `'foo`: not an identifier", | 555 | "error: Invalid name `'foo`: not an identifier", |
537 | ); | 556 | ); |
538 | } | 557 | } |
539 | 558 | ||
540 | #[test] | 559 | #[test] |
541 | fn test_rename_to_invalid_identifier_lifetime2() { | 560 | fn test_rename_to_invalid_identifier_lifetime2() { |
561 | mark::check!(rename_not_a_lifetime_ident_ref); | ||
542 | check( | 562 | check( |
543 | "foo", | 563 | "foo", |
544 | r#"fn main<'a>(_: &'a<|> ()) {}"#, | 564 | r#"fn main<'a>(_: &'a$0 ()) {}"#, |
545 | "error: Invalid name `foo`: not a lifetime identifier", | 565 | "error: Invalid name `foo`: not a lifetime identifier", |
546 | ); | 566 | ); |
547 | } | 567 | } |
548 | 568 | ||
549 | #[test] | 569 | #[test] |
570 | fn test_rename_to_underscore_invalid() { | ||
571 | mark::check!(rename_underscore_multiple); | ||
572 | check( | ||
573 | "_", | ||
574 | r#"fn main(foo$0: ()) {foo;}"#, | ||
575 | "error: Cannot rename reference to `_` as it is being referenced multiple times", | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn test_rename_mod_invalid() { | ||
581 | check( | ||
582 | "'foo", | ||
583 | r#"mod foo$0 {}"#, | ||
584 | "error: Invalid name `'foo`: cannot rename module to 'foo", | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
550 | fn test_rename_for_local() { | 589 | fn test_rename_for_local() { |
590 | mark::check!(rename_ident); | ||
551 | check( | 591 | check( |
552 | "k", | 592 | "k", |
553 | r#" | 593 | r#" |
554 | fn main() { | 594 | fn main() { |
555 | let mut i = 1; | 595 | let mut i = 1; |
556 | let j = 1; | 596 | let j = 1; |
557 | i = i<|> + j; | 597 | i = i$0 + j; |
558 | 598 | ||
559 | { i = 0; } | 599 | { i = 0; } |
560 | 600 | ||
@@ -579,7 +619,7 @@ fn main() { | |||
579 | fn test_rename_unresolved_reference() { | 619 | fn test_rename_unresolved_reference() { |
580 | check( | 620 | check( |
581 | "new_name", | 621 | "new_name", |
582 | r#"fn main() { let _ = unresolved_ref<|>; }"#, | 622 | r#"fn main() { let _ = unresolved_ref$0; }"#, |
583 | "error: No references found at position", | 623 | "error: No references found at position", |
584 | ); | 624 | ); |
585 | } | 625 | } |
@@ -591,7 +631,7 @@ fn main() { | |||
591 | r#" | 631 | r#" |
592 | macro_rules! foo {($i:ident) => {$i} } | 632 | macro_rules! foo {($i:ident) => {$i} } |
593 | fn main() { | 633 | fn main() { |
594 | let a<|> = "test"; | 634 | let a$0 = "test"; |
595 | foo!(a); | 635 | foo!(a); |
596 | } | 636 | } |
597 | "#, | 637 | "#, |
@@ -613,7 +653,7 @@ fn main() { | |||
613 | macro_rules! foo {($i:ident) => {$i} } | 653 | macro_rules! foo {($i:ident) => {$i} } |
614 | fn main() { | 654 | fn main() { |
615 | let a = "test"; | 655 | let a = "test"; |
616 | foo!(a<|>); | 656 | foo!(a$0); |
617 | } | 657 | } |
618 | "#, | 658 | "#, |
619 | r#" | 659 | r#" |
@@ -634,7 +674,7 @@ fn main() { | |||
634 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 674 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
635 | define_fn!(foo); | 675 | define_fn!(foo); |
636 | fn main() { | 676 | fn main() { |
637 | fo<|>o(); | 677 | fo$0o(); |
638 | } | 678 | } |
639 | "#, | 679 | "#, |
640 | r#" | 680 | r#" |
@@ -653,7 +693,7 @@ fn main() { | |||
653 | "bar", | 693 | "bar", |
654 | r#" | 694 | r#" |
655 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 695 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
656 | define_fn!(fo<|>o); | 696 | define_fn!(fo$0o); |
657 | fn main() { | 697 | fn main() { |
658 | foo(); | 698 | foo(); |
659 | } | 699 | } |
@@ -670,17 +710,17 @@ fn main() { | |||
670 | 710 | ||
671 | #[test] | 711 | #[test] |
672 | fn test_rename_for_param_inside() { | 712 | fn test_rename_for_param_inside() { |
673 | check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 713 | check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
674 | } | 714 | } |
675 | 715 | ||
676 | #[test] | 716 | #[test] |
677 | fn test_rename_refs_for_fn_param() { | 717 | fn test_rename_refs_for_fn_param() { |
678 | check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 718 | check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
679 | } | 719 | } |
680 | 720 | ||
681 | #[test] | 721 | #[test] |
682 | fn test_rename_for_mut_param() { | 722 | fn test_rename_for_mut_param() { |
683 | check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); | 723 | check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); |
684 | } | 724 | } |
685 | 725 | ||
686 | #[test] | 726 | #[test] |
@@ -688,7 +728,7 @@ fn main() { | |||
688 | check( | 728 | check( |
689 | "j", | 729 | "j", |
690 | r#" | 730 | r#" |
691 | struct Foo { i<|>: i32 } | 731 | struct Foo { i$0: i32 } |
692 | 732 | ||
693 | impl Foo { | 733 | impl Foo { |
694 | fn new(i: i32) -> Self { | 734 | fn new(i: i32) -> Self { |
@@ -714,7 +754,7 @@ impl Foo { | |||
714 | check( | 754 | check( |
715 | "j", | 755 | "j", |
716 | r#" | 756 | r#" |
717 | struct Foo { i<|>: i32 } | 757 | struct Foo { i$0: i32 } |
718 | 758 | ||
719 | impl Foo { | 759 | impl Foo { |
720 | fn new(i: i32) -> Self { | 760 | fn new(i: i32) -> Self { |
@@ -743,7 +783,7 @@ impl Foo { | |||
743 | struct Foo { i: i32 } | 783 | struct Foo { i: i32 } |
744 | 784 | ||
745 | impl Foo { | 785 | impl Foo { |
746 | fn new(i<|>: i32) -> Self { | 786 | fn new(i$0: i32) -> Self { |
747 | Self { i } | 787 | Self { i } |
748 | } | 788 | } |
749 | } | 789 | } |
@@ -765,7 +805,7 @@ impl Foo { | |||
765 | check( | 805 | check( |
766 | "j", | 806 | "j", |
767 | r#" | 807 | r#" |
768 | struct Foo { i<|>: i32 } | 808 | struct Foo { i$0: i32 } |
769 | struct Bar { i: i32 } | 809 | struct Bar { i: i32 } |
770 | 810 | ||
771 | impl Bar { | 811 | impl Bar { |
@@ -794,7 +834,7 @@ impl Bar { | |||
794 | r#" | 834 | r#" |
795 | struct Foo { i: i32 } | 835 | struct Foo { i: i32 } |
796 | 836 | ||
797 | fn baz(i<|>: i32) -> Self { | 837 | fn baz(i$0: i32) -> Self { |
798 | let x = Foo { i }; | 838 | let x = Foo { i }; |
799 | { | 839 | { |
800 | let i = 0; | 840 | let i = 0; |
@@ -825,7 +865,7 @@ fn baz(j: i32) -> Self { | |||
825 | mod bar; | 865 | mod bar; |
826 | 866 | ||
827 | //- /bar.rs | 867 | //- /bar.rs |
828 | mod foo<|>; | 868 | mod foo$0; |
829 | 869 | ||
830 | //- /bar/foo.rs | 870 | //- /bar/foo.rs |
831 | // empty | 871 | // empty |
@@ -834,21 +874,18 @@ mod foo<|>; | |||
834 | RangeInfo { | 874 | RangeInfo { |
835 | range: 4..7, | 875 | range: 4..7, |
836 | info: SourceChange { | 876 | info: SourceChange { |
837 | source_file_edits: [ | 877 | source_file_edits: { |
838 | SourceFileEdit { | 878 | FileId( |
839 | file_id: FileId( | 879 | 1, |
840 | 1, | 880 | ): TextEdit { |
841 | ), | 881 | indels: [ |
842 | edit: TextEdit { | 882 | Indel { |
843 | indels: [ | 883 | insert: "foo2", |
844 | Indel { | 884 | delete: 4..7, |
845 | insert: "foo2", | 885 | }, |
846 | delete: 4..7, | 886 | ], |
847 | }, | ||
848 | ], | ||
849 | }, | ||
850 | }, | 887 | }, |
851 | ], | 888 | }, |
852 | file_system_edits: [ | 889 | file_system_edits: [ |
853 | MoveFile { | 890 | MoveFile { |
854 | src: FileId( | 891 | src: FileId( |
@@ -883,40 +920,34 @@ fn main() {} | |||
883 | pub struct FooContent; | 920 | pub struct FooContent; |
884 | 921 | ||
885 | //- /bar.rs | 922 | //- /bar.rs |
886 | use crate::foo<|>::FooContent; | 923 | use crate::foo$0::FooContent; |
887 | "#, | 924 | "#, |
888 | expect![[r#" | 925 | expect![[r#" |
889 | RangeInfo { | 926 | RangeInfo { |
890 | range: 11..14, | 927 | range: 11..14, |
891 | info: SourceChange { | 928 | info: SourceChange { |
892 | source_file_edits: [ | 929 | source_file_edits: { |
893 | SourceFileEdit { | 930 | FileId( |
894 | file_id: FileId( | 931 | 0, |
895 | 0, | 932 | ): TextEdit { |
896 | ), | 933 | indels: [ |
897 | edit: TextEdit { | 934 | Indel { |
898 | indels: [ | 935 | insert: "quux", |
899 | Indel { | 936 | delete: 8..11, |
900 | insert: "quux", | 937 | }, |
901 | delete: 8..11, | 938 | ], |
902 | }, | ||
903 | ], | ||
904 | }, | ||
905 | }, | 939 | }, |
906 | SourceFileEdit { | 940 | FileId( |
907 | file_id: FileId( | 941 | 2, |
908 | 2, | 942 | ): TextEdit { |
909 | ), | 943 | indels: [ |
910 | edit: TextEdit { | 944 | Indel { |
911 | indels: [ | 945 | insert: "quux", |
912 | Indel { | 946 | delete: 11..14, |
913 | insert: "quux", | 947 | }, |
914 | delete: 11..14, | 948 | ], |
915 | }, | ||
916 | ], | ||
917 | }, | ||
918 | }, | 949 | }, |
919 | ], | 950 | }, |
920 | file_system_edits: [ | 951 | file_system_edits: [ |
921 | MoveFile { | 952 | MoveFile { |
922 | src: FileId( | 953 | src: FileId( |
@@ -943,29 +974,26 @@ use crate::foo<|>::FooContent; | |||
943 | "foo2", | 974 | "foo2", |
944 | r#" | 975 | r#" |
945 | //- /lib.rs | 976 | //- /lib.rs |
946 | mod fo<|>o; | 977 | mod fo$0o; |
947 | //- /foo/mod.rs | 978 | //- /foo/mod.rs |
948 | // emtpy | 979 | // empty |
949 | "#, | 980 | "#, |
950 | expect![[r#" | 981 | expect![[r#" |
951 | RangeInfo { | 982 | RangeInfo { |
952 | range: 4..7, | 983 | range: 4..7, |
953 | info: SourceChange { | 984 | info: SourceChange { |
954 | source_file_edits: [ | 985 | source_file_edits: { |
955 | SourceFileEdit { | 986 | FileId( |
956 | file_id: FileId( | 987 | 0, |
957 | 0, | 988 | ): TextEdit { |
958 | ), | 989 | indels: [ |
959 | edit: TextEdit { | 990 | Indel { |
960 | indels: [ | 991 | insert: "foo2", |
961 | Indel { | 992 | delete: 4..7, |
962 | insert: "foo2", | 993 | }, |
963 | delete: 4..7, | 994 | ], |
964 | }, | ||
965 | ], | ||
966 | }, | ||
967 | }, | 995 | }, |
968 | ], | 996 | }, |
969 | file_system_edits: [ | 997 | file_system_edits: [ |
970 | MoveFile { | 998 | MoveFile { |
971 | src: FileId( | 999 | src: FileId( |
@@ -992,30 +1020,27 @@ mod fo<|>o; | |||
992 | "bar", | 1020 | "bar", |
993 | r#" | 1021 | r#" |
994 | //- /lib.rs | 1022 | //- /lib.rs |
995 | mod outer { mod fo<|>o; } | 1023 | mod outer { mod fo$0o; } |
996 | 1024 | ||
997 | //- /outer/foo.rs | 1025 | //- /outer/foo.rs |
998 | // emtpy | 1026 | // empty |
999 | "#, | 1027 | "#, |
1000 | expect![[r#" | 1028 | expect![[r#" |
1001 | RangeInfo { | 1029 | RangeInfo { |
1002 | range: 16..19, | 1030 | range: 16..19, |
1003 | info: SourceChange { | 1031 | info: SourceChange { |
1004 | source_file_edits: [ | 1032 | source_file_edits: { |
1005 | SourceFileEdit { | 1033 | FileId( |
1006 | file_id: FileId( | 1034 | 0, |
1007 | 0, | 1035 | ): TextEdit { |
1008 | ), | 1036 | indels: [ |
1009 | edit: TextEdit { | 1037 | Indel { |
1010 | indels: [ | 1038 | insert: "bar", |
1011 | Indel { | 1039 | delete: 16..19, |
1012 | insert: "bar", | 1040 | }, |
1013 | delete: 16..19, | 1041 | ], |
1014 | }, | ||
1015 | ], | ||
1016 | }, | ||
1017 | }, | 1042 | }, |
1018 | ], | 1043 | }, |
1019 | file_system_edits: [ | 1044 | file_system_edits: [ |
1020 | MoveFile { | 1045 | MoveFile { |
1021 | src: FileId( | 1046 | src: FileId( |
@@ -1041,7 +1066,7 @@ mod outer { mod fo<|>o; } | |||
1041 | check( | 1066 | check( |
1042 | "baz", | 1067 | "baz", |
1043 | r#" | 1068 | r#" |
1044 | mod <|>foo { pub fn bar() {} } | 1069 | mod $0foo { pub fn bar() {} } |
1045 | 1070 | ||
1046 | fn main() { foo::bar(); } | 1071 | fn main() { foo::bar(); } |
1047 | "#, | 1072 | "#, |
@@ -1065,7 +1090,7 @@ fn f() { | |||
1065 | } | 1090 | } |
1066 | 1091 | ||
1067 | //- /bar.rs | 1092 | //- /bar.rs |
1068 | pub mod foo<|>; | 1093 | pub mod foo$0; |
1069 | 1094 | ||
1070 | //- /bar/foo.rs | 1095 | //- /bar/foo.rs |
1071 | // pub fn fun() {} | 1096 | // pub fn fun() {} |
@@ -1074,34 +1099,28 @@ pub mod foo<|>; | |||
1074 | RangeInfo { | 1099 | RangeInfo { |
1075 | range: 8..11, | 1100 | range: 8..11, |
1076 | info: SourceChange { | 1101 | info: SourceChange { |
1077 | source_file_edits: [ | 1102 | source_file_edits: { |
1078 | SourceFileEdit { | 1103 | FileId( |
1079 | file_id: FileId( | 1104 | 0, |
1080 | 1, | 1105 | ): TextEdit { |
1081 | ), | 1106 | indels: [ |
1082 | edit: TextEdit { | 1107 | Indel { |
1083 | indels: [ | 1108 | insert: "foo2", |
1084 | Indel { | 1109 | delete: 27..30, |
1085 | insert: "foo2", | 1110 | }, |
1086 | delete: 8..11, | 1111 | ], |
1087 | }, | ||
1088 | ], | ||
1089 | }, | ||
1090 | }, | 1112 | }, |
1091 | SourceFileEdit { | 1113 | FileId( |
1092 | file_id: FileId( | 1114 | 1, |
1093 | 0, | 1115 | ): TextEdit { |
1094 | ), | 1116 | indels: [ |
1095 | edit: TextEdit { | 1117 | Indel { |
1096 | indels: [ | 1118 | insert: "foo2", |
1097 | Indel { | 1119 | delete: 8..11, |
1098 | insert: "foo2", | 1120 | }, |
1099 | delete: 27..30, | 1121 | ], |
1100 | }, | ||
1101 | ], | ||
1102 | }, | ||
1103 | }, | 1122 | }, |
1104 | ], | 1123 | }, |
1105 | file_system_edits: [ | 1124 | file_system_edits: [ |
1106 | MoveFile { | 1125 | MoveFile { |
1107 | src: FileId( | 1126 | src: FileId( |
@@ -1128,7 +1147,7 @@ pub mod foo<|>; | |||
1128 | "Baz", | 1147 | "Baz", |
1129 | r#" | 1148 | r#" |
1130 | mod foo { | 1149 | mod foo { |
1131 | pub enum Foo { Bar<|> } | 1150 | pub enum Foo { Bar$0 } |
1132 | } | 1151 | } |
1133 | 1152 | ||
1134 | fn func(f: foo::Foo) { | 1153 | fn func(f: foo::Foo) { |
@@ -1157,7 +1176,7 @@ fn func(f: foo::Foo) { | |||
1157 | "baz", | 1176 | "baz", |
1158 | r#" | 1177 | r#" |
1159 | mod foo { | 1178 | mod foo { |
1160 | pub struct Foo { pub bar<|>: uint } | 1179 | pub struct Foo { pub bar$0: uint } |
1161 | } | 1180 | } |
1162 | 1181 | ||
1163 | fn foo(f: foo::Foo) { | 1182 | fn foo(f: foo::Foo) { |
@@ -1178,13 +1197,14 @@ fn foo(f: foo::Foo) { | |||
1178 | 1197 | ||
1179 | #[test] | 1198 | #[test] |
1180 | fn test_parameter_to_self() { | 1199 | fn test_parameter_to_self() { |
1200 | mark::check!(rename_to_self); | ||
1181 | check( | 1201 | check( |
1182 | "self", | 1202 | "self", |
1183 | r#" | 1203 | r#" |
1184 | struct Foo { i: i32 } | 1204 | struct Foo { i: i32 } |
1185 | 1205 | ||
1186 | impl Foo { | 1206 | impl Foo { |
1187 | fn f(foo<|>: &mut Foo) -> i32 { | 1207 | fn f(foo$0: &mut Foo) -> i32 { |
1188 | foo.i | 1208 | foo.i |
1189 | } | 1209 | } |
1190 | } | 1210 | } |
@@ -1205,7 +1225,7 @@ impl Foo { | |||
1205 | struct Foo { i: i32 } | 1225 | struct Foo { i: i32 } |
1206 | 1226 | ||
1207 | impl Foo { | 1227 | impl Foo { |
1208 | fn f(foo<|>: Foo) -> i32 { | 1228 | fn f(foo$0: Foo) -> i32 { |
1209 | foo.i | 1229 | foo.i |
1210 | } | 1230 | } |
1211 | } | 1231 | } |
@@ -1229,7 +1249,7 @@ impl Foo { | |||
1229 | r#" | 1249 | r#" |
1230 | struct Foo { i: i32 } | 1250 | struct Foo { i: i32 } |
1231 | 1251 | ||
1232 | fn f(foo<|>: &mut Foo) -> i32 { | 1252 | fn f(foo$0: &mut Foo) -> i32 { |
1233 | foo.i | 1253 | foo.i |
1234 | } | 1254 | } |
1235 | "#, | 1255 | "#, |
@@ -1242,7 +1262,7 @@ struct Foo { i: i32 } | |||
1242 | struct Bar; | 1262 | struct Bar; |
1243 | 1263 | ||
1244 | impl Bar { | 1264 | impl Bar { |
1245 | fn f(foo<|>: &mut Foo) -> i32 { | 1265 | fn f(foo$0: &mut Foo) -> i32 { |
1246 | foo.i | 1266 | foo.i |
1247 | } | 1267 | } |
1248 | } | 1268 | } |
@@ -1258,7 +1278,7 @@ impl Bar { | |||
1258 | r#" | 1278 | r#" |
1259 | struct Foo { i: i32 } | 1279 | struct Foo { i: i32 } |
1260 | impl Foo { | 1280 | impl Foo { |
1261 | fn f(x: (), foo<|>: &mut Foo) -> i32 { | 1281 | fn f(x: (), foo$0: &mut Foo) -> i32 { |
1262 | foo.i | 1282 | foo.i |
1263 | } | 1283 | } |
1264 | } | 1284 | } |
@@ -1274,7 +1294,7 @@ impl Foo { | |||
1274 | r#" | 1294 | r#" |
1275 | struct Foo { i: i32 } | 1295 | struct Foo { i: i32 } |
1276 | impl &Foo { | 1296 | impl &Foo { |
1277 | fn f(foo<|>: &Foo) -> i32 { | 1297 | fn f(foo$0: &Foo) -> i32 { |
1278 | foo.i | 1298 | foo.i |
1279 | } | 1299 | } |
1280 | } | 1300 | } |
@@ -1298,7 +1318,7 @@ impl &Foo { | |||
1298 | struct Foo { i: i32 } | 1318 | struct Foo { i: i32 } |
1299 | 1319 | ||
1300 | impl Foo { | 1320 | impl Foo { |
1301 | fn f(&mut <|>self) -> i32 { | 1321 | fn f(&mut $0self) -> i32 { |
1302 | self.i | 1322 | self.i |
1303 | } | 1323 | } |
1304 | } | 1324 | } |
@@ -1317,13 +1337,14 @@ impl Foo { | |||
1317 | 1337 | ||
1318 | #[test] | 1338 | #[test] |
1319 | fn test_owned_self_to_parameter() { | 1339 | fn test_owned_self_to_parameter() { |
1340 | mark::check!(rename_self_to_param); | ||
1320 | check( | 1341 | check( |
1321 | "foo", | 1342 | "foo", |
1322 | r#" | 1343 | r#" |
1323 | struct Foo { i: i32 } | 1344 | struct Foo { i: i32 } |
1324 | 1345 | ||
1325 | impl Foo { | 1346 | impl Foo { |
1326 | fn f(<|>self) -> i32 { | 1347 | fn f($0self) -> i32 { |
1327 | self.i | 1348 | self.i |
1328 | } | 1349 | } |
1329 | } | 1350 | } |
@@ -1350,7 +1371,7 @@ struct Foo { i: i32 } | |||
1350 | impl Foo { | 1371 | impl Foo { |
1351 | fn f(&self) -> i32 { | 1372 | fn f(&self) -> i32 { |
1352 | let self_var = 1; | 1373 | let self_var = 1; |
1353 | self<|>.i | 1374 | self$0.i |
1354 | } | 1375 | } |
1355 | } | 1376 | } |
1356 | "#, | 1377 | "#, |
@@ -1373,7 +1394,7 @@ impl Foo { | |||
1373 | check( | 1394 | check( |
1374 | "bar", | 1395 | "bar", |
1375 | r#" | 1396 | r#" |
1376 | struct Foo { i<|>: i32 } | 1397 | struct Foo { i$0: i32 } |
1377 | 1398 | ||
1378 | fn foo(bar: i32) -> Foo { | 1399 | fn foo(bar: i32) -> Foo { |
1379 | Foo { i: bar } | 1400 | Foo { i: bar } |
@@ -1394,7 +1415,7 @@ fn foo(bar: i32) -> Foo { | |||
1394 | check( | 1415 | check( |
1395 | "baz", | 1416 | "baz", |
1396 | r#" | 1417 | r#" |
1397 | struct Foo { i<|>: i32 } | 1418 | struct Foo { i$0: i32 } |
1398 | 1419 | ||
1399 | fn foo(foo: Foo) { | 1420 | fn foo(foo: Foo) { |
1400 | let Foo { i: baz } = foo; | 1421 | let Foo { i: baz } = foo; |
@@ -1433,7 +1454,7 @@ struct Foo { | |||
1433 | 1454 | ||
1434 | fn foo(foo: Foo) { | 1455 | fn foo(foo: Foo) { |
1435 | let Foo { i: b } = foo; | 1456 | let Foo { i: b } = foo; |
1436 | let _ = b<|>; | 1457 | let _ = b$0; |
1437 | } | 1458 | } |
1438 | "#, | 1459 | "#, |
1439 | expected_fixture, | 1460 | expected_fixture, |
@@ -1447,7 +1468,7 @@ struct Foo { | |||
1447 | 1468 | ||
1448 | fn foo(foo: Foo) { | 1469 | fn foo(foo: Foo) { |
1449 | let Foo { i } = foo; | 1470 | let Foo { i } = foo; |
1450 | let _ = i<|>; | 1471 | let _ = i$0; |
1451 | } | 1472 | } |
1452 | "#, | 1473 | "#, |
1453 | expected_fixture, | 1474 | expected_fixture, |
@@ -1464,7 +1485,7 @@ struct Foo { | |||
1464 | } | 1485 | } |
1465 | 1486 | ||
1466 | fn foo(Foo { i }: foo) -> i32 { | 1487 | fn foo(Foo { i }: foo) -> i32 { |
1467 | i<|> | 1488 | i$0 |
1468 | } | 1489 | } |
1469 | "#, | 1490 | "#, |
1470 | r#" | 1491 | r#" |
@@ -1481,6 +1502,7 @@ fn foo(Foo { i: bar }: foo) -> i32 { | |||
1481 | 1502 | ||
1482 | #[test] | 1503 | #[test] |
1483 | fn test_rename_lifetimes() { | 1504 | fn test_rename_lifetimes() { |
1505 | mark::check!(rename_lifetime); | ||
1484 | check( | 1506 | check( |
1485 | "'yeeee", | 1507 | "'yeeee", |
1486 | r#" | 1508 | r#" |
@@ -1488,7 +1510,7 @@ trait Foo<'a> { | |||
1488 | fn foo() -> &'a (); | 1510 | fn foo() -> &'a (); |
1489 | } | 1511 | } |
1490 | impl<'a> Foo<'a> for &'a () { | 1512 | impl<'a> Foo<'a> for &'a () { |
1491 | fn foo() -> &'a<|> () { | 1513 | fn foo() -> &'a$0 () { |
1492 | unimplemented!() | 1514 | unimplemented!() |
1493 | } | 1515 | } |
1494 | } | 1516 | } |
@@ -1520,7 +1542,7 @@ fn main() { | |||
1520 | let test_variable = CustomOption::Some(22); | 1542 | let test_variable = CustomOption::Some(22); |
1521 | 1543 | ||
1522 | match test_variable { | 1544 | match test_variable { |
1523 | CustomOption::Some(foo<|>) if foo == 11 => {} | 1545 | CustomOption::Some(foo$0) if foo == 11 => {} |
1524 | _ => (), | 1546 | _ => (), |
1525 | } | 1547 | } |
1526 | }"#, | 1548 | }"#, |
@@ -1549,7 +1571,7 @@ fn main() { | |||
1549 | fn foo<'a>() -> &'a () { | 1571 | fn foo<'a>() -> &'a () { |
1550 | 'a: { | 1572 | 'a: { |
1551 | 'b: loop { | 1573 | 'b: loop { |
1552 | break 'a<|>; | 1574 | break 'a$0; |
1553 | } | 1575 | } |
1554 | } | 1576 | } |
1555 | } | 1577 | } |
@@ -1565,4 +1587,24 @@ fn foo<'a>() -> &'a () { | |||
1565 | "#, | 1587 | "#, |
1566 | ) | 1588 | ) |
1567 | } | 1589 | } |
1590 | |||
1591 | #[test] | ||
1592 | fn test_self_to_self() { | ||
1593 | mark::check!(rename_self_to_self); | ||
1594 | check( | ||
1595 | "self", | ||
1596 | r#" | ||
1597 | struct Foo; | ||
1598 | impl Foo { | ||
1599 | fn foo(self$0) {} | ||
1600 | } | ||
1601 | "#, | ||
1602 | r#" | ||
1603 | struct Foo; | ||
1604 | impl Foo { | ||
1605 | fn foo(self) {} | ||
1606 | } | ||
1607 | "#, | ||
1608 | ) | ||
1609 | } | ||
1568 | } | 1610 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index f4030f3ef..f5ee7de86 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -3,7 +3,7 @@ use std::fmt; | |||
3 | use assists::utils::test_related_attribute; | 3 | use assists::utils::test_related_attribute; |
4 | use cfg::CfgExpr; | 4 | use cfg::CfgExpr; |
5 | use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; | 5 | use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; |
6 | use ide_db::RootDatabase; | 6 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, | 9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, |
@@ -96,21 +96,26 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 97 | let sema = Semantics::new(db); |
98 | let source_file = sema.parse(file_id); | 98 | let source_file = sema.parse(file_id); |
99 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() | 99 | source_file |
100 | } | 100 | .syntax() |
101 | 101 | .descendants() | |
102 | pub(crate) fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 102 | .filter_map(|item| { |
103 | let runnable_item = match_ast! { | 103 | let runnable = match_ast! { |
104 | match (item.clone()) { | 104 | match item { |
105 | ast::Fn(func) => { | 105 | ast::Fn(func) => { |
106 | let def = sema.to_def(&func)?; | 106 | let def = sema.to_def(&func)?; |
107 | runnable_fn(sema, def) | 107 | runnable_fn(&sema, def) |
108 | }, | 108 | }, |
109 | ast::Module(it) => runnable_mod(sema, it), | 109 | ast::Module(it) => runnable_mod(&sema, it), |
110 | _ => None, | 110 | _ => None, |
111 | } | 111 | } |
112 | }; | 112 | }; |
113 | runnable_item.or_else(|| runnable_doctest(sema, item)) | 113 | runnable.or_else(|| match doc_owner_to_def(&sema, item)? { |
114 | Definition::ModuleDef(def) => module_def_doctest(&sema, def), | ||
115 | _ => None, | ||
116 | }) | ||
117 | }) | ||
118 | .collect() | ||
114 | } | 119 | } |
115 | 120 | ||
116 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { | 121 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
@@ -145,20 +150,49 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> | |||
145 | Some(Runnable { nav, kind, cfg }) | 150 | Some(Runnable { nav, kind, cfg }) |
146 | } | 151 | } |
147 | 152 | ||
148 | fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 153 | pub(crate) fn runnable_mod( |
149 | match_ast! { | 154 | sema: &Semantics<RootDatabase>, |
155 | module: ast::Module, | ||
156 | ) -> Option<Runnable> { | ||
157 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
158 | return None; | ||
159 | } | ||
160 | let module_def = sema.to_def(&module)?; | ||
161 | |||
162 | let path = module_def | ||
163 | .path_to_root(sema.db) | ||
164 | .into_iter() | ||
165 | .rev() | ||
166 | .filter_map(|it| it.name(sema.db)) | ||
167 | .join("::"); | ||
168 | |||
169 | let def = sema.to_def(&module)?; | ||
170 | let attrs = def.attrs(sema.db); | ||
171 | let cfg = attrs.cfg(); | ||
172 | let nav = module_def.to_nav(sema.db); | ||
173 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
174 | } | ||
175 | |||
176 | // FIXME: figure out a proper API here. | ||
177 | pub(crate) fn doc_owner_to_def( | ||
178 | sema: &Semantics<RootDatabase>, | ||
179 | item: SyntaxNode, | ||
180 | ) -> Option<Definition> { | ||
181 | let res: hir::ModuleDef = match_ast! { | ||
150 | match item { | 182 | match item { |
151 | ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 183 | ast::SourceFile(it) => sema.scope(&item).module()?.into(), |
152 | ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 184 | ast::Fn(it) => sema.to_def(&it)?.into(), |
153 | ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 185 | ast::Struct(it) => sema.to_def(&it)?.into(), |
154 | ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 186 | ast::Enum(it) => sema.to_def(&it)?.into(), |
155 | ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 187 | ast::Union(it) => sema.to_def(&it)?.into(), |
156 | ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 188 | ast::Trait(it) => sema.to_def(&it)?.into(), |
157 | ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 189 | ast::Const(it) => sema.to_def(&it)?.into(), |
158 | ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 190 | ast::Static(it) => sema.to_def(&it)?.into(), |
159 | _ => None, | 191 | ast::TypeAlias(it) => sema.to_def(&it)?.into(), |
192 | _ => return None, | ||
160 | } | 193 | } |
161 | } | 194 | }; |
195 | Some(Definition::ModuleDef(res)) | ||
162 | } | 196 | } |
163 | 197 | ||
164 | fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { | 198 | fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { |
@@ -253,26 +287,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | |||
253 | }) | 287 | }) |
254 | } | 288 | } |
255 | 289 | ||
256 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | ||
257 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
258 | return None; | ||
259 | } | ||
260 | let module_def = sema.to_def(&module)?; | ||
261 | |||
262 | let path = module_def | ||
263 | .path_to_root(sema.db) | ||
264 | .into_iter() | ||
265 | .rev() | ||
266 | .filter_map(|it| it.name(sema.db)) | ||
267 | .join("::"); | ||
268 | |||
269 | let def = sema.to_def(&module)?; | ||
270 | let attrs = def.attrs(sema.db); | ||
271 | let cfg = attrs.cfg(); | ||
272 | let nav = module_def.to_nav(sema.db); | ||
273 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
274 | } | ||
275 | |||
276 | // We could create runnables for modules with number_of_test_submodules > 0, | 290 | // We could create runnables for modules with number_of_test_submodules > 0, |
277 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already | 291 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already |
278 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { | 292 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { |
@@ -329,7 +343,7 @@ mod tests { | |||
329 | check( | 343 | check( |
330 | r#" | 344 | r#" |
331 | //- /lib.rs | 345 | //- /lib.rs |
332 | <|> | 346 | $0 |
333 | fn main() {} | 347 | fn main() {} |
334 | 348 | ||
335 | #[test] | 349 | #[test] |
@@ -425,7 +439,7 @@ fn bench() {} | |||
425 | check( | 439 | check( |
426 | r#" | 440 | r#" |
427 | //- /lib.rs | 441 | //- /lib.rs |
428 | <|> | 442 | $0 |
429 | fn main() {} | 443 | fn main() {} |
430 | 444 | ||
431 | /// ``` | 445 | /// ``` |
@@ -573,7 +587,7 @@ struct StructWithRunnable(String); | |||
573 | check( | 587 | check( |
574 | r#" | 588 | r#" |
575 | //- /lib.rs | 589 | //- /lib.rs |
576 | <|> | 590 | $0 |
577 | fn main() {} | 591 | fn main() {} |
578 | 592 | ||
579 | struct Data; | 593 | struct Data; |
@@ -625,7 +639,7 @@ impl Data { | |||
625 | check( | 639 | check( |
626 | r#" | 640 | r#" |
627 | //- /lib.rs | 641 | //- /lib.rs |
628 | <|> | 642 | $0 |
629 | mod test_mod { | 643 | mod test_mod { |
630 | #[test] | 644 | #[test] |
631 | fn test_foo1() {} | 645 | fn test_foo1() {} |
@@ -679,7 +693,7 @@ mod test_mod { | |||
679 | check( | 693 | check( |
680 | r#" | 694 | r#" |
681 | //- /lib.rs | 695 | //- /lib.rs |
682 | <|> | 696 | $0 |
683 | mod root_tests { | 697 | mod root_tests { |
684 | mod nested_tests_0 { | 698 | mod nested_tests_0 { |
685 | mod nested_tests_1 { | 699 | mod nested_tests_1 { |
@@ -819,7 +833,7 @@ mod root_tests { | |||
819 | check( | 833 | check( |
820 | r#" | 834 | r#" |
821 | //- /lib.rs crate:foo cfg:feature=foo | 835 | //- /lib.rs crate:foo cfg:feature=foo |
822 | <|> | 836 | $0 |
823 | #[test] | 837 | #[test] |
824 | #[cfg(feature = "foo")] | 838 | #[cfg(feature = "foo")] |
825 | fn test_foo1() {} | 839 | fn test_foo1() {} |
@@ -864,7 +878,7 @@ fn test_foo1() {} | |||
864 | check( | 878 | check( |
865 | r#" | 879 | r#" |
866 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar | 880 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar |
867 | <|> | 881 | $0 |
868 | #[test] | 882 | #[test] |
869 | #[cfg(all(feature = "foo", feature = "bar"))] | 883 | #[cfg(all(feature = "foo", feature = "bar"))] |
870 | fn test_foo1() {} | 884 | fn test_foo1() {} |
@@ -919,7 +933,7 @@ fn test_foo1() {} | |||
919 | check( | 933 | check( |
920 | r#" | 934 | r#" |
921 | //- /lib.rs | 935 | //- /lib.rs |
922 | <|> | 936 | $0 |
923 | mod test_mod { | 937 | mod test_mod { |
924 | fn foo1() {} | 938 | fn foo1() {} |
925 | } | 939 | } |
@@ -938,7 +952,7 @@ mod test_mod { | |||
938 | //- /lib.rs | 952 | //- /lib.rs |
939 | mod foo; | 953 | mod foo; |
940 | //- /foo.rs | 954 | //- /foo.rs |
941 | struct Foo;<|> | 955 | struct Foo;$0 |
942 | impl Foo { | 956 | impl Foo { |
943 | /// ``` | 957 | /// ``` |
944 | /// let x = 5; | 958 | /// let x = 5; |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index ba0085244..f2d4da78d 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -1,35 +1,39 @@ | |||
1 | pub(crate) mod tags; | ||
2 | |||
3 | mod highlights; | ||
4 | mod injector; | ||
5 | |||
6 | mod highlight; | ||
1 | mod format; | 7 | mod format; |
2 | mod html; | ||
3 | mod injection; | ||
4 | mod macro_rules; | 8 | mod macro_rules; |
5 | pub(crate) mod tags; | 9 | mod inject; |
10 | |||
11 | mod html; | ||
6 | #[cfg(test)] | 12 | #[cfg(test)] |
7 | mod tests; | 13 | mod tests; |
8 | 14 | ||
9 | use hir::{AsAssocItem, Local, Name, Semantics, VariantDef}; | 15 | use hir::{Name, Semantics}; |
10 | use ide_db::{ | 16 | use ide_db::RootDatabase; |
11 | defs::{Definition, NameClass, NameRefClass}, | ||
12 | RootDatabase, | ||
13 | }; | ||
14 | use rustc_hash::FxHashMap; | 17 | use rustc_hash::FxHashMap; |
15 | use syntax::{ | 18 | use syntax::{ |
16 | ast::{self, HasFormatSpecifier}, | 19 | ast::{self, HasFormatSpecifier}, |
17 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, | 20 | AstNode, AstToken, Direction, NodeOrToken, |
18 | SyntaxKind::{self, *}, | 21 | SyntaxKind::*, |
19 | SyntaxNode, SyntaxToken, TextRange, WalkEvent, T, | 22 | SyntaxNode, TextRange, WalkEvent, T, |
20 | }; | 23 | }; |
21 | 24 | ||
22 | use crate::{ | 25 | use crate::{ |
23 | syntax_highlighting::{ | 26 | syntax_highlighting::{ |
24 | format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight, | 27 | format::highlight_format_string, highlights::Highlights, |
28 | macro_rules::MacroRulesHighlighter, tags::Highlight, | ||
25 | }, | 29 | }, |
26 | FileId, HighlightModifier, HighlightTag, SymbolKind, | 30 | FileId, HlMod, HlTag, SymbolKind, |
27 | }; | 31 | }; |
28 | 32 | ||
29 | pub(crate) use html::highlight_as_html; | 33 | pub(crate) use html::highlight_as_html; |
30 | 34 | ||
31 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone, Copy)] |
32 | pub struct HighlightedRange { | 36 | pub struct HlRange { |
33 | pub range: TextRange, | 37 | pub range: TextRange, |
34 | pub highlight: Highlight, | 38 | pub highlight: Highlight, |
35 | pub binding_hash: Option<u64>, | 39 | pub binding_hash: Option<u64>, |
@@ -49,7 +53,7 @@ pub(crate) fn highlight( | |||
49 | file_id: FileId, | 53 | file_id: FileId, |
50 | range_to_highlight: Option<TextRange>, | 54 | range_to_highlight: Option<TextRange>, |
51 | syntactic_name_ref_highlighting: bool, | 55 | syntactic_name_ref_highlighting: bool, |
52 | ) -> Vec<HighlightedRange> { | 56 | ) -> Vec<HlRange> { |
53 | let _p = profile::span("highlight"); | 57 | let _p = profile::span("highlight"); |
54 | let sema = Semantics::new(db); | 58 | let sema = Semantics::new(db); |
55 | 59 | ||
@@ -68,28 +72,30 @@ pub(crate) fn highlight( | |||
68 | } | 72 | } |
69 | }; | 73 | }; |
70 | 74 | ||
75 | let mut hl = highlights::Highlights::new(range_to_highlight); | ||
76 | traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting); | ||
77 | hl.to_vec() | ||
78 | } | ||
79 | |||
80 | fn traverse( | ||
81 | hl: &mut Highlights, | ||
82 | sema: &Semantics<RootDatabase>, | ||
83 | root: &SyntaxNode, | ||
84 | range_to_highlight: TextRange, | ||
85 | syntactic_name_ref_highlighting: bool, | ||
86 | ) { | ||
71 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 87 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
72 | // We use a stack for the DFS traversal below. | ||
73 | // When we leave a node, the we use it to flatten the highlighted ranges. | ||
74 | let mut stack = HighlightedRangeStack::new(); | ||
75 | 88 | ||
76 | let mut current_macro_call: Option<ast::MacroCall> = None; | 89 | let mut current_macro_call: Option<ast::MacroCall> = None; |
77 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 90 | let mut current_macro_rules: Option<ast::MacroRules> = None; |
78 | let mut format_string_highlighter = FormatStringHighlighter::default(); | ||
79 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 91 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); |
80 | let mut inside_attribute = false; | 92 | let mut inside_attribute = false; |
81 | 93 | ||
82 | // Walk all nodes, keeping track of whether we are inside a macro or not. | 94 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
83 | // If in macro, expand it first and highlight the expanded code. | 95 | // If in macro, expand it first and highlight the expanded code. |
84 | for event in root.preorder_with_tokens() { | 96 | for event in root.preorder_with_tokens() { |
85 | match &event { | ||
86 | WalkEvent::Enter(_) => stack.push(), | ||
87 | WalkEvent::Leave(_) => stack.pop(), | ||
88 | }; | ||
89 | |||
90 | let event_range = match &event { | 97 | let event_range = match &event { |
91 | WalkEvent::Enter(it) => it.text_range(), | 98 | WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(), |
92 | WalkEvent::Leave(it) => it.text_range(), | ||
93 | }; | 99 | }; |
94 | 100 | ||
95 | // Element outside of the viewport, no need to highlight | 101 | // Element outside of the viewport, no need to highlight |
@@ -101,9 +107,9 @@ pub(crate) fn highlight( | |||
101 | match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { | 107 | match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { |
102 | WalkEvent::Enter(Some(mc)) => { | 108 | WalkEvent::Enter(Some(mc)) => { |
103 | if let Some(range) = macro_call_range(&mc) { | 109 | if let Some(range) = macro_call_range(&mc) { |
104 | stack.add(HighlightedRange { | 110 | hl.add(HlRange { |
105 | range, | 111 | range, |
106 | highlight: HighlightTag::Symbol(SymbolKind::Macro).into(), | 112 | highlight: HlTag::Symbol(SymbolKind::Macro).into(), |
107 | binding_hash: None, | 113 | binding_hash: None, |
108 | }); | 114 | }); |
109 | } | 115 | } |
@@ -113,7 +119,6 @@ pub(crate) fn highlight( | |||
113 | WalkEvent::Leave(Some(mc)) => { | 119 | WalkEvent::Leave(Some(mc)) => { |
114 | assert_eq!(current_macro_call, Some(mc)); | 120 | assert_eq!(current_macro_call, Some(mc)); |
115 | current_macro_call = None; | 121 | current_macro_call = None; |
116 | format_string_highlighter = FormatStringHighlighter::default(); | ||
117 | } | 122 | } |
118 | _ => (), | 123 | _ => (), |
119 | } | 124 | } |
@@ -131,33 +136,24 @@ pub(crate) fn highlight( | |||
131 | } | 136 | } |
132 | _ => (), | 137 | _ => (), |
133 | } | 138 | } |
134 | |||
135 | match &event { | 139 | match &event { |
136 | // Check for Rust code in documentation | ||
137 | WalkEvent::Leave(NodeOrToken::Node(node)) => { | ||
138 | if ast::Attr::can_cast(node.kind()) { | ||
139 | inside_attribute = false | ||
140 | } | ||
141 | if let Some((doctest, range_mapping, new_comments)) = | ||
142 | injection::extract_doc_comments(node) | ||
143 | { | ||
144 | injection::highlight_doc_comment( | ||
145 | doctest, | ||
146 | range_mapping, | ||
147 | new_comments, | ||
148 | &mut stack, | ||
149 | ); | ||
150 | } | ||
151 | } | ||
152 | WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { | 140 | WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { |
153 | inside_attribute = true | 141 | inside_attribute = true |
154 | } | 142 | } |
143 | WalkEvent::Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { | ||
144 | inside_attribute = false | ||
145 | } | ||
155 | _ => (), | 146 | _ => (), |
156 | } | 147 | } |
157 | 148 | ||
158 | let element = match event { | 149 | let element = match event { |
159 | WalkEvent::Enter(it) => it, | 150 | WalkEvent::Enter(it) => it, |
160 | WalkEvent::Leave(_) => continue, | 151 | WalkEvent::Leave(it) => { |
152 | if let Some(node) = it.as_node() { | ||
153 | inject::doc_comment(hl, node); | ||
154 | } | ||
155 | continue; | ||
156 | } | ||
161 | }; | 157 | }; |
162 | 158 | ||
163 | let range = element.text_range(); | 159 | let range = element.text_range(); |
@@ -177,8 +173,6 @@ pub(crate) fn highlight( | |||
177 | let token = sema.descend_into_macros(token.clone()); | 173 | let token = sema.descend_into_macros(token.clone()); |
178 | let parent = token.parent(); | 174 | let parent = token.parent(); |
179 | 175 | ||
180 | format_string_highlighter.check_for_format_string(&parent); | ||
181 | |||
182 | // We only care Name and Name_ref | 176 | // We only care Name and Name_ref |
183 | match (token.kind(), parent.kind()) { | 177 | match (token.kind(), parent.kind()) { |
184 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 178 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), |
@@ -191,213 +185,45 @@ pub(crate) fn highlight( | |||
191 | if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { | 185 | if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { |
192 | if token.is_raw() { | 186 | if token.is_raw() { |
193 | let expanded = element_to_highlight.as_token().unwrap().clone(); | 187 | let expanded = element_to_highlight.as_token().unwrap().clone(); |
194 | if injection::highlight_injection(&mut stack, &sema, token, expanded).is_some() { | 188 | if inject::ra_fixture(hl, &sema, token, expanded).is_some() { |
195 | continue; | 189 | continue; |
196 | } | 190 | } |
197 | } | 191 | } |
198 | } | 192 | } |
199 | 193 | ||
200 | if let Some((mut highlight, binding_hash)) = highlight_element( | 194 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { |
195 | continue; | ||
196 | } | ||
197 | |||
198 | if let Some((mut highlight, binding_hash)) = highlight::element( | ||
201 | &sema, | 199 | &sema, |
202 | &mut bindings_shadow_count, | 200 | &mut bindings_shadow_count, |
203 | syntactic_name_ref_highlighting, | 201 | syntactic_name_ref_highlighting, |
204 | element_to_highlight.clone(), | 202 | element_to_highlight.clone(), |
205 | ) { | 203 | ) { |
206 | if inside_attribute { | 204 | if inside_attribute { |
207 | highlight = highlight | HighlightModifier::Attribute; | 205 | highlight = highlight | HlMod::Attribute; |
208 | } | ||
209 | |||
210 | if macro_rules_highlighter.highlight(element_to_highlight.clone()).is_none() { | ||
211 | stack.add(HighlightedRange { range, highlight, binding_hash }); | ||
212 | } | 206 | } |
213 | 207 | ||
214 | if let Some(string) = | 208 | hl.add(HlRange { range, highlight, binding_hash }); |
215 | element_to_highlight.as_token().cloned().and_then(ast::String::cast) | ||
216 | { | ||
217 | format_string_highlighter.highlight_format_string(&mut stack, &string, range); | ||
218 | // Highlight escape sequences | ||
219 | if let Some(char_ranges) = string.char_ranges() { | ||
220 | stack.push(); | ||
221 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { | ||
222 | if string.text()[piece_range.start().into()..].starts_with('\\') { | ||
223 | stack.add(HighlightedRange { | ||
224 | range: piece_range + range.start(), | ||
225 | highlight: HighlightTag::EscapeSequence.into(), | ||
226 | binding_hash: None, | ||
227 | }); | ||
228 | } | ||
229 | } | ||
230 | stack.pop_and_inject(None); | ||
231 | } | ||
232 | } | ||
233 | } | 209 | } |
234 | } | ||
235 | |||
236 | stack.flattened() | ||
237 | } | ||
238 | |||
239 | #[derive(Debug)] | ||
240 | struct HighlightedRangeStack { | ||
241 | stack: Vec<Vec<HighlightedRange>>, | ||
242 | } | ||
243 | |||
244 | /// We use a stack to implement the flattening logic for the highlighted | ||
245 | /// syntax ranges. | ||
246 | impl HighlightedRangeStack { | ||
247 | fn new() -> Self { | ||
248 | Self { stack: vec![Vec::new()] } | ||
249 | } | ||
250 | |||
251 | fn push(&mut self) { | ||
252 | self.stack.push(Vec::new()); | ||
253 | } | ||
254 | |||
255 | /// Flattens the highlighted ranges. | ||
256 | /// | ||
257 | /// For example `#[cfg(feature = "foo")]` contains the nested ranges: | ||
258 | /// 1) parent-range: Attribute [0, 23) | ||
259 | /// 2) child-range: String [16, 21) | ||
260 | /// | ||
261 | /// The following code implements the flattening, for our example this results to: | ||
262 | /// `[Attribute [0, 16), String [16, 21), Attribute [21, 23)]` | ||
263 | fn pop(&mut self) { | ||
264 | let children = self.stack.pop().unwrap(); | ||
265 | let prev = self.stack.last_mut().unwrap(); | ||
266 | let needs_flattening = !children.is_empty() | ||
267 | && !prev.is_empty() | ||
268 | && prev.last().unwrap().range.contains_range(children.first().unwrap().range); | ||
269 | if !needs_flattening { | ||
270 | prev.extend(children); | ||
271 | } else { | ||
272 | let mut parent = prev.pop().unwrap(); | ||
273 | for ele in children { | ||
274 | assert!(parent.range.contains_range(ele.range)); | ||
275 | |||
276 | let cloned = Self::intersect(&mut parent, &ele); | ||
277 | if !parent.range.is_empty() { | ||
278 | prev.push(parent); | ||
279 | } | ||
280 | prev.push(ele); | ||
281 | parent = cloned; | ||
282 | } | ||
283 | if !parent.range.is_empty() { | ||
284 | prev.push(parent); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /// Intersects the `HighlightedRange` `parent` with `child`. | ||
290 | /// `parent` is mutated in place, becoming the range before `child`. | ||
291 | /// Returns the range (of the same type as `parent`) *after* `child`. | ||
292 | fn intersect(parent: &mut HighlightedRange, child: &HighlightedRange) -> HighlightedRange { | ||
293 | assert!(parent.range.contains_range(child.range)); | ||
294 | |||
295 | let mut cloned = parent.clone(); | ||
296 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
297 | cloned.range = TextRange::new(child.range.end(), cloned.range.end()); | ||
298 | 210 | ||
299 | cloned | 211 | if let Some(string) = element_to_highlight.as_token().cloned().and_then(ast::String::cast) { |
300 | } | 212 | highlight_format_string(hl, &string, range); |
301 | 213 | // Highlight escape sequences | |
302 | /// Remove the `HighlightRange` of `parent` that's currently covered by `child`. | 214 | if let Some(char_ranges) = string.char_ranges() { |
303 | fn intersect_partial(parent: &mut HighlightedRange, child: &HighlightedRange) { | 215 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { |
304 | assert!( | 216 | if string.text()[piece_range.start().into()..].starts_with('\\') { |
305 | parent.range.start() <= child.range.start() | 217 | hl.add(HlRange { |
306 | && parent.range.end() >= child.range.start() | 218 | range: piece_range + range.start(), |
307 | && child.range.end() > parent.range.end() | 219 | highlight: HlTag::EscapeSequence.into(), |
308 | ); | 220 | binding_hash: None, |
309 | 221 | }); | |
310 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
311 | } | ||
312 | |||
313 | /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) | ||
314 | /// can only modify the last range currently on the stack. | ||
315 | /// Can be used to do injections that span multiple ranges, like the | ||
316 | /// doctest injection below. | ||
317 | /// If `overwrite_parent` is non-optional, the highlighting of the parent range | ||
318 | /// is overwritten with the argument. | ||
319 | /// | ||
320 | /// Note that `pop` can be simulated by `pop_and_inject(false)` but the | ||
321 | /// latter is computationally more expensive. | ||
322 | fn pop_and_inject(&mut self, overwrite_parent: Option<Highlight>) { | ||
323 | let mut children = self.stack.pop().unwrap(); | ||
324 | let prev = self.stack.last_mut().unwrap(); | ||
325 | children.sort_by_key(|range| range.range.start()); | ||
326 | prev.sort_by_key(|range| range.range.start()); | ||
327 | |||
328 | for child in children { | ||
329 | if let Some(idx) = | ||
330 | prev.iter().position(|parent| parent.range.contains_range(child.range)) | ||
331 | { | ||
332 | if let Some(tag) = overwrite_parent { | ||
333 | prev[idx].highlight = tag; | ||
334 | } | ||
335 | |||
336 | let cloned = Self::intersect(&mut prev[idx], &child); | ||
337 | let insert_idx = if prev[idx].range.is_empty() { | ||
338 | prev.remove(idx); | ||
339 | idx | ||
340 | } else { | ||
341 | idx + 1 | ||
342 | }; | ||
343 | prev.insert(insert_idx, child); | ||
344 | if !cloned.range.is_empty() { | ||
345 | prev.insert(insert_idx + 1, cloned); | ||
346 | } | ||
347 | } else { | ||
348 | let maybe_idx = | ||
349 | prev.iter().position(|parent| parent.range.contains(child.range.start())); | ||
350 | match (overwrite_parent, maybe_idx) { | ||
351 | (Some(_), Some(idx)) => { | ||
352 | Self::intersect_partial(&mut prev[idx], &child); | ||
353 | let insert_idx = if prev[idx].range.is_empty() { | ||
354 | prev.remove(idx); | ||
355 | idx | ||
356 | } else { | ||
357 | idx + 1 | ||
358 | }; | ||
359 | prev.insert(insert_idx, child); | ||
360 | } | ||
361 | (_, None) => { | ||
362 | let idx = prev | ||
363 | .binary_search_by_key(&child.range.start(), |range| range.range.start()) | ||
364 | .unwrap_or_else(|x| x); | ||
365 | prev.insert(idx, child); | ||
366 | } | ||
367 | _ => { | ||
368 | unreachable!("child range should be completely contained in parent range"); | ||
369 | } | 222 | } |
370 | } | 223 | } |
371 | } | 224 | } |
372 | } | 225 | } |
373 | } | 226 | } |
374 | |||
375 | fn add(&mut self, range: HighlightedRange) { | ||
376 | self.stack | ||
377 | .last_mut() | ||
378 | .expect("during DFS traversal, the stack must not be empty") | ||
379 | .push(range) | ||
380 | } | ||
381 | |||
382 | fn flattened(mut self) -> Vec<HighlightedRange> { | ||
383 | assert_eq!( | ||
384 | self.stack.len(), | ||
385 | 1, | ||
386 | "after DFS traversal, the stack should only contain a single element" | ||
387 | ); | ||
388 | let mut res = self.stack.pop().unwrap(); | ||
389 | res.sort_by_key(|range| range.range.start()); | ||
390 | // Check that ranges are sorted and disjoint | ||
391 | for (left, right) in res.iter().zip(res.iter().skip(1)) { | ||
392 | assert!( | ||
393 | left.range.end() <= right.range.start(), | ||
394 | "left: {:#?}, right: {:#?}", | ||
395 | left, | ||
396 | right | ||
397 | ); | ||
398 | } | ||
399 | res | ||
400 | } | ||
401 | } | 227 | } |
402 | 228 | ||
403 | fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | 229 | fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { |
@@ -415,524 +241,3 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | |||
415 | 241 | ||
416 | Some(TextRange::new(range_start, range_end)) | 242 | Some(TextRange::new(range_start, range_end)) |
417 | } | 243 | } |
418 | |||
419 | /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. | ||
420 | fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool { | ||
421 | while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { | ||
422 | if parent.kind() != *kind { | ||
423 | return false; | ||
424 | } | ||
425 | |||
426 | // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value | ||
427 | // in the same pattern is unstable: rust-lang/rust#68354. | ||
428 | node = node.parent().unwrap().into(); | ||
429 | kinds = rest; | ||
430 | } | ||
431 | |||
432 | // Only true if we matched all expected kinds | ||
433 | kinds.len() == 0 | ||
434 | } | ||
435 | |||
436 | fn is_consumed_lvalue( | ||
437 | node: NodeOrToken<SyntaxNode, SyntaxToken>, | ||
438 | local: &Local, | ||
439 | db: &RootDatabase, | ||
440 | ) -> bool { | ||
441 | // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. | ||
442 | parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) | ||
443 | } | ||
444 | |||
445 | fn highlight_element( | ||
446 | sema: &Semantics<RootDatabase>, | ||
447 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | ||
448 | syntactic_name_ref_highlighting: bool, | ||
449 | element: SyntaxElement, | ||
450 | ) -> Option<(Highlight, Option<u64>)> { | ||
451 | let db = sema.db; | ||
452 | let mut binding_hash = None; | ||
453 | let highlight: Highlight = match element.kind() { | ||
454 | FN => { | ||
455 | bindings_shadow_count.clear(); | ||
456 | return None; | ||
457 | } | ||
458 | |||
459 | // Highlight definitions depending on the "type" of the definition. | ||
460 | NAME => { | ||
461 | let name = element.into_node().and_then(ast::Name::cast).unwrap(); | ||
462 | let name_kind = NameClass::classify(sema, &name); | ||
463 | |||
464 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { | ||
465 | if let Some(name) = local.name(db) { | ||
466 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | ||
467 | *shadow_count += 1; | ||
468 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
469 | } | ||
470 | }; | ||
471 | |||
472 | match name_kind { | ||
473 | Some(NameClass::ExternCrate(_)) => HighlightTag::Symbol(SymbolKind::Module).into(), | ||
474 | Some(NameClass::Definition(def)) => { | ||
475 | highlight_def(db, def) | HighlightModifier::Definition | ||
476 | } | ||
477 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | ||
478 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | ||
479 | let mut h = HighlightTag::Symbol(SymbolKind::Field).into(); | ||
480 | if let Definition::Field(field) = field_ref { | ||
481 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
482 | h |= HighlightModifier::Unsafe; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | h | ||
487 | } | ||
488 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, | ||
489 | } | ||
490 | } | ||
491 | |||
492 | // Highlight references like the definitions they resolve to | ||
493 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { | ||
494 | // even though we track whether we are in an attribute or not we still need this special case | ||
495 | // as otherwise we would emit unresolved references for name refs inside attributes | ||
496 | Highlight::from(HighlightTag::Symbol(SymbolKind::Function)) | ||
497 | } | ||
498 | NAME_REF => { | ||
499 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | ||
500 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | ||
501 | match NameRefClass::classify(sema, &name_ref) { | ||
502 | Some(name_kind) => match name_kind { | ||
503 | NameRefClass::ExternCrate(_) => { | ||
504 | HighlightTag::Symbol(SymbolKind::Module).into() | ||
505 | } | ||
506 | NameRefClass::Definition(def) => { | ||
507 | if let Definition::Local(local) = &def { | ||
508 | if let Some(name) = local.name(db) { | ||
509 | let shadow_count = | ||
510 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
511 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
512 | } | ||
513 | }; | ||
514 | |||
515 | let mut h = highlight_def(db, def); | ||
516 | |||
517 | if let Definition::Local(local) = &def { | ||
518 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | ||
519 | h |= HighlightModifier::Consuming; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | if let Some(parent) = name_ref.syntax().parent() { | ||
524 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
525 | if let Definition::Field(field) = def { | ||
526 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
527 | h |= HighlightModifier::Unsafe; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | h | ||
534 | } | ||
535 | NameRefClass::FieldShorthand { .. } => { | ||
536 | HighlightTag::Symbol(SymbolKind::Field).into() | ||
537 | } | ||
538 | }, | ||
539 | None if syntactic_name_ref_highlighting => { | ||
540 | highlight_name_ref_by_syntax(name_ref, sema) | ||
541 | } | ||
542 | None => HighlightTag::UnresolvedReference.into(), | ||
543 | } | ||
544 | }) | ||
545 | } | ||
546 | |||
547 | // Simple token-based highlighting | ||
548 | COMMENT => { | ||
549 | let comment = element.into_token().and_then(ast::Comment::cast)?; | ||
550 | let h = HighlightTag::Comment; | ||
551 | match comment.kind().doc { | ||
552 | Some(_) => h | HighlightModifier::Documentation, | ||
553 | None => h.into(), | ||
554 | } | ||
555 | } | ||
556 | STRING | BYTE_STRING => HighlightTag::StringLiteral.into(), | ||
557 | ATTR => HighlightTag::Attribute.into(), | ||
558 | INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(), | ||
559 | BYTE => HighlightTag::ByteLiteral.into(), | ||
560 | CHAR => HighlightTag::CharLiteral.into(), | ||
561 | QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow, | ||
562 | LIFETIME => { | ||
563 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | ||
564 | |||
565 | match NameClass::classify_lifetime(sema, &lifetime) { | ||
566 | Some(NameClass::Definition(def)) => { | ||
567 | highlight_def(db, def) | HighlightModifier::Definition | ||
568 | } | ||
569 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | ||
570 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | ||
571 | _ => Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)), | ||
572 | }, | ||
573 | _ => { | ||
574 | Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)) | ||
575 | | HighlightModifier::Definition | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | p if p.is_punct() => match p { | ||
580 | T![&] => { | ||
581 | let h = HighlightTag::Operator.into(); | ||
582 | let is_unsafe = element | ||
583 | .parent() | ||
584 | .and_then(ast::RefExpr::cast) | ||
585 | .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) | ||
586 | .unwrap_or(false); | ||
587 | if is_unsafe { | ||
588 | h | HighlightModifier::Unsafe | ||
589 | } else { | ||
590 | h | ||
591 | } | ||
592 | } | ||
593 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => { | ||
594 | HighlightTag::Operator.into() | ||
595 | } | ||
596 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | ||
597 | HighlightTag::Symbol(SymbolKind::Macro).into() | ||
598 | } | ||
599 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { | ||
600 | HighlightTag::BuiltinType.into() | ||
601 | } | ||
602 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { | ||
603 | HighlightTag::Keyword.into() | ||
604 | } | ||
605 | T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
606 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
607 | |||
608 | let expr = prefix_expr.expr()?; | ||
609 | let ty = sema.type_of_expr(&expr)?; | ||
610 | if ty.is_raw_ptr() { | ||
611 | HighlightTag::Operator | HighlightModifier::Unsafe | ||
612 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { | ||
613 | HighlightTag::Operator.into() | ||
614 | } else { | ||
615 | HighlightTag::Punctuation.into() | ||
616 | } | ||
617 | } | ||
618 | T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
619 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
620 | |||
621 | let expr = prefix_expr.expr()?; | ||
622 | match expr { | ||
623 | ast::Expr::Literal(_) => HighlightTag::NumericLiteral, | ||
624 | _ => HighlightTag::Operator, | ||
625 | } | ||
626 | .into() | ||
627 | } | ||
628 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
629 | HighlightTag::Operator.into() | ||
630 | } | ||
631 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { | ||
632 | HighlightTag::Operator.into() | ||
633 | } | ||
634 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { | ||
635 | HighlightTag::Operator.into() | ||
636 | } | ||
637 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => { | ||
638 | HighlightTag::Operator.into() | ||
639 | } | ||
640 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => { | ||
641 | HighlightTag::Operator.into() | ||
642 | } | ||
643 | _ if element.parent().and_then(ast::Attr::cast).is_some() => { | ||
644 | HighlightTag::Attribute.into() | ||
645 | } | ||
646 | _ => HighlightTag::Punctuation.into(), | ||
647 | }, | ||
648 | |||
649 | k if k.is_keyword() => { | ||
650 | let h = Highlight::new(HighlightTag::Keyword); | ||
651 | match k { | ||
652 | T![break] | ||
653 | | T![continue] | ||
654 | | T![else] | ||
655 | | T![if] | ||
656 | | T![loop] | ||
657 | | T![match] | ||
658 | | T![return] | ||
659 | | T![while] | ||
660 | | T![in] => h | HighlightModifier::ControlFlow, | ||
661 | T![for] if !is_child_of_impl(&element) => h | HighlightModifier::ControlFlow, | ||
662 | T![unsafe] => h | HighlightModifier::Unsafe, | ||
663 | T![true] | T![false] => HighlightTag::BoolLiteral.into(), | ||
664 | T![self] => { | ||
665 | let self_param_is_mut = element | ||
666 | .parent() | ||
667 | .and_then(ast::SelfParam::cast) | ||
668 | .and_then(|p| p.mut_token()) | ||
669 | .is_some(); | ||
670 | let self_path = &element | ||
671 | .parent() | ||
672 | .as_ref() | ||
673 | .and_then(SyntaxNode::parent) | ||
674 | .and_then(ast::Path::cast) | ||
675 | .and_then(|p| sema.resolve_path(&p)); | ||
676 | let mut h = HighlightTag::Symbol(SymbolKind::SelfParam).into(); | ||
677 | if self_param_is_mut | ||
678 | || matches!(self_path, | ||
679 | Some(hir::PathResolution::Local(local)) | ||
680 | if local.is_self(db) | ||
681 | && (local.is_mut(db) || local.ty(db).is_mutable_reference()) | ||
682 | ) | ||
683 | { | ||
684 | h |= HighlightModifier::Mutable | ||
685 | } | ||
686 | |||
687 | if let Some(hir::PathResolution::Local(local)) = self_path { | ||
688 | if is_consumed_lvalue(element, &local, db) { | ||
689 | h |= HighlightModifier::Consuming; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | h | ||
694 | } | ||
695 | T![ref] => element | ||
696 | .parent() | ||
697 | .and_then(ast::IdentPat::cast) | ||
698 | .and_then(|ident_pat| { | ||
699 | if sema.is_unsafe_ident_pat(&ident_pat) { | ||
700 | Some(HighlightModifier::Unsafe) | ||
701 | } else { | ||
702 | None | ||
703 | } | ||
704 | }) | ||
705 | .map(|modifier| h | modifier) | ||
706 | .unwrap_or(h), | ||
707 | _ => h, | ||
708 | } | ||
709 | } | ||
710 | |||
711 | _ => return None, | ||
712 | }; | ||
713 | |||
714 | return Some((highlight, binding_hash)); | ||
715 | |||
716 | fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 { | ||
717 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | ||
718 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | ||
719 | |||
720 | let mut hasher = DefaultHasher::new(); | ||
721 | x.hash(&mut hasher); | ||
722 | hasher.finish() | ||
723 | } | ||
724 | |||
725 | hash((name, shadow_count)) | ||
726 | } | ||
727 | } | ||
728 | |||
729 | fn is_child_of_impl(element: &SyntaxElement) -> bool { | ||
730 | match element.parent() { | ||
731 | Some(e) => e.kind() == IMPL, | ||
732 | _ => false, | ||
733 | } | ||
734 | } | ||
735 | |||
736 | fn highlight_func_by_name_ref( | ||
737 | sema: &Semantics<RootDatabase>, | ||
738 | name_ref: &ast::NameRef, | ||
739 | ) -> Option<Highlight> { | ||
740 | let method_call = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | ||
741 | highlight_method_call(sema, &method_call) | ||
742 | } | ||
743 | |||
744 | fn highlight_method_call( | ||
745 | sema: &Semantics<RootDatabase>, | ||
746 | method_call: &ast::MethodCallExpr, | ||
747 | ) -> Option<Highlight> { | ||
748 | let func = sema.resolve_method_call(&method_call)?; | ||
749 | let mut h = HighlightTag::Symbol(SymbolKind::Function).into(); | ||
750 | h |= HighlightModifier::Associated; | ||
751 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | ||
752 | h |= HighlightModifier::Unsafe; | ||
753 | } | ||
754 | if let Some(self_param) = func.self_param(sema.db) { | ||
755 | match self_param.access(sema.db) { | ||
756 | hir::Access::Shared => (), | ||
757 | hir::Access::Exclusive => h |= HighlightModifier::Mutable, | ||
758 | hir::Access::Owned => { | ||
759 | if let Some(receiver_ty) = | ||
760 | method_call.receiver().and_then(|it| sema.type_of_expr(&it)) | ||
761 | { | ||
762 | if !receiver_ty.is_copy(sema.db) { | ||
763 | h |= HighlightModifier::Consuming | ||
764 | } | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | } | ||
769 | Some(h) | ||
770 | } | ||
771 | |||
772 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | ||
773 | match def { | ||
774 | Definition::Macro(_) => HighlightTag::Symbol(SymbolKind::Macro), | ||
775 | Definition::Field(_) => HighlightTag::Symbol(SymbolKind::Field), | ||
776 | Definition::ModuleDef(def) => match def { | ||
777 | hir::ModuleDef::Module(_) => HighlightTag::Symbol(SymbolKind::Module), | ||
778 | hir::ModuleDef::Function(func) => { | ||
779 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Function)); | ||
780 | if func.as_assoc_item(db).is_some() { | ||
781 | h |= HighlightModifier::Associated; | ||
782 | if func.self_param(db).is_none() { | ||
783 | h |= HighlightModifier::Static | ||
784 | } | ||
785 | } | ||
786 | if func.is_unsafe(db) { | ||
787 | h |= HighlightModifier::Unsafe; | ||
788 | } | ||
789 | return h; | ||
790 | } | ||
791 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Symbol(SymbolKind::Struct), | ||
792 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Symbol(SymbolKind::Enum), | ||
793 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Symbol(SymbolKind::Union), | ||
794 | hir::ModuleDef::Variant(_) => HighlightTag::Symbol(SymbolKind::Variant), | ||
795 | hir::ModuleDef::Const(konst) => { | ||
796 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Const)); | ||
797 | if konst.as_assoc_item(db).is_some() { | ||
798 | h |= HighlightModifier::Associated | ||
799 | } | ||
800 | return h; | ||
801 | } | ||
802 | hir::ModuleDef::Trait(_) => HighlightTag::Symbol(SymbolKind::Trait), | ||
803 | hir::ModuleDef::TypeAlias(type_) => { | ||
804 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::TypeAlias)); | ||
805 | if type_.as_assoc_item(db).is_some() { | ||
806 | h |= HighlightModifier::Associated | ||
807 | } | ||
808 | return h; | ||
809 | } | ||
810 | hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType, | ||
811 | hir::ModuleDef::Static(s) => { | ||
812 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Static)); | ||
813 | if s.is_mut(db) { | ||
814 | h |= HighlightModifier::Mutable; | ||
815 | h |= HighlightModifier::Unsafe; | ||
816 | } | ||
817 | return h; | ||
818 | } | ||
819 | }, | ||
820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), | ||
821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), | ||
822 | Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam), | ||
823 | Definition::Local(local) => { | ||
824 | let tag = if local.is_param(db) { | ||
825 | HighlightTag::Symbol(SymbolKind::ValueParam) | ||
826 | } else { | ||
827 | HighlightTag::Symbol(SymbolKind::Local) | ||
828 | }; | ||
829 | let mut h = Highlight::new(tag); | ||
830 | if local.is_mut(db) || local.ty(db).is_mutable_reference() { | ||
831 | h |= HighlightModifier::Mutable; | ||
832 | } | ||
833 | if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { | ||
834 | h |= HighlightModifier::Callable; | ||
835 | } | ||
836 | return h; | ||
837 | } | ||
838 | Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam), | ||
839 | Definition::Label(_) => HighlightTag::Symbol(SymbolKind::Label), | ||
840 | } | ||
841 | .into() | ||
842 | } | ||
843 | |||
844 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | ||
845 | let default = HighlightTag::UnresolvedReference; | ||
846 | |||
847 | let parent = match name.syntax().parent() { | ||
848 | Some(it) => it, | ||
849 | _ => return default.into(), | ||
850 | }; | ||
851 | |||
852 | let tag = match parent.kind() { | ||
853 | STRUCT => HighlightTag::Symbol(SymbolKind::Struct), | ||
854 | ENUM => HighlightTag::Symbol(SymbolKind::Enum), | ||
855 | VARIANT => HighlightTag::Symbol(SymbolKind::Variant), | ||
856 | UNION => HighlightTag::Symbol(SymbolKind::Union), | ||
857 | TRAIT => HighlightTag::Symbol(SymbolKind::Trait), | ||
858 | TYPE_ALIAS => HighlightTag::Symbol(SymbolKind::TypeAlias), | ||
859 | TYPE_PARAM => HighlightTag::Symbol(SymbolKind::TypeParam), | ||
860 | RECORD_FIELD => HighlightTag::Symbol(SymbolKind::Field), | ||
861 | MODULE => HighlightTag::Symbol(SymbolKind::Module), | ||
862 | FN => HighlightTag::Symbol(SymbolKind::Function), | ||
863 | CONST => HighlightTag::Symbol(SymbolKind::Const), | ||
864 | STATIC => HighlightTag::Symbol(SymbolKind::Static), | ||
865 | IDENT_PAT => HighlightTag::Symbol(SymbolKind::Local), | ||
866 | _ => default, | ||
867 | }; | ||
868 | |||
869 | tag.into() | ||
870 | } | ||
871 | |||
872 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | ||
873 | let default = HighlightTag::UnresolvedReference; | ||
874 | |||
875 | let parent = match name.syntax().parent() { | ||
876 | Some(it) => it, | ||
877 | _ => return default.into(), | ||
878 | }; | ||
879 | |||
880 | match parent.kind() { | ||
881 | METHOD_CALL_EXPR => { | ||
882 | return ast::MethodCallExpr::cast(parent) | ||
883 | .and_then(|method_call| highlight_method_call(sema, &method_call)) | ||
884 | .unwrap_or_else(|| HighlightTag::Symbol(SymbolKind::Function).into()); | ||
885 | } | ||
886 | FIELD_EXPR => { | ||
887 | let h = HighlightTag::Symbol(SymbolKind::Field); | ||
888 | let is_union = ast::FieldExpr::cast(parent) | ||
889 | .and_then(|field_expr| { | ||
890 | let field = sema.resolve_field(&field_expr)?; | ||
891 | Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { | ||
892 | true | ||
893 | } else { | ||
894 | false | ||
895 | }) | ||
896 | }) | ||
897 | .unwrap_or(false); | ||
898 | if is_union { | ||
899 | h | HighlightModifier::Unsafe | ||
900 | } else { | ||
901 | h.into() | ||
902 | } | ||
903 | } | ||
904 | PATH_SEGMENT => { | ||
905 | let path = match parent.parent().and_then(ast::Path::cast) { | ||
906 | Some(it) => it, | ||
907 | _ => return default.into(), | ||
908 | }; | ||
909 | let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
910 | Some(it) => it, | ||
911 | _ => { | ||
912 | // within path, decide whether it is module or adt by checking for uppercase name | ||
913 | return if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
914 | HighlightTag::Symbol(SymbolKind::Struct) | ||
915 | } else { | ||
916 | HighlightTag::Symbol(SymbolKind::Module) | ||
917 | } | ||
918 | .into(); | ||
919 | } | ||
920 | }; | ||
921 | let parent = match expr.syntax().parent() { | ||
922 | Some(it) => it, | ||
923 | None => return default.into(), | ||
924 | }; | ||
925 | |||
926 | match parent.kind() { | ||
927 | CALL_EXPR => HighlightTag::Symbol(SymbolKind::Function).into(), | ||
928 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
929 | HighlightTag::Symbol(SymbolKind::Struct) | ||
930 | } else { | ||
931 | HighlightTag::Symbol(SymbolKind::Const) | ||
932 | } | ||
933 | .into(), | ||
934 | } | ||
935 | } | ||
936 | _ => default.into(), | ||
937 | } | ||
938 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 26416022b..a74ca844b 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -1,65 +1,51 @@ | |||
1 | //! Syntax highlighting for format macro strings. | 1 | //! Syntax highlighting for format macro strings. |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, | 3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, |
4 | AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | 4 | AstNode, AstToken, TextRange, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind}; |
8 | syntax_highlighting::HighlightedRangeStack, HighlightTag, HighlightedRange, SymbolKind, | ||
9 | }; | ||
10 | |||
11 | #[derive(Default)] | ||
12 | pub(super) struct FormatStringHighlighter { | ||
13 | format_string: Option<SyntaxElement>, | ||
14 | } | ||
15 | 8 | ||
16 | impl FormatStringHighlighter { | 9 | pub(super) fn highlight_format_string( |
17 | pub(super) fn check_for_format_string(&mut self, parent: &SyntaxNode) { | 10 | stack: &mut Highlights, |
18 | // Check if macro takes a format string and remember it for highlighting later. | 11 | string: &ast::String, |
19 | // The macros that accept a format string expand to a compiler builtin macros | 12 | range: TextRange, |
20 | // `format_args` and `format_args_nl`. | 13 | ) { |
21 | if let Some(name) = parent | 14 | if is_format_string(string).is_none() { |
22 | .parent() | 15 | return; |
23 | .and_then(ast::MacroCall::cast) | ||
24 | .and_then(|mc| mc.path()) | ||
25 | .and_then(|p| p.segment()) | ||
26 | .and_then(|s| s.name_ref()) | ||
27 | { | ||
28 | match name.text().as_str() { | ||
29 | "format_args" | "format_args_nl" => { | ||
30 | self.format_string = parent | ||
31 | .children_with_tokens() | ||
32 | .filter(|t| t.kind() != SyntaxKind::WHITESPACE) | ||
33 | .nth(1) | ||
34 | .filter(|e| ast::String::can_cast(e.kind())) | ||
35 | } | ||
36 | _ => {} | ||
37 | } | ||
38 | } | ||
39 | } | 16 | } |
40 | pub(super) fn highlight_format_string( | 17 | |
41 | &self, | 18 | string.lex_format_specifier(|piece_range, kind| { |
42 | range_stack: &mut HighlightedRangeStack, | 19 | if let Some(highlight) = highlight_format_specifier(kind) { |
43 | string: &impl HasFormatSpecifier, | 20 | stack.add(HlRange { |
44 | range: TextRange, | 21 | range: piece_range + range.start(), |
45 | ) { | 22 | highlight: highlight.into(), |
46 | if self.format_string.as_ref() == Some(&SyntaxElement::from(string.syntax().clone())) { | 23 | binding_hash: None, |
47 | range_stack.push(); | ||
48 | string.lex_format_specifier(|piece_range, kind| { | ||
49 | if let Some(highlight) = highlight_format_specifier(kind) { | ||
50 | range_stack.add(HighlightedRange { | ||
51 | range: piece_range + range.start(), | ||
52 | highlight: highlight.into(), | ||
53 | binding_hash: None, | ||
54 | }); | ||
55 | } | ||
56 | }); | 24 | }); |
57 | range_stack.pop(); | ||
58 | } | 25 | } |
26 | }); | ||
27 | } | ||
28 | |||
29 | fn is_format_string(string: &ast::String) -> Option<()> { | ||
30 | let parent = string.syntax().parent(); | ||
31 | |||
32 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | ||
33 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { | ||
34 | return None; | ||
35 | } | ||
36 | |||
37 | let first_literal = parent | ||
38 | .children_with_tokens() | ||
39 | .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast)) | ||
40 | .next()?; | ||
41 | if &first_literal != string { | ||
42 | return None; | ||
59 | } | 43 | } |
44 | |||
45 | Some(()) | ||
60 | } | 46 | } |
61 | 47 | ||
62 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { | 48 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { |
63 | Some(match kind { | 49 | Some(match kind { |
64 | FormatSpecifier::Open | 50 | FormatSpecifier::Open |
65 | | FormatSpecifier::Close | 51 | | FormatSpecifier::Close |
@@ -71,8 +57,10 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { | |||
71 | | FormatSpecifier::DollarSign | 57 | | FormatSpecifier::DollarSign |
72 | | FormatSpecifier::Dot | 58 | | FormatSpecifier::Dot |
73 | | FormatSpecifier::Asterisk | 59 | | FormatSpecifier::Asterisk |
74 | | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier, | 60 | | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, |
75 | FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, | 61 | |
76 | FormatSpecifier::Identifier => HighlightTag::Symbol(SymbolKind::Local), | 62 | FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, |
63 | |||
64 | FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), | ||
77 | }) | 65 | }) |
78 | } | 66 | } |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs new file mode 100644 index 000000000..8625ef5df --- /dev/null +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -0,0 +1,509 @@ | |||
1 | //! Computes color for a single element. | ||
2 | |||
3 | use hir::{AsAssocItem, Semantics, VariantDef}; | ||
4 | use ide_db::{ | ||
5 | defs::{Definition, NameClass, NameRefClass}, | ||
6 | RootDatabase, | ||
7 | }; | ||
8 | use rustc_hash::FxHashMap; | ||
9 | use syntax::{ | ||
10 | ast, AstNode, AstToken, NodeOrToken, SyntaxElement, | ||
11 | SyntaxKind::{self, *}, | ||
12 | SyntaxNode, SyntaxToken, T, | ||
13 | }; | ||
14 | |||
15 | use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag, SymbolKind}; | ||
16 | |||
17 | pub(super) fn element( | ||
18 | sema: &Semantics<RootDatabase>, | ||
19 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, | ||
20 | syntactic_name_ref_highlighting: bool, | ||
21 | element: SyntaxElement, | ||
22 | ) -> Option<(Highlight, Option<u64>)> { | ||
23 | let db = sema.db; | ||
24 | let mut binding_hash = None; | ||
25 | let highlight: Highlight = match element.kind() { | ||
26 | FN => { | ||
27 | bindings_shadow_count.clear(); | ||
28 | return None; | ||
29 | } | ||
30 | |||
31 | // Highlight definitions depending on the "type" of the definition. | ||
32 | NAME => { | ||
33 | let name = element.into_node().and_then(ast::Name::cast).unwrap(); | ||
34 | let name_kind = NameClass::classify(sema, &name); | ||
35 | |||
36 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { | ||
37 | if let Some(name) = local.name(db) { | ||
38 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | ||
39 | *shadow_count += 1; | ||
40 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
41 | } | ||
42 | }; | ||
43 | |||
44 | match name_kind { | ||
45 | Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(), | ||
46 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | ||
47 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | ||
48 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | ||
49 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); | ||
50 | if let Definition::Field(field) = field_ref { | ||
51 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
52 | h |= HlMod::Unsafe; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | h | ||
57 | } | ||
58 | None => highlight_name_by_syntax(name) | HlMod::Definition, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | // Highlight references like the definitions they resolve to | ||
63 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { | ||
64 | // even though we track whether we are in an attribute or not we still need this special case | ||
65 | // as otherwise we would emit unresolved references for name refs inside attributes | ||
66 | Highlight::from(HlTag::Symbol(SymbolKind::Function)) | ||
67 | } | ||
68 | NAME_REF => { | ||
69 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | ||
70 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | ||
71 | let is_self = name_ref.self_token().is_some(); | ||
72 | let h = match NameRefClass::classify(sema, &name_ref) { | ||
73 | Some(name_kind) => match name_kind { | ||
74 | NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(), | ||
75 | NameRefClass::Definition(def) => { | ||
76 | if let Definition::Local(local) = &def { | ||
77 | if let Some(name) = local.name(db) { | ||
78 | let shadow_count = | ||
79 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
80 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | let mut h = highlight_def(db, def); | ||
85 | |||
86 | if let Definition::Local(local) = &def { | ||
87 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | ||
88 | h |= HlMod::Consuming; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | if let Some(parent) = name_ref.syntax().parent() { | ||
93 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
94 | if let Definition::Field(field) = def { | ||
95 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
96 | h |= HlMod::Unsafe; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | h | ||
103 | } | ||
104 | NameRefClass::FieldShorthand { .. } => { | ||
105 | HlTag::Symbol(SymbolKind::Field).into() | ||
106 | } | ||
107 | }, | ||
108 | None if syntactic_name_ref_highlighting => { | ||
109 | highlight_name_ref_by_syntax(name_ref, sema) | ||
110 | } | ||
111 | None => HlTag::UnresolvedReference.into(), | ||
112 | }; | ||
113 | if h.tag == HlTag::Symbol(SymbolKind::Module) && is_self { | ||
114 | HlTag::Symbol(SymbolKind::SelfParam).into() | ||
115 | } else { | ||
116 | h | ||
117 | } | ||
118 | }) | ||
119 | } | ||
120 | |||
121 | // Simple token-based highlighting | ||
122 | COMMENT => { | ||
123 | let comment = element.into_token().and_then(ast::Comment::cast)?; | ||
124 | let h = HlTag::Comment; | ||
125 | match comment.kind().doc { | ||
126 | Some(_) => h | HlMod::Documentation, | ||
127 | None => h.into(), | ||
128 | } | ||
129 | } | ||
130 | STRING | BYTE_STRING => HlTag::StringLiteral.into(), | ||
131 | ATTR => HlTag::Attribute.into(), | ||
132 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), | ||
133 | BYTE => HlTag::ByteLiteral.into(), | ||
134 | CHAR => HlTag::CharLiteral.into(), | ||
135 | QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow, | ||
136 | LIFETIME => { | ||
137 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | ||
138 | |||
139 | match NameClass::classify_lifetime(sema, &lifetime) { | ||
140 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | ||
141 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | ||
142 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | ||
143 | _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)), | ||
144 | }, | ||
145 | _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition, | ||
146 | } | ||
147 | } | ||
148 | p if p.is_punct() => match p { | ||
149 | T![&] => { | ||
150 | let h = HlTag::Operator.into(); | ||
151 | let is_unsafe = element | ||
152 | .parent() | ||
153 | .and_then(ast::RefExpr::cast) | ||
154 | .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) | ||
155 | .unwrap_or(false); | ||
156 | if is_unsafe { | ||
157 | h | HlMod::Unsafe | ||
158 | } else { | ||
159 | h | ||
160 | } | ||
161 | } | ||
162 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(), | ||
163 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | ||
164 | HlTag::Symbol(SymbolKind::Macro).into() | ||
165 | } | ||
166 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { | ||
167 | HlTag::BuiltinType.into() | ||
168 | } | ||
169 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { | ||
170 | HlTag::Keyword.into() | ||
171 | } | ||
172 | T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
173 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
174 | |||
175 | let expr = prefix_expr.expr()?; | ||
176 | let ty = sema.type_of_expr(&expr)?; | ||
177 | if ty.is_raw_ptr() { | ||
178 | HlTag::Operator | HlMod::Unsafe | ||
179 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { | ||
180 | HlTag::Operator.into() | ||
181 | } else { | ||
182 | HlTag::Punctuation(HlPunct::Other).into() | ||
183 | } | ||
184 | } | ||
185 | T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
186 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
187 | |||
188 | let expr = prefix_expr.expr()?; | ||
189 | match expr { | ||
190 | ast::Expr::Literal(_) => HlTag::NumericLiteral, | ||
191 | _ => HlTag::Operator, | ||
192 | } | ||
193 | .into() | ||
194 | } | ||
195 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
196 | HlTag::Operator.into() | ||
197 | } | ||
198 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(), | ||
199 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { | ||
200 | HlTag::Operator.into() | ||
201 | } | ||
202 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(), | ||
203 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(), | ||
204 | _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), | ||
205 | kind => HlTag::Punctuation(match kind { | ||
206 | T!['['] | T![']'] => HlPunct::Bracket, | ||
207 | T!['{'] | T!['}'] => HlPunct::Brace, | ||
208 | T!['('] | T![')'] => HlPunct::Parenthesis, | ||
209 | T![<] | T![>] => HlPunct::Angle, | ||
210 | T![,] => HlPunct::Comma, | ||
211 | T![:] => HlPunct::Colon, | ||
212 | T![;] => HlPunct::Semi, | ||
213 | T![.] => HlPunct::Dot, | ||
214 | _ => HlPunct::Other, | ||
215 | }) | ||
216 | .into(), | ||
217 | }, | ||
218 | |||
219 | k if k.is_keyword() => { | ||
220 | let h = Highlight::new(HlTag::Keyword); | ||
221 | match k { | ||
222 | T![break] | ||
223 | | T![continue] | ||
224 | | T![else] | ||
225 | | T![if] | ||
226 | | T![loop] | ||
227 | | T![match] | ||
228 | | T![return] | ||
229 | | T![while] | ||
230 | | T![in] => h | HlMod::ControlFlow, | ||
231 | T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow, | ||
232 | T![unsafe] => h | HlMod::Unsafe, | ||
233 | T![true] | T![false] => HlTag::BoolLiteral.into(), | ||
234 | // self is handled as either a Name or NameRef already | ||
235 | T![self] => return None, | ||
236 | T![ref] => element | ||
237 | .parent() | ||
238 | .and_then(ast::IdentPat::cast) | ||
239 | .and_then(|ident_pat| { | ||
240 | if sema.is_unsafe_ident_pat(&ident_pat) { | ||
241 | Some(HlMod::Unsafe) | ||
242 | } else { | ||
243 | None | ||
244 | } | ||
245 | }) | ||
246 | .map(|modifier| h | modifier) | ||
247 | .unwrap_or(h), | ||
248 | _ => h, | ||
249 | } | ||
250 | } | ||
251 | |||
252 | _ => return None, | ||
253 | }; | ||
254 | |||
255 | return Some((highlight, binding_hash)); | ||
256 | |||
257 | fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { | ||
258 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | ||
259 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | ||
260 | |||
261 | let mut hasher = DefaultHasher::new(); | ||
262 | x.hash(&mut hasher); | ||
263 | hasher.finish() | ||
264 | } | ||
265 | |||
266 | hash((name, shadow_count)) | ||
267 | } | ||
268 | } | ||
269 | |||
270 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | ||
271 | match def { | ||
272 | Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), | ||
273 | Definition::Field(_) => HlTag::Symbol(SymbolKind::Field), | ||
274 | Definition::ModuleDef(def) => match def { | ||
275 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | ||
276 | hir::ModuleDef::Function(func) => { | ||
277 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | ||
278 | if func.as_assoc_item(db).is_some() { | ||
279 | h |= HlMod::Associated; | ||
280 | if func.self_param(db).is_none() { | ||
281 | h |= HlMod::Static | ||
282 | } | ||
283 | } | ||
284 | if func.is_unsafe(db) { | ||
285 | h |= HlMod::Unsafe; | ||
286 | } | ||
287 | return h; | ||
288 | } | ||
289 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct), | ||
290 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum), | ||
291 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union), | ||
292 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | ||
293 | hir::ModuleDef::Const(konst) => { | ||
294 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | ||
295 | if konst.as_assoc_item(db).is_some() { | ||
296 | h |= HlMod::Associated | ||
297 | } | ||
298 | return h; | ||
299 | } | ||
300 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), | ||
301 | hir::ModuleDef::TypeAlias(type_) => { | ||
302 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | ||
303 | if type_.as_assoc_item(db).is_some() { | ||
304 | h |= HlMod::Associated | ||
305 | } | ||
306 | return h; | ||
307 | } | ||
308 | hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType, | ||
309 | hir::ModuleDef::Static(s) => { | ||
310 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); | ||
311 | if s.is_mut(db) { | ||
312 | h |= HlMod::Mutable; | ||
313 | h |= HlMod::Unsafe; | ||
314 | } | ||
315 | return h; | ||
316 | } | ||
317 | }, | ||
318 | Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl), | ||
319 | Definition::GenericParam(it) => match it { | ||
320 | hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam), | ||
321 | hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam), | ||
322 | hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), | ||
323 | }, | ||
324 | Definition::Local(local) => { | ||
325 | let tag = if local.is_self(db) { | ||
326 | HlTag::Symbol(SymbolKind::SelfParam) | ||
327 | } else if local.is_param(db) { | ||
328 | HlTag::Symbol(SymbolKind::ValueParam) | ||
329 | } else { | ||
330 | HlTag::Symbol(SymbolKind::Local) | ||
331 | }; | ||
332 | let mut h = Highlight::new(tag); | ||
333 | if local.is_mut(db) || local.ty(db).is_mutable_reference() { | ||
334 | h |= HlMod::Mutable; | ||
335 | } | ||
336 | if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { | ||
337 | h |= HlMod::Callable; | ||
338 | } | ||
339 | return h; | ||
340 | } | ||
341 | Definition::Label(_) => HlTag::Symbol(SymbolKind::Label), | ||
342 | } | ||
343 | .into() | ||
344 | } | ||
345 | |||
346 | fn highlight_func_by_name_ref( | ||
347 | sema: &Semantics<RootDatabase>, | ||
348 | name_ref: &ast::NameRef, | ||
349 | ) -> Option<Highlight> { | ||
350 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | ||
351 | highlight_method_call(sema, &mc) | ||
352 | } | ||
353 | |||
354 | fn highlight_method_call( | ||
355 | sema: &Semantics<RootDatabase>, | ||
356 | method_call: &ast::MethodCallExpr, | ||
357 | ) -> Option<Highlight> { | ||
358 | let func = sema.resolve_method_call(&method_call)?; | ||
359 | let mut h = HlTag::Symbol(SymbolKind::Function).into(); | ||
360 | h |= HlMod::Associated; | ||
361 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | ||
362 | h |= HlMod::Unsafe; | ||
363 | } | ||
364 | if let Some(self_param) = func.self_param(sema.db) { | ||
365 | match self_param.access(sema.db) { | ||
366 | hir::Access::Shared => (), | ||
367 | hir::Access::Exclusive => h |= HlMod::Mutable, | ||
368 | hir::Access::Owned => { | ||
369 | if let Some(receiver_ty) = | ||
370 | method_call.receiver().and_then(|it| sema.type_of_expr(&it)) | ||
371 | { | ||
372 | if !receiver_ty.is_copy(sema.db) { | ||
373 | h |= HlMod::Consuming | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | Some(h) | ||
380 | } | ||
381 | |||
382 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | ||
383 | let default = HlTag::UnresolvedReference; | ||
384 | |||
385 | let parent = match name.syntax().parent() { | ||
386 | Some(it) => it, | ||
387 | _ => return default.into(), | ||
388 | }; | ||
389 | |||
390 | let tag = match parent.kind() { | ||
391 | STRUCT => HlTag::Symbol(SymbolKind::Struct), | ||
392 | ENUM => HlTag::Symbol(SymbolKind::Enum), | ||
393 | VARIANT => HlTag::Symbol(SymbolKind::Variant), | ||
394 | UNION => HlTag::Symbol(SymbolKind::Union), | ||
395 | TRAIT => HlTag::Symbol(SymbolKind::Trait), | ||
396 | TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias), | ||
397 | TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam), | ||
398 | RECORD_FIELD => HlTag::Symbol(SymbolKind::Field), | ||
399 | MODULE => HlTag::Symbol(SymbolKind::Module), | ||
400 | FN => HlTag::Symbol(SymbolKind::Function), | ||
401 | CONST => HlTag::Symbol(SymbolKind::Const), | ||
402 | STATIC => HlTag::Symbol(SymbolKind::Static), | ||
403 | IDENT_PAT => HlTag::Symbol(SymbolKind::Local), | ||
404 | _ => default, | ||
405 | }; | ||
406 | |||
407 | tag.into() | ||
408 | } | ||
409 | |||
410 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | ||
411 | let default = HlTag::UnresolvedReference; | ||
412 | |||
413 | let parent = match name.syntax().parent() { | ||
414 | Some(it) => it, | ||
415 | _ => return default.into(), | ||
416 | }; | ||
417 | |||
418 | match parent.kind() { | ||
419 | METHOD_CALL_EXPR => { | ||
420 | return ast::MethodCallExpr::cast(parent) | ||
421 | .and_then(|it| highlight_method_call(sema, &it)) | ||
422 | .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into()); | ||
423 | } | ||
424 | FIELD_EXPR => { | ||
425 | let h = HlTag::Symbol(SymbolKind::Field); | ||
426 | let is_union = ast::FieldExpr::cast(parent) | ||
427 | .and_then(|field_expr| { | ||
428 | let field = sema.resolve_field(&field_expr)?; | ||
429 | Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { | ||
430 | true | ||
431 | } else { | ||
432 | false | ||
433 | }) | ||
434 | }) | ||
435 | .unwrap_or(false); | ||
436 | if is_union { | ||
437 | h | HlMod::Unsafe | ||
438 | } else { | ||
439 | h.into() | ||
440 | } | ||
441 | } | ||
442 | PATH_SEGMENT => { | ||
443 | let path = match parent.parent().and_then(ast::Path::cast) { | ||
444 | Some(it) => it, | ||
445 | _ => return default.into(), | ||
446 | }; | ||
447 | let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
448 | Some(it) => it, | ||
449 | _ => { | ||
450 | // within path, decide whether it is module or adt by checking for uppercase name | ||
451 | return if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
452 | HlTag::Symbol(SymbolKind::Struct) | ||
453 | } else { | ||
454 | HlTag::Symbol(SymbolKind::Module) | ||
455 | } | ||
456 | .into(); | ||
457 | } | ||
458 | }; | ||
459 | let parent = match expr.syntax().parent() { | ||
460 | Some(it) => it, | ||
461 | None => return default.into(), | ||
462 | }; | ||
463 | |||
464 | match parent.kind() { | ||
465 | CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(), | ||
466 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
467 | HlTag::Symbol(SymbolKind::Struct) | ||
468 | } else { | ||
469 | HlTag::Symbol(SymbolKind::Const) | ||
470 | } | ||
471 | .into(), | ||
472 | } | ||
473 | } | ||
474 | _ => default.into(), | ||
475 | } | ||
476 | } | ||
477 | |||
478 | fn is_consumed_lvalue( | ||
479 | node: NodeOrToken<SyntaxNode, SyntaxToken>, | ||
480 | local: &hir::Local, | ||
481 | db: &RootDatabase, | ||
482 | ) -> bool { | ||
483 | // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. | ||
484 | parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) | ||
485 | } | ||
486 | |||
487 | /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. | ||
488 | fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool { | ||
489 | while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { | ||
490 | if parent.kind() != *kind { | ||
491 | return false; | ||
492 | } | ||
493 | |||
494 | // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value | ||
495 | // in the same pattern is unstable: rust-lang/rust#68354. | ||
496 | node = node.parent().unwrap().into(); | ||
497 | kinds = rest; | ||
498 | } | ||
499 | |||
500 | // Only true if we matched all expected kinds | ||
501 | kinds.len() == 0 | ||
502 | } | ||
503 | |||
504 | fn is_child_of_impl(element: &SyntaxElement) -> bool { | ||
505 | match element.parent() { | ||
506 | Some(e) => e.kind() == IMPL, | ||
507 | _ => false, | ||
508 | } | ||
509 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs new file mode 100644 index 000000000..882a685a5 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/highlights.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | //! Collects a tree of highlighted ranges and flattens it. | ||
2 | use std::iter; | ||
3 | |||
4 | use stdx::equal_range_by; | ||
5 | use syntax::TextRange; | ||
6 | |||
7 | use crate::{HlRange, HlTag}; | ||
8 | |||
9 | pub(super) struct Highlights { | ||
10 | root: Node, | ||
11 | } | ||
12 | |||
13 | struct Node { | ||
14 | hl_range: HlRange, | ||
15 | nested: Vec<Node>, | ||
16 | } | ||
17 | |||
18 | impl Highlights { | ||
19 | pub(super) fn new(range: TextRange) -> Highlights { | ||
20 | Highlights { | ||
21 | root: Node::new(HlRange { range, highlight: HlTag::None.into(), binding_hash: None }), | ||
22 | } | ||
23 | } | ||
24 | |||
25 | pub(super) fn add(&mut self, hl_range: HlRange) { | ||
26 | self.root.add(hl_range); | ||
27 | } | ||
28 | |||
29 | pub(super) fn to_vec(self) -> Vec<HlRange> { | ||
30 | let mut res = Vec::new(); | ||
31 | self.root.flatten(&mut res); | ||
32 | res | ||
33 | } | ||
34 | } | ||
35 | |||
36 | impl Node { | ||
37 | fn new(hl_range: HlRange) -> Node { | ||
38 | Node { hl_range, nested: Vec::new() } | ||
39 | } | ||
40 | |||
41 | fn add(&mut self, hl_range: HlRange) { | ||
42 | assert!(self.hl_range.range.contains_range(hl_range.range)); | ||
43 | |||
44 | // Fast path | ||
45 | if let Some(last) = self.nested.last_mut() { | ||
46 | if last.hl_range.range.contains_range(hl_range.range) { | ||
47 | return last.add(hl_range); | ||
48 | } | ||
49 | if last.hl_range.range.end() <= hl_range.range.start() { | ||
50 | return self.nested.push(Node::new(hl_range)); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | let overlapping = | ||
55 | equal_range_by(&self.nested, |n| TextRange::ordering(n.hl_range.range, hl_range.range)); | ||
56 | |||
57 | if overlapping.len() == 1 | ||
58 | && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range) | ||
59 | { | ||
60 | return self.nested[overlapping.start].add(hl_range); | ||
61 | } | ||
62 | |||
63 | let nested = self | ||
64 | .nested | ||
65 | .splice(overlapping.clone(), iter::once(Node::new(hl_range))) | ||
66 | .collect::<Vec<_>>(); | ||
67 | self.nested[overlapping.start].nested = nested; | ||
68 | } | ||
69 | |||
70 | fn flatten(&self, acc: &mut Vec<HlRange>) { | ||
71 | let mut start = self.hl_range.range.start(); | ||
72 | let mut nested = self.nested.iter(); | ||
73 | loop { | ||
74 | let next = nested.next(); | ||
75 | let end = next.map_or(self.hl_range.range.end(), |it| it.hl_range.range.start()); | ||
76 | if start < end { | ||
77 | acc.push(HlRange { | ||
78 | range: TextRange::new(start, end), | ||
79 | highlight: self.hl_range.highlight, | ||
80 | binding_hash: self.hl_range.binding_hash, | ||
81 | }); | ||
82 | } | ||
83 | start = match next { | ||
84 | Some(child) => { | ||
85 | child.flatten(acc); | ||
86 | child.hl_range.range.end() | ||
87 | } | ||
88 | None => break, | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 99ba3a59d..0ee7bc96e 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use ide_db::base_db::SourceDatabase; | 3 | use ide_db::base_db::SourceDatabase; |
4 | use oorandom::Rand32; | 4 | use oorandom::Rand32; |
5 | use stdx::format_to; | 5 | use stdx::format_to; |
6 | use syntax::{AstNode, TextRange, TextSize}; | 6 | use syntax::AstNode; |
7 | 7 | ||
8 | use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; | 8 | use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; |
9 | 9 | ||
@@ -20,35 +20,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo | |||
20 | ) | 20 | ) |
21 | } | 21 | } |
22 | 22 | ||
23 | let ranges = highlight(db, file_id, None, false); | 23 | let hl_ranges = highlight(db, file_id, None, false); |
24 | let text = parse.tree().syntax().to_string(); | 24 | let text = parse.tree().syntax().to_string(); |
25 | let mut prev_pos = TextSize::from(0); | ||
26 | let mut buf = String::new(); | 25 | let mut buf = String::new(); |
27 | buf.push_str(&STYLE); | 26 | buf.push_str(&STYLE); |
28 | buf.push_str("<pre><code>"); | 27 | buf.push_str("<pre><code>"); |
29 | for range in &ranges { | 28 | for r in &hl_ranges { |
30 | if range.range.start() > prev_pos { | 29 | let chunk = html_escape(&text[r.range]); |
31 | let curr = &text[TextRange::new(prev_pos, range.range.start())]; | 30 | if r.highlight.is_empty() { |
32 | let text = html_escape(curr); | 31 | format_to!(buf, "{}", chunk); |
33 | buf.push_str(&text); | 32 | continue; |
34 | } | 33 | } |
35 | let curr = &text[TextRange::new(range.range.start(), range.range.end())]; | ||
36 | 34 | ||
37 | let class = range.highlight.to_string().replace('.', " "); | 35 | let class = r.highlight.to_string().replace('.', " "); |
38 | let color = match (rainbow, range.binding_hash) { | 36 | let color = match (rainbow, r.binding_hash) { |
39 | (true, Some(hash)) => { | 37 | (true, Some(hash)) => { |
40 | format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) | 38 | format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) |
41 | } | 39 | } |
42 | _ => "".into(), | 40 | _ => "".into(), |
43 | }; | 41 | }; |
44 | format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, html_escape(curr)); | 42 | format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, chunk); |
45 | |||
46 | prev_pos = range.range.end(); | ||
47 | } | 43 | } |
48 | // Add the remaining (non-highlighted) text | ||
49 | let curr = &text[TextRange::new(prev_pos, TextSize::of(&text))]; | ||
50 | let text = html_escape(curr); | ||
51 | buf.push_str(&text); | ||
52 | buf.push_str("</code></pre>"); | 44 | buf.push_str("</code></pre>"); |
53 | buf | 45 | buf |
54 | } | 46 | } |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs new file mode 100644 index 000000000..281461493 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -0,0 +1,158 @@ | |||
1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. | ||
2 | |||
3 | use hir::Semantics; | ||
4 | use ide_db::call_info::ActiveParameter; | ||
5 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
6 | |||
7 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; | ||
8 | |||
9 | use super::{highlights::Highlights, injector::Injector}; | ||
10 | |||
11 | pub(super) fn ra_fixture( | ||
12 | hl: &mut Highlights, | ||
13 | sema: &Semantics<RootDatabase>, | ||
14 | literal: ast::String, | ||
15 | expanded: SyntaxToken, | ||
16 | ) -> Option<()> { | ||
17 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
18 | if !active_parameter.name.starts_with("ra_fixture") { | ||
19 | return None; | ||
20 | } | ||
21 | let value = literal.value()?; | ||
22 | |||
23 | if let Some(range) = literal.open_quote_text_range() { | ||
24 | hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) | ||
25 | } | ||
26 | |||
27 | let mut inj = Injector::default(); | ||
28 | |||
29 | let mut text = &*value; | ||
30 | let mut offset: TextSize = 0.into(); | ||
31 | |||
32 | while !text.is_empty() { | ||
33 | let marker = "$0"; | ||
34 | let idx = text.find(marker).unwrap_or(text.len()); | ||
35 | let (chunk, next) = text.split_at(idx); | ||
36 | inj.add(chunk, TextRange::at(offset, TextSize::of(chunk))); | ||
37 | |||
38 | text = next; | ||
39 | offset += TextSize::of(chunk); | ||
40 | |||
41 | if let Some(next) = text.strip_prefix(marker) { | ||
42 | if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) { | ||
43 | hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None }); | ||
44 | } | ||
45 | |||
46 | text = next; | ||
47 | |||
48 | let marker_len = TextSize::of(marker); | ||
49 | offset += marker_len; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); | ||
54 | |||
55 | for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { | ||
56 | for range in inj.map_range_up(hl_range.range) { | ||
57 | if let Some(range) = literal.map_range_up(range) { | ||
58 | hl_range.range = range; | ||
59 | hl.add(hl_range.clone()); | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if let Some(range) = literal.close_quote_text_range() { | ||
65 | hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) | ||
66 | } | ||
67 | |||
68 | Some(()) | ||
69 | } | ||
70 | |||
71 | const RUSTDOC_FENCE: &'static str = "```"; | ||
72 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | ||
73 | "", | ||
74 | "rust", | ||
75 | "should_panic", | ||
76 | "ignore", | ||
77 | "no_run", | ||
78 | "compile_fail", | ||
79 | "edition2015", | ||
80 | "edition2018", | ||
81 | "edition2021", | ||
82 | ]; | ||
83 | |||
84 | /// Injection of syntax highlighting of doctests. | ||
85 | pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | ||
86 | let doc_comments = node | ||
87 | .children_with_tokens() | ||
88 | .filter_map(|it| it.into_token().and_then(ast::Comment::cast)) | ||
89 | .filter(|it| it.kind().doc.is_some()); | ||
90 | |||
91 | if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) { | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | let mut inj = Injector::default(); | ||
96 | inj.add_unmapped("fn doctest() {\n"); | ||
97 | |||
98 | let mut is_codeblock = false; | ||
99 | let mut is_doctest = false; | ||
100 | |||
101 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | ||
102 | // spanning comment ranges. | ||
103 | let mut new_comments = Vec::new(); | ||
104 | for comment in doc_comments { | ||
105 | match comment.text().find(RUSTDOC_FENCE) { | ||
106 | Some(idx) => { | ||
107 | is_codeblock = !is_codeblock; | ||
108 | // Check whether code is rust by inspecting fence guards | ||
109 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | ||
110 | let is_rust = | ||
111 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | ||
112 | is_doctest = is_codeblock && is_rust; | ||
113 | continue; | ||
114 | } | ||
115 | None if !is_doctest => continue, | ||
116 | None => (), | ||
117 | } | ||
118 | |||
119 | let line: &str = comment.text().as_str(); | ||
120 | let range = comment.syntax().text_range(); | ||
121 | |||
122 | let mut pos = TextSize::of(comment.prefix()); | ||
123 | // whitespace after comment is ignored | ||
124 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { | ||
125 | pos += TextSize::of(ws); | ||
126 | } | ||
127 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
128 | if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') { | ||
129 | pos += TextSize::of(ws); | ||
130 | } | ||
131 | |||
132 | new_comments.push(TextRange::at(range.start(), pos)); | ||
133 | |||
134 | inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end())); | ||
135 | inj.add_unmapped("\n"); | ||
136 | } | ||
137 | inj.add_unmapped("\n}"); | ||
138 | |||
139 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); | ||
140 | |||
141 | for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | ||
142 | for r in inj.map_range_up(h.range) { | ||
143 | hl.add(HlRange { | ||
144 | range: r, | ||
145 | highlight: h.highlight | HlMod::Injected, | ||
146 | binding_hash: h.binding_hash, | ||
147 | }); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | for range in new_comments { | ||
152 | hl.add(HlRange { | ||
153 | range, | ||
154 | highlight: HlTag::Comment | HlMod::Documentation, | ||
155 | binding_hash: None, | ||
156 | }); | ||
157 | } | ||
158 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs deleted file mode 100644 index 6cbd683c6..000000000 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ /dev/null | |||
@@ -1,192 +0,0 @@ | |||
1 | //! Syntax highlighting injections such as highlighting of documentation tests. | ||
2 | |||
3 | use std::{collections::BTreeMap, convert::TryFrom}; | ||
4 | |||
5 | use hir::Semantics; | ||
6 | use ide_db::call_info::ActiveParameter; | ||
7 | use itertools::Itertools; | ||
8 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
9 | |||
10 | use crate::{Analysis, Highlight, HighlightModifier, HighlightTag, HighlightedRange, RootDatabase}; | ||
11 | |||
12 | use super::HighlightedRangeStack; | ||
13 | |||
14 | pub(super) fn highlight_injection( | ||
15 | acc: &mut HighlightedRangeStack, | ||
16 | sema: &Semantics<RootDatabase>, | ||
17 | literal: ast::String, | ||
18 | expanded: SyntaxToken, | ||
19 | ) -> Option<()> { | ||
20 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
21 | if !active_parameter.name.starts_with("ra_fixture") { | ||
22 | return None; | ||
23 | } | ||
24 | let value = literal.value()?; | ||
25 | let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned()); | ||
26 | |||
27 | if let Some(range) = literal.open_quote_text_range() { | ||
28 | acc.add(HighlightedRange { | ||
29 | range, | ||
30 | highlight: HighlightTag::StringLiteral.into(), | ||
31 | binding_hash: None, | ||
32 | }) | ||
33 | } | ||
34 | |||
35 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | ||
36 | if let Some(r) = literal.map_range_up(h.range) { | ||
37 | h.range = r; | ||
38 | acc.add(h) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | if let Some(range) = literal.close_quote_text_range() { | ||
43 | acc.add(HighlightedRange { | ||
44 | range, | ||
45 | highlight: HighlightTag::StringLiteral.into(), | ||
46 | binding_hash: None, | ||
47 | }) | ||
48 | } | ||
49 | |||
50 | Some(()) | ||
51 | } | ||
52 | |||
53 | /// Mapping from extracted documentation code to original code | ||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | ||
55 | |||
56 | const RUSTDOC_FENCE: &'static str = "```"; | ||
57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | ||
58 | "", | ||
59 | "rust", | ||
60 | "should_panic", | ||
61 | "ignore", | ||
62 | "no_run", | ||
63 | "compile_fail", | ||
64 | "edition2015", | ||
65 | "edition2018", | ||
66 | "edition2021", | ||
67 | ]; | ||
68 | |||
69 | /// Extracts Rust code from documentation comments as well as a mapping from | ||
70 | /// the extracted source code back to the original source ranges. | ||
71 | /// Lastly, a vector of new comment highlight ranges (spanning only the | ||
72 | /// comment prefix) is returned which is used in the syntax highlighting | ||
73 | /// injection to replace the previous (line-spanning) comment ranges. | ||
74 | pub(super) fn extract_doc_comments( | ||
75 | node: &SyntaxNode, | ||
76 | ) -> Option<(String, RangesMap, Vec<HighlightedRange>)> { | ||
77 | // wrap the doctest into function body to get correct syntax highlighting | ||
78 | let prefix = "fn doctest() {\n"; | ||
79 | let suffix = "}\n"; | ||
80 | // Mapping from extracted documentation code to original code | ||
81 | let mut range_mapping: RangesMap = BTreeMap::new(); | ||
82 | let mut line_start = TextSize::try_from(prefix.len()).unwrap(); | ||
83 | let mut is_codeblock = false; | ||
84 | let mut is_doctest = false; | ||
85 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | ||
86 | // spanning comment ranges. | ||
87 | let mut new_comments = Vec::new(); | ||
88 | let doctest = node | ||
89 | .children_with_tokens() | ||
90 | .filter_map(|el| el.into_token().and_then(ast::Comment::cast)) | ||
91 | .filter(|comment| comment.kind().doc.is_some()) | ||
92 | .filter(|comment| { | ||
93 | if let Some(idx) = comment.text().find(RUSTDOC_FENCE) { | ||
94 | is_codeblock = !is_codeblock; | ||
95 | // Check whether code is rust by inspecting fence guards | ||
96 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | ||
97 | let is_rust = | ||
98 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | ||
99 | is_doctest = is_codeblock && is_rust; | ||
100 | false | ||
101 | } else { | ||
102 | is_doctest | ||
103 | } | ||
104 | }) | ||
105 | .map(|comment| { | ||
106 | let prefix_len = comment.prefix().len(); | ||
107 | let line: &str = comment.text().as_str(); | ||
108 | let range = comment.syntax().text_range(); | ||
109 | |||
110 | // whitespace after comment is ignored | ||
111 | let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) { | ||
112 | prefix_len + ws.len_utf8() | ||
113 | } else { | ||
114 | prefix_len | ||
115 | }; | ||
116 | |||
117 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
118 | let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') { | ||
119 | pos + ws.len_utf8() | ||
120 | } else { | ||
121 | pos | ||
122 | }; | ||
123 | |||
124 | range_mapping.insert(line_start, range.start() + TextSize::try_from(pos).unwrap()); | ||
125 | new_comments.push(HighlightedRange { | ||
126 | range: TextRange::new( | ||
127 | range.start(), | ||
128 | range.start() + TextSize::try_from(pos).unwrap(), | ||
129 | ), | ||
130 | highlight: HighlightTag::Comment | HighlightModifier::Documentation, | ||
131 | binding_hash: None, | ||
132 | }); | ||
133 | line_start += range.len() - TextSize::try_from(pos).unwrap(); | ||
134 | line_start += TextSize::try_from('\n'.len_utf8()).unwrap(); | ||
135 | |||
136 | line[pos..].to_owned() | ||
137 | }) | ||
138 | .join("\n"); | ||
139 | |||
140 | if doctest.is_empty() { | ||
141 | return None; | ||
142 | } | ||
143 | |||
144 | let doctest = format!("{}{}{}", prefix, doctest, suffix); | ||
145 | Some((doctest, range_mapping, new_comments)) | ||
146 | } | ||
147 | |||
148 | /// Injection of syntax highlighting of doctests. | ||
149 | pub(super) fn highlight_doc_comment( | ||
150 | text: String, | ||
151 | range_mapping: RangesMap, | ||
152 | new_comments: Vec<HighlightedRange>, | ||
153 | stack: &mut HighlightedRangeStack, | ||
154 | ) { | ||
155 | let (analysis, tmp_file_id) = Analysis::from_single_file(text); | ||
156 | |||
157 | stack.push(); | ||
158 | for mut h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | ||
159 | // Determine start offset and end offset in case of multi-line ranges | ||
160 | let mut start_offset = None; | ||
161 | let mut end_offset = None; | ||
162 | for (line_start, orig_line_start) in range_mapping.range(..h.range.end()).rev() { | ||
163 | // It's possible for orig_line_start - line_start to be negative. Add h.range.start() | ||
164 | // here and remove it from the end range after the loop below so that the values are | ||
165 | // always non-negative. | ||
166 | let offset = h.range.start() + orig_line_start - line_start; | ||
167 | if line_start <= &h.range.start() { | ||
168 | start_offset.get_or_insert(offset); | ||
169 | break; | ||
170 | } else { | ||
171 | end_offset.get_or_insert(offset); | ||
172 | } | ||
173 | } | ||
174 | if let Some(start_offset) = start_offset { | ||
175 | h.range = TextRange::new( | ||
176 | start_offset, | ||
177 | h.range.end() + end_offset.unwrap_or(start_offset) - h.range.start(), | ||
178 | ); | ||
179 | |||
180 | h.highlight |= HighlightModifier::Injected; | ||
181 | stack.add(h); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | // Inject the comment prefix highlight ranges | ||
186 | stack.push(); | ||
187 | for comment in new_comments { | ||
188 | stack.add(comment); | ||
189 | } | ||
190 | stack.pop_and_inject(None); | ||
191 | stack.pop_and_inject(Some(Highlight::from(HighlightTag::Dummy) | HighlightModifier::Injected)); | ||
192 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs new file mode 100644 index 000000000..24ff473ec --- /dev/null +++ b/crates/ide/src/syntax_highlighting/injector.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | //! Extracts a subsequence of a text document, remembering the mapping of ranges | ||
2 | //! between original and extracted texts. | ||
3 | use std::ops::{self, Sub}; | ||
4 | |||
5 | use stdx::equal_range_by; | ||
6 | use syntax::{TextRange, TextSize}; | ||
7 | |||
8 | #[derive(Default)] | ||
9 | pub(super) struct Injector { | ||
10 | buf: String, | ||
11 | ranges: Vec<(TextRange, Option<Delta<TextSize>>)>, | ||
12 | } | ||
13 | |||
14 | impl Injector { | ||
15 | pub(super) fn add(&mut self, text: &str, source_range: TextRange) { | ||
16 | let len = TextSize::of(text); | ||
17 | assert_eq!(len, source_range.len()); | ||
18 | self.add_impl(text, Some(source_range.start())); | ||
19 | } | ||
20 | pub(super) fn add_unmapped(&mut self, text: &str) { | ||
21 | self.add_impl(text, None); | ||
22 | } | ||
23 | fn add_impl(&mut self, text: &str, source: Option<TextSize>) { | ||
24 | let len = TextSize::of(text); | ||
25 | let target_range = TextRange::at(TextSize::of(&self.buf), len); | ||
26 | self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it)))); | ||
27 | self.buf.push_str(text); | ||
28 | } | ||
29 | |||
30 | pub(super) fn text(&self) -> &str { | ||
31 | &self.buf | ||
32 | } | ||
33 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
34 | equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| { | ||
35 | let (target_range, delta) = self.ranges[i]; | ||
36 | let intersection = target_range.intersect(range).unwrap(); | ||
37 | Some(intersection + delta?) | ||
38 | }) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | #[derive(Clone, Copy)] | ||
43 | enum Delta<T> { | ||
44 | Add(T), | ||
45 | Sub(T), | ||
46 | } | ||
47 | |||
48 | impl<T> Delta<T> { | ||
49 | fn new(from: T, to: T) -> Delta<T> | ||
50 | where | ||
51 | T: Ord + Sub<Output = T>, | ||
52 | { | ||
53 | if to >= from { | ||
54 | Delta::Add(to - from) | ||
55 | } else { | ||
56 | Delta::Sub(from - to) | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | impl ops::Add<Delta<TextSize>> for TextSize { | ||
62 | type Output = TextSize; | ||
63 | |||
64 | fn add(self, rhs: Delta<TextSize>) -> TextSize { | ||
65 | match rhs { | ||
66 | Delta::Add(it) => self + it, | ||
67 | Delta::Sub(it) => self - it, | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | impl ops::Add<Delta<TextSize>> for TextRange { | ||
73 | type Output = TextRange; | ||
74 | |||
75 | fn add(self, rhs: Delta<TextSize>) -> TextRange { | ||
76 | TextRange::at(self.start() + rhs, self.len()) | ||
77 | } | ||
78 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_rules.rs index 4462af47e..44620e912 100644 --- a/crates/ide/src/syntax_highlighting/macro_rules.rs +++ b/crates/ide/src/syntax_highlighting/macro_rules.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Syntax highlighting for macro_rules!. | 1 | //! Syntax highlighting for macro_rules!. |
2 | use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; | 2 | use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; |
3 | 3 | ||
4 | use crate::{HighlightTag, HighlightedRange}; | 4 | use crate::{HlRange, HlTag}; |
5 | 5 | ||
6 | #[derive(Default)] | 6 | #[derive(Default)] |
7 | pub(super) struct MacroRulesHighlighter { | 7 | pub(super) struct MacroRulesHighlighter { |
@@ -19,13 +19,13 @@ impl MacroRulesHighlighter { | |||
19 | } | 19 | } |
20 | } | 20 | } |
21 | 21 | ||
22 | pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HighlightedRange> { | 22 | pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HlRange> { |
23 | if let Some(state) = self.state.as_ref() { | 23 | if let Some(state) = self.state.as_ref() { |
24 | if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { | 24 | if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { |
25 | if let Some(range) = is_metavariable(element) { | 25 | if let Some(range) = is_metavariable(element) { |
26 | return Some(HighlightedRange { | 26 | return Some(HlRange { |
27 | range, | 27 | range, |
28 | highlight: HighlightTag::UnresolvedReference.into(), | 28 | highlight: HlTag::UnresolvedReference.into(), |
29 | binding_hash: None, | 29 | binding_hash: None, |
30 | }); | 30 | }); |
31 | } | 31 | } |
@@ -119,7 +119,7 @@ fn is_metavariable(element: SyntaxElement) -> Option<TextRange> { | |||
119 | let tok = element.as_token()?; | 119 | let tok = element.as_token()?; |
120 | match tok.kind() { | 120 | match tok.kind() { |
121 | kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { | 121 | kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { |
122 | if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == SyntaxKind::DOLLAR) { | 122 | if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) { |
123 | return Some(tok.text_range()); | 123 | return Some(tok.text_range()); |
124 | } | 124 | } |
125 | } | 125 | } |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 8b8867079..8dd05ac52 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -7,15 +7,15 @@ use crate::SymbolKind; | |||
7 | 7 | ||
8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
9 | pub struct Highlight { | 9 | pub struct Highlight { |
10 | pub tag: HighlightTag, | 10 | pub tag: HlTag, |
11 | pub modifiers: HighlightModifiers, | 11 | pub mods: HlMods, |
12 | } | 12 | } |
13 | 13 | ||
14 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 14 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
15 | pub struct HighlightModifiers(u32); | 15 | pub struct HlMods(u32); |
16 | 16 | ||
17 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 17 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
18 | pub enum HighlightTag { | 18 | pub enum HlTag { |
19 | Symbol(SymbolKind), | 19 | Symbol(SymbolKind), |
20 | 20 | ||
21 | BoolLiteral, | 21 | BoolLiteral, |
@@ -29,17 +29,17 @@ pub enum HighlightTag { | |||
29 | EscapeSequence, | 29 | EscapeSequence, |
30 | FormatSpecifier, | 30 | FormatSpecifier, |
31 | Keyword, | 31 | Keyword, |
32 | Punctuation, | 32 | Punctuation(HlPunct), |
33 | Operator, | 33 | Operator, |
34 | UnresolvedReference, | 34 | UnresolvedReference, |
35 | 35 | ||
36 | // For things which don't have proper Tag, but want to use modifiers. | 36 | // For things which don't have a specific highlight. |
37 | Dummy, | 37 | None, |
38 | } | 38 | } |
39 | 39 | ||
40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
41 | #[repr(u8)] | 41 | #[repr(u8)] |
42 | pub enum HighlightModifier { | 42 | pub enum HlMod { |
43 | /// Used to differentiate individual elements within attributes. | 43 | /// Used to differentiate individual elements within attributes. |
44 | Attribute = 0, | 44 | Attribute = 0, |
45 | /// Used with keywords like `if` and `break`. | 45 | /// Used with keywords like `if` and `break`. |
@@ -61,10 +61,32 @@ pub enum HighlightModifier { | |||
61 | Unsafe, | 61 | Unsafe, |
62 | } | 62 | } |
63 | 63 | ||
64 | impl HighlightTag { | 64 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
65 | pub enum HlPunct { | ||
66 | /// [] | ||
67 | Bracket, | ||
68 | /// {} | ||
69 | Brace, | ||
70 | /// () | ||
71 | Parenthesis, | ||
72 | /// <> | ||
73 | Angle, | ||
74 | /// , | ||
75 | Comma, | ||
76 | /// . | ||
77 | Dot, | ||
78 | /// : | ||
79 | Colon, | ||
80 | /// ; | ||
81 | Semi, | ||
82 | /// | ||
83 | Other, | ||
84 | } | ||
85 | |||
86 | impl HlTag { | ||
65 | fn as_str(self) -> &'static str { | 87 | fn as_str(self) -> &'static str { |
66 | match self { | 88 | match self { |
67 | HighlightTag::Symbol(symbol) => match symbol { | 89 | HlTag::Symbol(symbol) => match symbol { |
68 | SymbolKind::Const => "constant", | 90 | SymbolKind::Const => "constant", |
69 | SymbolKind::Static => "static", | 91 | SymbolKind::Static => "static", |
70 | SymbolKind::Enum => "enum", | 92 | SymbolKind::Enum => "enum", |
@@ -86,59 +108,69 @@ impl HighlightTag { | |||
86 | SymbolKind::SelfParam => "self_keyword", | 108 | SymbolKind::SelfParam => "self_keyword", |
87 | SymbolKind::Impl => "self_type", | 109 | SymbolKind::Impl => "self_type", |
88 | }, | 110 | }, |
89 | HighlightTag::Attribute => "attribute", | 111 | HlTag::Attribute => "attribute", |
90 | HighlightTag::BoolLiteral => "bool_literal", | 112 | HlTag::BoolLiteral => "bool_literal", |
91 | HighlightTag::BuiltinType => "builtin_type", | 113 | HlTag::BuiltinType => "builtin_type", |
92 | HighlightTag::ByteLiteral => "byte_literal", | 114 | HlTag::ByteLiteral => "byte_literal", |
93 | HighlightTag::CharLiteral => "char_literal", | 115 | HlTag::CharLiteral => "char_literal", |
94 | HighlightTag::Comment => "comment", | 116 | HlTag::Comment => "comment", |
95 | HighlightTag::EscapeSequence => "escape_sequence", | 117 | HlTag::EscapeSequence => "escape_sequence", |
96 | HighlightTag::FormatSpecifier => "format_specifier", | 118 | HlTag::FormatSpecifier => "format_specifier", |
97 | HighlightTag::Dummy => "dummy", | 119 | HlTag::Keyword => "keyword", |
98 | HighlightTag::Keyword => "keyword", | 120 | HlTag::Punctuation(punct) => match punct { |
99 | HighlightTag::Punctuation => "punctuation", | 121 | HlPunct::Bracket => "bracket", |
100 | HighlightTag::NumericLiteral => "numeric_literal", | 122 | HlPunct::Brace => "brace", |
101 | HighlightTag::Operator => "operator", | 123 | HlPunct::Parenthesis => "parenthesis", |
102 | HighlightTag::StringLiteral => "string_literal", | 124 | HlPunct::Angle => "angle", |
103 | HighlightTag::UnresolvedReference => "unresolved_reference", | 125 | HlPunct::Comma => "comma", |
126 | HlPunct::Dot => "dot", | ||
127 | HlPunct::Colon => "colon", | ||
128 | HlPunct::Semi => "semicolon", | ||
129 | HlPunct::Other => "punctuation", | ||
130 | }, | ||
131 | HlTag::NumericLiteral => "numeric_literal", | ||
132 | HlTag::Operator => "operator", | ||
133 | HlTag::StringLiteral => "string_literal", | ||
134 | HlTag::UnresolvedReference => "unresolved_reference", | ||
135 | HlTag::None => "none", | ||
104 | } | 136 | } |
105 | } | 137 | } |
106 | } | 138 | } |
107 | 139 | ||
108 | impl fmt::Display for HighlightTag { | 140 | impl fmt::Display for HlTag { |
109 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 141 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
110 | fmt::Display::fmt(self.as_str(), f) | 142 | fmt::Display::fmt(self.as_str(), f) |
111 | } | 143 | } |
112 | } | 144 | } |
113 | 145 | ||
114 | impl HighlightModifier { | 146 | impl HlMod { |
115 | const ALL: &'static [HighlightModifier; HighlightModifier::Unsafe as u8 as usize + 1] = &[ | 147 | const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ |
116 | HighlightModifier::Attribute, | 148 | HlMod::Attribute, |
117 | HighlightModifier::ControlFlow, | 149 | HlMod::ControlFlow, |
118 | HighlightModifier::Definition, | 150 | HlMod::Definition, |
119 | HighlightModifier::Documentation, | 151 | HlMod::Documentation, |
120 | HighlightModifier::Injected, | 152 | HlMod::Injected, |
121 | HighlightModifier::Mutable, | 153 | HlMod::Mutable, |
122 | HighlightModifier::Consuming, | 154 | HlMod::Consuming, |
123 | HighlightModifier::Callable, | 155 | HlMod::Callable, |
124 | HighlightModifier::Static, | 156 | HlMod::Static, |
125 | HighlightModifier::Associated, | 157 | HlMod::Associated, |
126 | HighlightModifier::Unsafe, | 158 | HlMod::Unsafe, |
127 | ]; | 159 | ]; |
128 | 160 | ||
129 | fn as_str(self) -> &'static str { | 161 | fn as_str(self) -> &'static str { |
130 | match self { | 162 | match self { |
131 | HighlightModifier::Attribute => "attribute", | 163 | HlMod::Attribute => "attribute", |
132 | HighlightModifier::ControlFlow => "control", | 164 | HlMod::ControlFlow => "control", |
133 | HighlightModifier::Definition => "declaration", | 165 | HlMod::Definition => "declaration", |
134 | HighlightModifier::Documentation => "documentation", | 166 | HlMod::Documentation => "documentation", |
135 | HighlightModifier::Injected => "injected", | 167 | HlMod::Injected => "injected", |
136 | HighlightModifier::Mutable => "mutable", | 168 | HlMod::Mutable => "mutable", |
137 | HighlightModifier::Consuming => "consuming", | 169 | HlMod::Consuming => "consuming", |
138 | HighlightModifier::Unsafe => "unsafe", | 170 | HlMod::Unsafe => "unsafe", |
139 | HighlightModifier::Callable => "callable", | 171 | HlMod::Callable => "callable", |
140 | HighlightModifier::Static => "static", | 172 | HlMod::Static => "static", |
141 | HighlightModifier::Associated => "associated", | 173 | HlMod::Associated => "associated", |
142 | } | 174 | } |
143 | } | 175 | } |
144 | 176 | ||
@@ -147,7 +179,7 @@ impl HighlightModifier { | |||
147 | } | 179 | } |
148 | } | 180 | } |
149 | 181 | ||
150 | impl fmt::Display for HighlightModifier { | 182 | impl fmt::Display for HlMod { |
151 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 183 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
152 | fmt::Display::fmt(self.as_str(), f) | 184 | fmt::Display::fmt(self.as_str(), f) |
153 | } | 185 | } |
@@ -156,60 +188,63 @@ impl fmt::Display for HighlightModifier { | |||
156 | impl fmt::Display for Highlight { | 188 | impl fmt::Display for Highlight { |
157 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 189 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
158 | write!(f, "{}", self.tag)?; | 190 | write!(f, "{}", self.tag)?; |
159 | for modifier in self.modifiers.iter() { | 191 | for modifier in self.mods.iter() { |
160 | write!(f, ".{}", modifier)? | 192 | write!(f, ".{}", modifier)? |
161 | } | 193 | } |
162 | Ok(()) | 194 | Ok(()) |
163 | } | 195 | } |
164 | } | 196 | } |
165 | 197 | ||
166 | impl From<HighlightTag> for Highlight { | 198 | impl From<HlTag> for Highlight { |
167 | fn from(tag: HighlightTag) -> Highlight { | 199 | fn from(tag: HlTag) -> Highlight { |
168 | Highlight::new(tag) | 200 | Highlight::new(tag) |
169 | } | 201 | } |
170 | } | 202 | } |
171 | 203 | ||
172 | impl Highlight { | 204 | impl Highlight { |
173 | pub(crate) fn new(tag: HighlightTag) -> Highlight { | 205 | pub(crate) fn new(tag: HlTag) -> Highlight { |
174 | Highlight { tag, modifiers: HighlightModifiers::default() } | 206 | Highlight { tag, mods: HlMods::default() } |
207 | } | ||
208 | pub fn is_empty(&self) -> bool { | ||
209 | self.tag == HlTag::None && self.mods == HlMods::default() | ||
175 | } | 210 | } |
176 | } | 211 | } |
177 | 212 | ||
178 | impl ops::BitOr<HighlightModifier> for HighlightTag { | 213 | impl ops::BitOr<HlMod> for HlTag { |
179 | type Output = Highlight; | 214 | type Output = Highlight; |
180 | 215 | ||
181 | fn bitor(self, rhs: HighlightModifier) -> Highlight { | 216 | fn bitor(self, rhs: HlMod) -> Highlight { |
182 | Highlight::new(self) | rhs | 217 | Highlight::new(self) | rhs |
183 | } | 218 | } |
184 | } | 219 | } |
185 | 220 | ||
186 | impl ops::BitOrAssign<HighlightModifier> for HighlightModifiers { | 221 | impl ops::BitOrAssign<HlMod> for HlMods { |
187 | fn bitor_assign(&mut self, rhs: HighlightModifier) { | 222 | fn bitor_assign(&mut self, rhs: HlMod) { |
188 | self.0 |= rhs.mask(); | 223 | self.0 |= rhs.mask(); |
189 | } | 224 | } |
190 | } | 225 | } |
191 | 226 | ||
192 | impl ops::BitOrAssign<HighlightModifier> for Highlight { | 227 | impl ops::BitOrAssign<HlMod> for Highlight { |
193 | fn bitor_assign(&mut self, rhs: HighlightModifier) { | 228 | fn bitor_assign(&mut self, rhs: HlMod) { |
194 | self.modifiers |= rhs; | 229 | self.mods |= rhs; |
195 | } | 230 | } |
196 | } | 231 | } |
197 | 232 | ||
198 | impl ops::BitOr<HighlightModifier> for Highlight { | 233 | impl ops::BitOr<HlMod> for Highlight { |
199 | type Output = Highlight; | 234 | type Output = Highlight; |
200 | 235 | ||
201 | fn bitor(mut self, rhs: HighlightModifier) -> Highlight { | 236 | fn bitor(mut self, rhs: HlMod) -> Highlight { |
202 | self |= rhs; | 237 | self |= rhs; |
203 | self | 238 | self |
204 | } | 239 | } |
205 | } | 240 | } |
206 | 241 | ||
207 | impl HighlightModifiers { | 242 | impl HlMods { |
208 | pub fn contains(self, m: HighlightModifier) -> bool { | 243 | pub fn contains(self, m: HlMod) -> bool { |
209 | self.0 & m.mask() == m.mask() | 244 | self.0 & m.mask() == m.mask() |
210 | } | 245 | } |
211 | 246 | ||
212 | pub fn iter(self) -> impl Iterator<Item = HighlightModifier> { | 247 | pub fn iter(self) -> impl Iterator<Item = HlMod> { |
213 | HighlightModifier::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) | 248 | HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) |
214 | } | 249 | } |
215 | } | 250 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index 506ebe60e..d421a7803 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -36,22 +36,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 41 | <span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span> |
42 | 42 | ||
43 | <span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> | 43 | <span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span> |
44 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 44 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
45 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 45 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | 47 | ||
48 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> | 48 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> |
49 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 49 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
50 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 50 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
51 | <span class="punctuation">}</span> | 51 | <span class="brace">}</span> |
52 | 52 | ||
53 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> | 53 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> |
54 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 54 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
56 | <span class="punctuation">}</span> | 56 | <span class="brace">}</span> |
57 | </code></pre> \ No newline at end of file | 57 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 4dd7413ba..5e877df88 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -37,67 +37,72 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="comment documentation">/// ```</span> | 39 | <pre><code><span class="comment documentation">/// ```</span> |
40 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="punctuation injected">_</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 40 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="semicolon injected">;</span> |
41 | </span><span class="comment documentation">/// ```</span> | 41 | <span class="comment documentation">/// ```</span> |
42 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> | 42 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span> |
43 | <span class="field declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span><span class="punctuation">,</span> | 43 | <span class="field declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span><span class="comma">,</span> |
44 | <span class="punctuation">}</span> | 44 | <span class="brace">}</span> |
45 | 45 | ||
46 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 46 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> |
47 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="punctuation">;</span> | 47 | <span class="comment documentation">/// ```</span> |
48 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Call me</span> | ||
49 | <span class="comment">// KILLER WHALE</span> | ||
50 | <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span> | ||
51 | <span class="comment documentation">/// ```</span> | ||
52 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span> | ||
48 | 53 | ||
49 | <span class="comment documentation">/// Constructs a new `Foo`.</span> | 54 | <span class="comment documentation">/// Constructs a new `Foo`.</span> |
50 | <span class="comment documentation">///</span> | 55 | <span class="comment documentation">///</span> |
51 | <span class="comment documentation">/// # Examples</span> | 56 | <span class="comment documentation">/// # Examples</span> |
52 | <span class="comment documentation">///</span> | 57 | <span class="comment documentation">///</span> |
53 | <span class="comment documentation">/// ```</span> | 58 | <span class="comment documentation">/// ```</span> |
54 | <span class="comment documentation">/// #</span><span class="dummy injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="punctuation attribute injected">)</span><span class="attribute attribute injected">]</span> | 59 | <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span> |
55 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="keyword injected">mut</span><span class="dummy injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 60 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
56 | </span> <span class="comment documentation">/// ```</span> | 61 | <span class="comment documentation">/// ```</span> |
57 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 62 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="brace">{</span> |
58 | <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> | 63 | <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span> |
59 | <span class="punctuation">}</span> | 64 | <span class="brace">}</span> |
60 | 65 | ||
61 | <span class="comment documentation">/// `bar` method on `Foo`.</span> | 66 | <span class="comment documentation">/// `bar` method on `Foo`.</span> |
62 | <span class="comment documentation">///</span> | 67 | <span class="comment documentation">///</span> |
63 | <span class="comment documentation">/// # Examples</span> | 68 | <span class="comment documentation">/// # Examples</span> |
64 | <span class="comment documentation">///</span> | 69 | <span class="comment documentation">///</span> |
65 | <span class="comment documentation">/// ```</span> | 70 | <span class="comment documentation">/// ```</span> |
66 | <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="dummy injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="punctuation injected">;</span> | 71 | <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="none injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="semicolon injected">;</span> |
67 | <span class="comment documentation">///</span> | 72 | <span class="comment documentation">///</span> |
68 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> | 73 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
69 | <span class="comment documentation">///</span> | 74 | <span class="comment documentation">///</span> |
70 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> | 75 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> |
71 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="punctuation injected">(</span><span class="dummy injected">foo</span><span class="operator injected">.</span><span class="dummy injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> | 76 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
72 | <span class="comment documentation">///</span> | 77 | <span class="comment documentation">///</span> |
73 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">bar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="dummy injected"> </span><span class="operator injected">||</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="punctuation injected">;</span> | 78 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> |
74 | <span class="comment documentation">///</span> | 79 | <span class="comment documentation">///</span> |
75 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line | 80 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> |
76 | </span><span class="comment documentation">/// </span><span class="comment injected"> comment */</span> | 81 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> |
77 | <span class="comment documentation">///</span> | 82 | <span class="comment documentation">///</span> |
78 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"Foo | 83 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span> |
79 | </span><span class="comment documentation">/// </span><span class="string_literal injected"> bar | 84 | <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span> |
80 | </span><span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="punctuation injected">;</span> | 85 | <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span> |
81 | <span class="comment documentation">///</span> | 86 | <span class="comment documentation">///</span> |
82 | <span class="comment documentation">/// ```</span> | 87 | <span class="comment documentation">/// ```</span> |
83 | <span class="comment documentation">///</span> | 88 | <span class="comment documentation">///</span> |
84 | <span class="comment documentation">/// ```rust,no_run</span> | 89 | <span class="comment documentation">/// ```rust,no_run</span> |
85 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foobar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 90 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
86 | </span> <span class="comment documentation">/// ```</span> | 91 | <span class="comment documentation">/// ```</span> |
87 | <span class="comment documentation">///</span> | 92 | <span class="comment documentation">///</span> |
88 | <span class="comment documentation">/// ```sh</span> | 93 | <span class="comment documentation">/// ```sh</span> |
89 | <span class="comment documentation">/// echo 1</span> | 94 | <span class="comment documentation">/// echo 1</span> |
90 | <span class="comment documentation">/// ```</span> | 95 | <span class="comment documentation">/// ```</span> |
91 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="punctuation">{</span> | 96 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="brace">{</span> |
92 | <span class="bool_literal">true</span> | 97 | <span class="bool_literal">true</span> |
93 | <span class="punctuation">}</span> | 98 | <span class="brace">}</span> |
94 | <span class="punctuation">}</span> | 99 | <span class="brace">}</span> |
95 | 100 | ||
96 | <span class="comment documentation">/// ```</span> | 101 | <span class="comment documentation">/// ```</span> |
97 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 102 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
98 | </span><span class="comment documentation">/// ```</span> | 103 | <span class="comment documentation">/// ```</span> |
99 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> | 104 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> |
100 | <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span> | 105 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> |
101 | <span class="punctuation">$</span>expr | 106 | <span class="punctuation">$</span>expr |
102 | <span class="punctuation">}</span> | 107 | <span class="brace">}</span> |
103 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 108 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index ed452586a..6f7a7ffff 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -36,6 +36,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span> | 39 | <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="semicolon">;</span> |
40 | <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span> | 40 | <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="semicolon">;</span> |
41 | </code></pre> \ No newline at end of file | 41 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 92e7dc3e4..753b535b5 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -36,14 +36,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 41 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
42 | <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> | 42 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> |
43 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> | 43 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> |
44 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 44 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
45 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> | 45 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | <span class="punctuation">}</span><span class="string_literal">"#</span> | 47 | <span class="brace">}</span><span class="string_literal">"#</span> |
48 | <span class="punctuation">)</span><span class="punctuation">;</span> | 48 | <span class="parenthesis">)</span><span class="semicolon">;</span> |
49 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 49 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 31dad5d42..66d80c4b6 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -36,64 +36,64 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span> | 39 | <pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="brace">{</span> |
40 | <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</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> | 40 | <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span> |
41 | <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> | 41 | <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
42 | <span class="punctuation">}</span><span class="punctuation">)</span> | 42 | <span class="brace">}</span><span class="parenthesis">)</span> |
43 | <span class="punctuation">}</span> | 43 | <span class="brace">}</span> |
44 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 44 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
45 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span> | 45 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span> |
46 | <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> | 46 | <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> |
47 | <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</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="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> | 47 | <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>args<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> |
48 | <span class="punctuation">}</span> | 48 | <span class="brace">}</span> |
49 | 49 | ||
50 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 50 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
51 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> | 51 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> |
52 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "Hello"</span> | 52 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span> |
53 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "Hello, world!"</span> | 53 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span> |
54 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "The number is 1"</span> | 54 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span> |
55 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="numeric_literal">3</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "(3, 4)"</span> | 55 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="parenthesis">(</span><span class="numeric_literal">3</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span> |
56 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "4"</span> | 56 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span> |
57 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "1 2"</span> | 57 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span> |
58 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">42</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "0042" with leading zerosV</span> | 58 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">42</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span> |
59 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "2 1 1 2"</span> | 59 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span> |
60 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "test"</span> | 60 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span> |
61 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "2 1"</span> | 61 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span> |
62 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="punctuation">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="punctuation">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "a 3 b"</span> | 62 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="comma">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="comma">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span> |
63 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "{2}"</span> | 63 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span> |
64 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 64 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
65 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 65 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 66 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
67 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 67 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
68 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 68 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
69 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 69 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
70 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 70 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
71 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 71 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
72 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 72 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
73 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> | 73 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
74 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 74 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
75 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 75 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
76 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> | 76 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
77 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 77 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
78 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 78 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
79 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 79 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
80 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 80 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
81 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 81 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
82 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 82 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="comma">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
83 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="punctuation">)</span><span class="punctuation">;</span> | 83 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
84 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 84 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
85 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 85 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
86 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello {{}}"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 86 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello {{}}"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
87 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{ Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 87 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{ Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
88 | 88 | ||
89 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 89 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
90 | 90 | ||
91 | <span class="comment">// escape sequences</span> | 91 | <span class="comment">// escape sequences</span> |
92 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 92 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
93 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 93 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
94 | 94 | ||
95 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 95 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
96 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 96 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
97 | 97 | ||
98 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="punctuation">,</span> thingy<span class="punctuation">,</span> n2<span class="punctuation">)</span><span class="punctuation">;</span> | 98 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="comma">,</span> thingy<span class="comma">,</span> n2<span class="parenthesis">)</span><span class="semicolon">;</span> |
99 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 99 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index e3a0aa317..036cb6c11 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -36,65 +36,65 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span> | 41 | <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span> |
42 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> | 42 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span> |
43 | <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span> | 43 | <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span> |
44 | <span class="punctuation">}</span> | 44 | <span class="brace">}</span> |
45 | 45 | ||
46 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> | 46 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span> |
47 | 47 | ||
48 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> | 48 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span> |
49 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 49 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
50 | <span class="punctuation">}</span> | 50 | <span class="brace">}</span> |
51 | 51 | ||
52 | <span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> | 52 | <span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span> |
53 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span> | 53 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u8</span> |
54 | <span class="punctuation">}</span> | 54 | <span class="brace">}</span> |
55 | 55 | ||
56 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 56 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="colon">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
57 | 57 | ||
58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="punctuation attribute">(</span><span class="attribute attribute">packed</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> | 58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> |
59 | <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span> | 59 | <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span> |
60 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span> | 60 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> |
61 | <span class="punctuation">}</span> | 61 | <span class="brace">}</span> |
62 | 62 | ||
63 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> | 63 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
64 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span> | 64 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
65 | <span class="punctuation">}</span> | 65 | <span class="brace">}</span> |
66 | 66 | ||
67 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span> | 67 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> |
68 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 68 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
69 | <span class="punctuation">}</span> | 69 | <span class="brace">}</span> |
70 | 70 | ||
71 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 71 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
72 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> | 72 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span> |
73 | <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 73 | <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
74 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 74 | <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> |
75 | <span class="comment">// unsafe fn and method calls</span> | 75 | <span class="comment">// unsafe fn and method calls</span> |
76 | <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 76 | <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
77 | <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="punctuation">;</span> | 77 | <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span> |
78 | <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span> | 78 | <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span> |
79 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 79 | <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
80 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 80 | <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
81 | <span class="punctuation">}</span> | 81 | <span class="brace">}</span> |
82 | <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 82 | <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
83 | 83 | ||
84 | <span class="comment">// unsafe deref</span> | 84 | <span class="comment">// unsafe deref</span> |
85 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span> | 85 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span> |
86 | 86 | ||
87 | <span class="comment">// unsafe access to a static mut</span> | 87 | <span class="comment">// unsafe access to a static mut</span> |
88 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 88 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
89 | 89 | ||
90 | <span class="comment">// unsafe ref of packed fields</span> | 90 | <span class="comment">// unsafe ref of packed fields</span> |
91 | <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 91 | <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
92 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 92 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
93 | <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 93 | <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
94 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | 94 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
95 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | 95 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
96 | 96 | ||
97 | <span class="comment">// unsafe auto ref of packed field</span> | 97 | <span class="comment">// unsafe auto ref of packed field</span> |
98 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 98 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
99 | <span class="punctuation">}</span> | 99 | <span class="brace">}</span> |
100 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 100 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 02270b077..237149566 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -36,187 +36,187 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span> | 39 | <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span> |
40 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 40 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> |
41 | 41 | ||
42 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 42 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
43 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 43 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
44 | 44 | ||
45 | <span class="comment">// Needed for function consuming vs normal</span> | 45 | <span class="comment">// Needed for function consuming vs normal</span> |
46 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span> | 46 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> |
47 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> | 47 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> |
48 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 48 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
49 | <span class="punctuation">}</span> | 49 | <span class="brace">}</span> |
50 | 50 | ||
51 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="punctuation">{</span> | 51 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="brace">{</span> |
52 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> | 52 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> |
53 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 53 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
54 | 54 | ||
55 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> | 55 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> |
56 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span><span class="punctuation">:</span> <span class="trait">FnOnce</span><span class="punctuation"><</span><span class="type_param">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 56 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span><span class="colon">:</span> <span class="trait">FnOnce</span><span class="angle"><</span><span class="type_param">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
57 | 57 | ||
58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> | 58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> |
59 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span><span class="punctuation">:</span> <span class="trait">FnMut</span><span class="punctuation"><</span><span class="type_param">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 59 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span><span class="colon">:</span> <span class="trait">FnMut</span><span class="angle"><</span><span class="type_param">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
60 | <span class="punctuation">}</span> | 60 | <span class="brace">}</span> |
61 | 61 | ||
62 | 62 | ||
63 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> | 63 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span> |
64 | <span class="keyword">pub</span> <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> | 64 | <span class="keyword">pub</span> <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span> |
65 | <span class="keyword">pub</span> <span class="field declaration">y</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> | 65 | <span class="keyword">pub</span> <span class="field declaration">y</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span> |
66 | <span class="punctuation">}</span> | 66 | <span class="brace">}</span> |
67 | 67 | ||
68 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span> | 68 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> |
69 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="punctuation">;</span> | 69 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> |
70 | <span class="punctuation">}</span> | 70 | <span class="brace">}</span> |
71 | 71 | ||
72 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 72 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> |
73 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 73 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
74 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 74 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
75 | <span class="punctuation">}</span> | 75 | <span class="brace">}</span> |
76 | <span class="punctuation">}</span> | 76 | <span class="brace">}</span> |
77 | 77 | ||
78 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 78 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> |
79 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 79 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
80 | <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span> | 80 | <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span> |
81 | <span class="punctuation">}</span> | 81 | <span class="brace">}</span> |
82 | 82 | ||
83 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 83 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> |
84 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 84 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
85 | <span class="punctuation">}</span> | 85 | <span class="brace">}</span> |
86 | 86 | ||
87 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 87 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
88 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 88 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
89 | <span class="punctuation">}</span> | 89 | <span class="brace">}</span> |
90 | <span class="punctuation">}</span> | 90 | <span class="brace">}</span> |
91 | 91 | ||
92 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="punctuation attribute">(</span><span class="attribute attribute">Copy</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> | 92 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="parenthesis attribute">(</span><span class="attribute attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> |
93 | <span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="punctuation">{</span> | 93 | <span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span> |
94 | <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> | 94 | <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span> |
95 | <span class="punctuation">}</span> | 95 | <span class="brace">}</span> |
96 | 96 | ||
97 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> | 97 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span> |
98 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">FooCopy</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 98 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="brace">{</span> |
99 | <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> | 99 | <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span> |
100 | <span class="punctuation">}</span> | 100 | <span class="brace">}</span> |
101 | 101 | ||
102 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 102 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> |
103 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 103 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
104 | <span class="punctuation">}</span> | 104 | <span class="brace">}</span> |
105 | 105 | ||
106 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 106 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="brace">{</span> |
107 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 107 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
108 | <span class="punctuation">}</span> | 108 | <span class="brace">}</span> |
109 | <span class="punctuation">}</span> | 109 | <span class="brace">}</span> |
110 | 110 | ||
111 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 111 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
112 | 112 | ||
113 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation"><</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="punctuation">{</span> | 113 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="angle"><</span><span class="lifetime declaration">'a</span><span class="comma">,</span> <span class="type_param declaration">T</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="brace">{</span> |
114 | <span class="function">foo</span><span class="operator">::</span><span class="punctuation"><</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> | 114 | <span class="function">foo</span><span class="operator">::</span><span class="angle"><</span><span class="lifetime">'a</span><span class="comma">,</span> <span class="builtin_type">i32</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> |
115 | <span class="punctuation">}</span> | 115 | <span class="brace">}</span> |
116 | 116 | ||
117 | <span class="keyword">fn</span> <span class="function declaration">never</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">!</span> <span class="punctuation">{</span> | 117 | <span class="keyword">fn</span> <span class="function declaration">never</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">!</span> <span class="brace">{</span> |
118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 118 | <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span> |
119 | <span class="punctuation">}</span> | 119 | <span class="brace">}</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> | 121 | <span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle"><</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">usize</span> <span class="brace">{</span> |
122 | <span class="const_param">FOO</span> | 122 | <span class="const_param">FOO</span> |
123 | <span class="punctuation">}</span> | 123 | <span class="brace">}</span> |
124 | 124 | ||
125 | <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="semicolon">;</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> | 126 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle"><</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">></span><span class="parenthesis">(</span><span class="value_param declaration callable">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span> |
127 | <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="parenthesis">(</span><span class="parenthesis">)</span> |
128 | <span class="punctuation">}</span> | 128 | <span class="brace">}</span> |
129 | 129 | ||
130 | <span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 130 | <span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
131 | 131 | ||
132 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 132 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
133 | <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 133 | <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
134 | <span class="punctuation">}</span> | 134 | <span class="brace">}</span> |
135 | 135 | ||
136 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span> | 136 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span> |
137 | <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</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="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span> | 137 | <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span> |
138 | <span class="punctuation">}</span> | 138 | <span class="brace">}</span> |
139 | 139 | ||
140 | <span class="macro">def_fn!</span> <span class="punctuation">{</span> | 140 | <span class="macro">def_fn!</span> <span class="brace">{</span> |
141 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-</span><span class="operator">></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 141 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-</span><span class="operator">></span> <span class="builtin_type">u32</span> <span class="brace">{</span> |
142 | <span class="numeric_literal">100</span> | 142 | <span class="numeric_literal">100</span> |
143 | <span class="punctuation">}</span> | 143 | <span class="brace">}</span> |
144 | <span class="punctuation">}</span> | 144 | <span class="brace">}</span> |
145 | 145 | ||
146 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> | 146 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> |
147 | <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span> | 147 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> |
148 | <span class="punctuation">$</span>expr | 148 | <span class="punctuation">$</span>expr |
149 | <span class="punctuation">}</span> | 149 | <span class="brace">}</span> |
150 | <span class="punctuation">}</span> | 150 | <span class="brace">}</span> |
151 | 151 | ||
152 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span> | 152 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span> |
153 | <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span> | 153 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> |
154 | <span class="punctuation">}</span> | 154 | <span class="brace">}</span> |
155 | 155 | ||
156 | <span class="comment">// comment</span> | 156 | <span class="comment">// comment</span> |
157 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 157 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
158 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 158 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
159 | 159 | ||
160 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 160 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
161 | <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="punctuation">{</span> | 161 | <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="brace">{</span> |
162 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">;</span> | 162 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span> |
163 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="punctuation">(</span><span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="numeric_literal">1</span> <span class="punctuation">}</span><span class="punctuation">)</span><span class="punctuation">;</span> | 163 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="parenthesis">(</span><span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="numeric_literal">1</span> <span class="brace">}</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
164 | <span class="punctuation">}</span> | 164 | <span class="brace">}</span> |
165 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 165 | <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> |
166 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> | 166 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="parenthesis">(</span><span class="numeric_literal">0</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
167 | <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> | 167 | <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span> |
168 | <span class="punctuation">}</span> | 168 | <span class="brace">}</span> |
169 | 169 | ||
170 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> | 170 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="brace">{</span> |
171 | <span class="comment">// Do nothing</span> | 171 | <span class="comment">// Do nothing</span> |
172 | <span class="punctuation">}</span> | 172 | <span class="brace">}</span> |
173 | 173 | ||
174 | <span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> | 174 | <span class="macro">noop!</span><span class="parenthesis">(</span><span class="macro">noop</span><span class="macro">!</span><span class="parenthesis">(</span><span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
175 | 175 | ||
176 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span> | 176 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span> |
177 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span> | 177 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="semicolon">;</span> |
178 | <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span> | 178 | <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="semicolon">;</span> |
179 | 179 | ||
180 | <span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 180 | <span class="keyword">let</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable declaration">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span><span class="semicolon">;</span> |
181 | 181 | ||
182 | <span class="variable">y</span><span class="punctuation">;</span> | 182 | <span class="variable">y</span><span class="semicolon">;</span> |
183 | 183 | ||
184 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 184 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
185 | <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 185 | <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
186 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 186 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
187 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 187 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
188 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> | 188 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
189 | 189 | ||
190 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 190 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
191 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 191 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
192 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 192 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
193 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> | 193 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
194 | 194 | ||
195 | <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span> | 195 | <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> |
196 | <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="punctuation">;</span> | 196 | <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> |
197 | 197 | ||
198 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="punctuation">;</span> | 198 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> |
199 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> | 199 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> |
200 | 200 | ||
201 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> | 201 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> |
202 | 202 | ||
203 | <span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span> | 203 | <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> |
204 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span> | 204 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> |
205 | <span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span> | 205 | <span class="keyword control">continue</span> <span class="label">'foo</span><span class="semicolon">;</span> |
206 | <span class="punctuation">}</span> | 206 | <span class="brace">}</span> |
207 | <span class="punctuation">}</span> | 207 | <span class="brace">}</span> |
208 | 208 | ||
209 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 209 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="brace">{</span> |
210 | <span class="enum_variant declaration">Some</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">)</span><span class="punctuation">,</span> | 210 | <span class="enum_variant declaration">Some</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="comma">,</span> |
211 | <span class="enum_variant declaration">None</span><span class="punctuation">,</span> | 211 | <span class="enum_variant declaration">None</span><span class="comma">,</span> |
212 | <span class="punctuation">}</span> | 212 | <span class="brace">}</span> |
213 | <span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span> | 213 | <span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> |
214 | 214 | ||
215 | <span class="keyword">impl</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="enum">Option</span><span class="punctuation"><</span><span class="type_param">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 215 | <span class="keyword">impl</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">T</span><span class="angle">></span> <span class="brace">{</span> |
216 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="punctuation"><</span><span class="type_param declaration">U</span><span class="punctuation">></span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">other</span><span class="punctuation">:</span> <span class="enum">Option</span><span class="punctuation"><</span><span class="type_param">U</span><span class="punctuation">></span><span class="punctuation">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="punctuation"><</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">,</span> <span class="type_param">U</span><span class="punctuation">)</span><span class="punctuation">></span> <span class="punctuation">{</span> | 216 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle"><</span><span class="type_param declaration">U</span><span class="angle">></span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">U</span><span class="angle">></span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="angle"><</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">></span> <span class="brace">{</span> |
217 | <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span> | 217 | <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span> |
218 | <span class="enum_variant">None</span> <span class="operator">=></span> <span class="macro">unimplemented!</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 218 | <span class="enum_variant">None</span> <span class="operator">=></span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
219 | <span class="variable declaration">Nope</span> <span class="operator">=></span> <span class="variable">Nope</span><span class="punctuation">,</span> | 219 | <span class="variable declaration">Nope</span> <span class="operator">=></span> <span class="variable">Nope</span><span class="comma">,</span> |
220 | <span class="punctuation">}</span> | 220 | <span class="brace">}</span> |
221 | <span class="punctuation">}</span> | 221 | <span class="brace">}</span> |
222 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 222 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html new file mode 100644 index 000000000..78dfec951 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .label { color: #DFAF8F; font-style: italic; } | ||
8 | .comment { color: #7F9F7F; } | ||
9 | .documentation { color: #629755; } | ||
10 | .injected { opacity: 0.65 ; } | ||
11 | .struct, .enum { color: #7CB8BB; } | ||
12 | .enum_variant { color: #BDE0F3; } | ||
13 | .string_literal { color: #CC9393; } | ||
14 | .field { color: #94BFF3; } | ||
15 | .function { color: #93E0E3; } | ||
16 | .function.unsafe { color: #BC8383; } | ||
17 | .operator.unsafe { color: #BC8383; } | ||
18 | .parameter { color: #94BFF3; } | ||
19 | .text { color: #DCDCCC; } | ||
20 | .type { color: #7CB8BB; } | ||
21 | .builtin_type { color: #8CD0D3; } | ||
22 | .type_param { color: #DFAF8F; } | ||
23 | .attribute { color: #94BFF3; } | ||
24 | .numeric_literal { color: #BFEBBF; } | ||
25 | .bool_literal { color: #BFE6EB; } | ||
26 | .macro { color: #94BFF3; } | ||
27 | .module { color: #AFD8AF; } | ||
28 | .value_param { color: #DCDCCC; } | ||
29 | .variable { color: #DCDCCC; } | ||
30 | .format_specifier { color: #CC696B; } | ||
31 | .mutable { text-decoration: underline; } | ||
32 | .escape_sequence { color: #94BFF3; } | ||
33 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
34 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
35 | .control { font-style: italic; } | ||
36 | |||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | ||
38 | </style> | ||
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
40 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
41 | <span class="function">f</span><span class="parenthesis">(</span><span class="string_literal">r"</span> | ||
42 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
43 | <span class="function">foo</span><span class="parenthesis">(</span><span class="keyword">$0</span><span class="brace">{</span> | ||
44 | <span class="numeric_literal">92</span> | ||
45 | <span class="brace">}</span><span class="keyword">$0</span><span class="parenthesis">)</span> | ||
46 | <span class="brace">}</span><span class="string_literal">"</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
47 | <span class="brace">}</span> | ||
48 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index 8b3dfa69f..e64f2e5e9 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -36,15 +36,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
40 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> | 40 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> |
41 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 41 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
42 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 42 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
43 | 43 | ||
44 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="punctuation">;</span> | 44 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span> |
45 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 45 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | 47 | ||
48 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 48 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
49 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> | 49 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> |
50 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 50 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 30b5b648e..a62704c39 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -446,6 +446,11 @@ struct Foo { | |||
446 | } | 446 | } |
447 | 447 | ||
448 | impl Foo { | 448 | impl Foo { |
449 | /// ``` | ||
450 | /// let _ = "Call me | ||
451 | // KILLER WHALE | ||
452 | /// Ishmael."; | ||
453 | /// ``` | ||
449 | pub const bar: bool = true; | 454 | pub const bar: bool = true; |
450 | 455 | ||
451 | /// Constructs a new `Foo`. | 456 | /// Constructs a new `Foo`. |
@@ -555,6 +560,25 @@ impl t for foo { | |||
555 | ) | 560 | ) |
556 | } | 561 | } |
557 | 562 | ||
563 | #[test] | ||
564 | fn test_injection() { | ||
565 | check_highlighting( | ||
566 | r##" | ||
567 | fn f(ra_fixture: &str) {} | ||
568 | fn main() { | ||
569 | f(r" | ||
570 | fn foo() { | ||
571 | foo(\$0{ | ||
572 | 92 | ||
573 | }\$0) | ||
574 | }"); | ||
575 | } | ||
576 | "##, | ||
577 | expect_file!["./test_data/injection.html"], | ||
578 | false, | ||
579 | ); | ||
580 | } | ||
581 | |||
558 | /// Highlights the code given by the `ra_fixture` argument, renders the | 582 | /// Highlights the code given by the `ra_fixture` argument, renders the |
559 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | 583 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
560 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | 584 | /// Note that the `snapshot` file is overwritten by the rendered HTML. |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 6dd05c05d..4c63d3023 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ide_db::base_db::{FileId, SourceDatabase}; | 1 | use ide_db::base_db::{FileId, SourceDatabase}; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::{ | 3 | use syntax::{ |
4 | algo, AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, | 4 | AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | // Feature: Show Syntax Tree | 7 | // Feature: Show Syntax Tree |
@@ -21,7 +21,7 @@ pub(crate) fn syntax_tree( | |||
21 | ) -> String { | 21 | ) -> String { |
22 | let parse = db.parse(file_id); | 22 | let parse = db.parse(file_id); |
23 | if let Some(text_range) = text_range { | 23 | if let Some(text_range) = text_range { |
24 | let node = match algo::find_covering_element(parse.tree().syntax(), text_range) { | 24 | let node = match parse.tree().syntax().covering_element(text_range) { |
25 | NodeOrToken::Node(node) => node, | 25 | NodeOrToken::Node(node) => node, |
26 | NodeOrToken::Token(token) => { | 26 | NodeOrToken::Token(token) => { |
27 | if let Some(tree) = syntax_tree_for_string(&token, text_range) { | 27 | if let Some(tree) = syntax_tree_for_string(&token, text_range) { |
@@ -85,7 +85,7 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St | |||
85 | .trim_end_matches('"') | 85 | .trim_end_matches('"') |
86 | .trim() | 86 | .trim() |
87 | // Remove custom markers | 87 | // Remove custom markers |
88 | .replace("<|>", ""); | 88 | .replace("$0", ""); |
89 | 89 | ||
90 | let parsed = SourceFile::parse(&text); | 90 | let parsed = SourceFile::parse(&text); |
91 | 91 | ||
@@ -111,7 +111,6 @@ mod tests { | |||
111 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | 111 | let syn = analysis.syntax_tree(file_id, None).unwrap(); |
112 | 112 | ||
113 | assert_eq_text!( | 113 | assert_eq_text!( |
114 | syn.trim(), | ||
115 | r#" | 114 | r#" |
116 | [email protected] | 115 | [email protected] |
117 | [email protected] | 116 | [email protected] |
@@ -127,7 +126,8 @@ [email protected] | |||
127 | [email protected] "{" | 126 | [email protected] "{" |
128 | [email protected] "}" | 127 | [email protected] "}" |
129 | "# | 128 | "# |
130 | .trim() | 129 | .trim(), |
130 | syn.trim() | ||
131 | ); | 131 | ); |
132 | 132 | ||
133 | let (analysis, file_id) = fixture::file( | 133 | let (analysis, file_id) = fixture::file( |
@@ -143,7 +143,6 @@ fn test() { | |||
143 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | 143 | let syn = analysis.syntax_tree(file_id, None).unwrap(); |
144 | 144 | ||
145 | assert_eq_text!( | 145 | assert_eq_text!( |
146 | syn.trim(), | ||
147 | r#" | 146 | r#" |
148 | [email protected] | 147 | [email protected] |
149 | [email protected] | 148 | [email protected] |
@@ -176,17 +175,17 @@ [email protected] | |||
176 | [email protected] "\n" | 175 | [email protected] "\n" |
177 | [email protected] "}" | 176 | [email protected] "}" |
178 | "# | 177 | "# |
179 | .trim() | 178 | .trim(), |
179 | syn.trim() | ||
180 | ); | 180 | ); |
181 | } | 181 | } |
182 | 182 | ||
183 | #[test] | 183 | #[test] |
184 | fn test_syntax_tree_with_range() { | 184 | fn test_syntax_tree_with_range() { |
185 | let (analysis, range) = fixture::range(r#"<|>fn foo() {}<|>"#.trim()); | 185 | let (analysis, range) = fixture::range(r#"$0fn foo() {}$0"#.trim()); |
186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
187 | 187 | ||
188 | assert_eq_text!( | 188 | assert_eq_text!( |
189 | syn.trim(), | ||
190 | r#" | 189 | r#" |
191 | [email protected] | 190 | [email protected] |
192 | [email protected] "fn" | 191 | [email protected] "fn" |
@@ -201,22 +200,22 @@ [email protected] | |||
201 | [email protected] "{" | 200 | [email protected] "{" |
202 | [email protected] "}" | 201 | [email protected] "}" |
203 | "# | 202 | "# |
204 | .trim() | 203 | .trim(), |
204 | syn.trim() | ||
205 | ); | 205 | ); |
206 | 206 | ||
207 | let (analysis, range) = fixture::range( | 207 | let (analysis, range) = fixture::range( |
208 | r#"fn test() { | 208 | r#"fn test() { |
209 | <|>assert!(" | 209 | $0assert!(" |
210 | fn foo() { | 210 | fn foo() { |
211 | } | 211 | } |
212 | ", "");<|> | 212 | ", "");$0 |
213 | }"# | 213 | }"# |
214 | .trim(), | 214 | .trim(), |
215 | ); | 215 | ); |
216 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 216 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
217 | 217 | ||
218 | assert_eq_text!( | 218 | assert_eq_text!( |
219 | syn.trim(), | ||
220 | r#" | 219 | r#" |
221 | [email protected] | 220 | [email protected] |
222 | [email protected] | 221 | [email protected] |
@@ -234,7 +233,8 @@ [email protected] | |||
234 | [email protected] ")" | 233 | [email protected] ")" |
235 | [email protected] ";" | 234 | [email protected] ";" |
236 | "# | 235 | "# |
237 | .trim() | 236 | .trim(), |
237 | syn.trim() | ||
238 | ); | 238 | ); |
239 | } | 239 | } |
240 | 240 | ||
@@ -243,8 +243,8 @@ [email protected] | |||
243 | let (analysis, range) = fixture::range( | 243 | let (analysis, range) = fixture::range( |
244 | r#"fn test() { | 244 | r#"fn test() { |
245 | assert!(" | 245 | assert!(" |
246 | <|>fn foo() { | 246 | $0fn foo() { |
247 | }<|> | 247 | }$0 |
248 | fn bar() { | 248 | fn bar() { |
249 | } | 249 | } |
250 | ", ""); | 250 | ", ""); |
@@ -253,7 +253,6 @@ fn bar() { | |||
253 | ); | 253 | ); |
254 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 254 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
255 | assert_eq_text!( | 255 | assert_eq_text!( |
256 | syn.trim(), | ||
257 | r#" | 256 | r#" |
258 | [email protected] | 257 | [email protected] |
259 | [email protected] | 258 | [email protected] |
@@ -270,15 +269,16 @@ [email protected] | |||
270 | [email protected] "\n" | 269 | [email protected] "\n" |
271 | [email protected] "}" | 270 | [email protected] "}" |
272 | "# | 271 | "# |
273 | .trim() | 272 | .trim(), |
273 | syn.trim() | ||
274 | ); | 274 | ); |
275 | 275 | ||
276 | // With a raw string | 276 | // With a raw string |
277 | let (analysis, range) = fixture::range( | 277 | let (analysis, range) = fixture::range( |
278 | r###"fn test() { | 278 | r###"fn test() { |
279 | assert!(r#" | 279 | assert!(r#" |
280 | <|>fn foo() { | 280 | $0fn foo() { |
281 | }<|> | 281 | }$0 |
282 | fn bar() { | 282 | fn bar() { |
283 | } | 283 | } |
284 | "#, ""); | 284 | "#, ""); |
@@ -287,7 +287,6 @@ fn bar() { | |||
287 | ); | 287 | ); |
288 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 288 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
289 | assert_eq_text!( | 289 | assert_eq_text!( |
290 | syn.trim(), | ||
291 | r#" | 290 | r#" |
292 | [email protected] | 291 | [email protected] |
293 | [email protected] | 292 | [email protected] |
@@ -304,23 +303,23 @@ [email protected] | |||
304 | [email protected] "\n" | 303 | [email protected] "\n" |
305 | [email protected] "}" | 304 | [email protected] "}" |
306 | "# | 305 | "# |
307 | .trim() | 306 | .trim(), |
307 | syn.trim() | ||
308 | ); | 308 | ); |
309 | 309 | ||
310 | // With a raw string | 310 | // With a raw string |
311 | let (analysis, range) = fixture::range( | 311 | let (analysis, range) = fixture::range( |
312 | r###"fn test() { | 312 | r###"fn test() { |
313 | assert!(r<|>#" | 313 | assert!(r$0#" |
314 | fn foo() { | 314 | fn foo() { |
315 | } | 315 | } |
316 | fn bar() { | 316 | fn bar() { |
317 | }"<|>#, ""); | 317 | }"$0#, ""); |
318 | }"### | 318 | }"### |
319 | .trim(), | 319 | .trim(), |
320 | ); | 320 | ); |
321 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 321 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
322 | assert_eq_text!( | 322 | assert_eq_text!( |
323 | syn.trim(), | ||
324 | r#" | 323 | r#" |
325 | [email protected] | 324 | [email protected] |
326 | [email protected] | 325 | [email protected] |
@@ -351,7 +350,8 @@ [email protected] | |||
351 | [email protected] "\n" | 350 | [email protected] "\n" |
352 | [email protected] "}" | 351 | [email protected] "}" |
353 | "# | 352 | "# |
354 | .trim() | 353 | .trim(), |
354 | syn.trim() | ||
355 | ); | 355 | ); |
356 | } | 356 | } |
357 | } | 357 | } |
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 43458a3a2..e3c3aebac 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -15,8 +15,10 @@ | |||
15 | 15 | ||
16 | mod on_enter; | 16 | mod on_enter; |
17 | 17 | ||
18 | use ide_db::base_db::{FilePosition, SourceDatabase}; | 18 | use ide_db::{ |
19 | use ide_db::{source_change::SourceFileEdit, RootDatabase}; | 19 | base_db::{FilePosition, SourceDatabase}, |
20 | RootDatabase, | ||
21 | }; | ||
20 | use syntax::{ | 22 | use syntax::{ |
21 | algo::find_node_at_offset, | 23 | algo::find_node_at_offset, |
22 | ast::{self, edit::IndentLevel, AstToken}, | 24 | ast::{self, edit::IndentLevel, AstToken}, |
@@ -56,7 +58,7 @@ pub(crate) fn on_char_typed( | |||
56 | let file = &db.parse(position.file_id).tree(); | 58 | let file = &db.parse(position.file_id).tree(); |
57 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); | 59 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); |
58 | let edit = on_char_typed_inner(file, position.offset, char_typed)?; | 60 | let edit = on_char_typed_inner(file, position.offset, char_typed)?; |
59 | Some(SourceFileEdit { file_id: position.file_id, edit }.into()) | 61 | Some(SourceChange::from_text_edit(position.file_id, edit)) |
60 | } | 62 | } |
61 | 63 | ||
62 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { | 64 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { |
@@ -170,7 +172,7 @@ mod tests { | |||
170 | fn test_on_eq_typed() { | 172 | fn test_on_eq_typed() { |
171 | // do_check(r" | 173 | // do_check(r" |
172 | // fn foo() { | 174 | // fn foo() { |
173 | // let foo =<|> | 175 | // let foo =$0 |
174 | // } | 176 | // } |
175 | // ", r" | 177 | // ", r" |
176 | // fn foo() { | 178 | // fn foo() { |
@@ -181,7 +183,7 @@ mod tests { | |||
181 | '=', | 183 | '=', |
182 | r" | 184 | r" |
183 | fn foo() { | 185 | fn foo() { |
184 | let foo <|> 1 + 1 | 186 | let foo $0 1 + 1 |
185 | } | 187 | } |
186 | ", | 188 | ", |
187 | r" | 189 | r" |
@@ -192,7 +194,7 @@ fn foo() { | |||
192 | ); | 194 | ); |
193 | // do_check(r" | 195 | // do_check(r" |
194 | // fn foo() { | 196 | // fn foo() { |
195 | // let foo =<|> | 197 | // let foo =$0 |
196 | // let bar = 1; | 198 | // let bar = 1; |
197 | // } | 199 | // } |
198 | // ", r" | 200 | // ", r" |
@@ -210,7 +212,7 @@ fn foo() { | |||
210 | r" | 212 | r" |
211 | fn main() { | 213 | fn main() { |
212 | xs.foo() | 214 | xs.foo() |
213 | <|> | 215 | $0 |
214 | } | 216 | } |
215 | ", | 217 | ", |
216 | r" | 218 | r" |
@@ -225,7 +227,7 @@ fn foo() { | |||
225 | r" | 227 | r" |
226 | fn main() { | 228 | fn main() { |
227 | xs.foo() | 229 | xs.foo() |
228 | <|> | 230 | $0 |
229 | } | 231 | } |
230 | ", | 232 | ", |
231 | ) | 233 | ) |
@@ -238,7 +240,7 @@ fn foo() { | |||
238 | r" | 240 | r" |
239 | fn main() { | 241 | fn main() { |
240 | xs.foo() | 242 | xs.foo() |
241 | <|>; | 243 | $0; |
242 | } | 244 | } |
243 | ", | 245 | ", |
244 | r" | 246 | r" |
@@ -253,7 +255,7 @@ fn foo() { | |||
253 | r" | 255 | r" |
254 | fn main() { | 256 | fn main() { |
255 | xs.foo() | 257 | xs.foo() |
256 | <|>; | 258 | $0; |
257 | } | 259 | } |
258 | ", | 260 | ", |
259 | ) | 261 | ) |
@@ -266,7 +268,7 @@ fn foo() { | |||
266 | r#" | 268 | r#" |
267 | fn main() { | 269 | fn main() { |
268 | let _ = foo | 270 | let _ = foo |
269 | <|> | 271 | $0 |
270 | bar() | 272 | bar() |
271 | } | 273 | } |
272 | "#, | 274 | "#, |
@@ -288,7 +290,7 @@ fn main() { | |||
288 | fn main() { | 290 | fn main() { |
289 | xs.foo() | 291 | xs.foo() |
290 | .first() | 292 | .first() |
291 | <|> | 293 | $0 |
292 | } | 294 | } |
293 | ", | 295 | ", |
294 | r" | 296 | r" |
@@ -305,7 +307,7 @@ fn main() { | |||
305 | fn main() { | 307 | fn main() { |
306 | xs.foo() | 308 | xs.foo() |
307 | .first() | 309 | .first() |
308 | <|> | 310 | $0 |
309 | } | 311 | } |
310 | ", | 312 | ", |
311 | ); | 313 | ); |
@@ -318,7 +320,7 @@ fn main() { | |||
318 | r" | 320 | r" |
319 | fn source_impl() { | 321 | fn source_impl() { |
320 | let var = enum_defvariant_list().unwrap() | 322 | let var = enum_defvariant_list().unwrap() |
321 | <|> | 323 | $0 |
322 | .nth(92) | 324 | .nth(92) |
323 | .unwrap(); | 325 | .unwrap(); |
324 | } | 326 | } |
@@ -337,7 +339,7 @@ fn main() { | |||
337 | r" | 339 | r" |
338 | fn source_impl() { | 340 | fn source_impl() { |
339 | let var = enum_defvariant_list().unwrap() | 341 | let var = enum_defvariant_list().unwrap() |
340 | <|> | 342 | $0 |
341 | .nth(92) | 343 | .nth(92) |
342 | .unwrap(); | 344 | .unwrap(); |
343 | } | 345 | } |
@@ -351,7 +353,7 @@ fn main() { | |||
351 | '.', | 353 | '.', |
352 | r" | 354 | r" |
353 | fn main() { | 355 | fn main() { |
354 | <|> | 356 | $0 |
355 | } | 357 | } |
356 | ", | 358 | ", |
357 | ); | 359 | ); |
@@ -359,7 +361,7 @@ fn main() { | |||
359 | '.', | 361 | '.', |
360 | r" | 362 | r" |
361 | fn main() { | 363 | fn main() { |
362 | <|> | 364 | $0 |
363 | } | 365 | } |
364 | ", | 366 | ", |
365 | ); | 367 | ); |
@@ -367,6 +369,6 @@ fn main() { | |||
367 | 369 | ||
368 | #[test] | 370 | #[test] |
369 | fn adds_space_after_return_type() { | 371 | fn adds_space_after_return_type() { |
370 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -> { 92 }") | 372 | type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") |
371 | } | 373 | } |
372 | } | 374 | } |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index f4ea30352..63cd51b69 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -136,7 +136,7 @@ mod tests { | |||
136 | fn continues_doc_comment() { | 136 | fn continues_doc_comment() { |
137 | do_check( | 137 | do_check( |
138 | r" | 138 | r" |
139 | /// Some docs<|> | 139 | /// Some docs$0 |
140 | fn foo() { | 140 | fn foo() { |
141 | } | 141 | } |
142 | ", | 142 | ", |
@@ -151,7 +151,7 @@ fn foo() { | |||
151 | do_check( | 151 | do_check( |
152 | r" | 152 | r" |
153 | impl S { | 153 | impl S { |
154 | /// Some<|> docs. | 154 | /// Some$0 docs. |
155 | fn foo() {} | 155 | fn foo() {} |
156 | } | 156 | } |
157 | ", | 157 | ", |
@@ -166,7 +166,7 @@ impl S { | |||
166 | 166 | ||
167 | do_check( | 167 | do_check( |
168 | r" | 168 | r" |
169 | ///<|> Some docs | 169 | ///$0 Some docs |
170 | fn foo() { | 170 | fn foo() { |
171 | } | 171 | } |
172 | ", | 172 | ", |
@@ -181,7 +181,7 @@ fn foo() { | |||
181 | 181 | ||
182 | #[test] | 182 | #[test] |
183 | fn does_not_continue_before_doc_comment() { | 183 | fn does_not_continue_before_doc_comment() { |
184 | do_check_noop(r"<|>//! docz"); | 184 | do_check_noop(r"$0//! docz"); |
185 | } | 185 | } |
186 | 186 | ||
187 | #[test] | 187 | #[test] |
@@ -189,7 +189,7 @@ fn foo() { | |||
189 | do_check( | 189 | do_check( |
190 | r" | 190 | r" |
191 | fn main() { | 191 | fn main() { |
192 | // Fix<|> me | 192 | // Fix$0 me |
193 | let x = 1 + 1; | 193 | let x = 1 + 1; |
194 | } | 194 | } |
195 | ", | 195 | ", |
@@ -208,7 +208,7 @@ fn main() { | |||
208 | do_check( | 208 | do_check( |
209 | r" | 209 | r" |
210 | fn main() { | 210 | fn main() { |
211 | // Fix<|> | 211 | // Fix$0 |
212 | // me | 212 | // me |
213 | let x = 1 + 1; | 213 | let x = 1 + 1; |
214 | } | 214 | } |
@@ -229,7 +229,7 @@ fn main() { | |||
229 | do_check_noop( | 229 | do_check_noop( |
230 | r" | 230 | r" |
231 | fn main() { | 231 | fn main() { |
232 | // Fix me<|> | 232 | // Fix me$0 |
233 | let x = 1 + 1; | 233 | let x = 1 + 1; |
234 | } | 234 | } |
235 | ", | 235 | ", |
@@ -242,7 +242,7 @@ fn main() { | |||
242 | do_check( | 242 | do_check( |
243 | r#" | 243 | r#" |
244 | fn main() { | 244 | fn main() { |
245 | // Fix me <|> | 245 | // Fix me $0 |
246 | let x = 1 + 1; | 246 | let x = 1 + 1; |
247 | } | 247 | } |
248 | "#, | 248 | "#, |
@@ -261,7 +261,7 @@ fn main() { | |||
261 | do_check( | 261 | do_check( |
262 | " | 262 | " |
263 | fn main() { | 263 | fn main() { |
264 | // Fix me \t\t <|> | 264 | // Fix me \t\t $0 |
265 | let x = 1 + 1; | 265 | let x = 1 + 1; |
266 | } | 266 | } |
267 | ", | 267 | ", |