aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config3
-rw-r--r--Cargo.lock47
-rw-r--r--crates/assists/src/handlers/auto_import.rs2
-rw-r--r--crates/assists/src/handlers/merge_imports.rs5
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs3
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs131
-rw-r--r--crates/assists/src/handlers/replace_unwrap_with_match.rs2
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs21
-rw-r--r--crates/assists/src/utils.rs6
-rw-r--r--crates/expect/Cargo.toml15
-rw-r--r--crates/expect/src/lib.rs356
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_def/src/body/lower.rs2
-rw-r--r--crates/hir_def/src/import_map.rs2
-rw-r--r--crates/hir_def/src/item_tree/tests.rs2
-rw-r--r--crates/hir_def/src/nameres/tests.rs2
-rw-r--r--crates/hir_ty/Cargo.toml3
-rw-r--r--crates/hir_ty/src/tests.rs2
-rw-r--r--crates/hir_ty/src/tests/coercion.rs2
-rw-r--r--crates/hir_ty/src/tests/macros.rs2
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs2
-rw-r--r--crates/hir_ty/src/tests/never_type.rs2
-rw-r--r--crates/hir_ty/src/tests/patterns.rs2
-rw-r--r--crates/hir_ty/src/tests/regression.rs2
-rw-r--r--crates/hir_ty/src/tests/simple.rs2
-rw-r--r--crates/hir_ty/src/tests/traits.rs2
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/call_info.rs2
-rw-r--r--crates/ide/src/completion/complete_attribute.rs2
-rw-r--r--crates/ide/src/completion/complete_dot.rs2
-rw-r--r--crates/ide/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ide/src/completion/complete_keyword.rs2
-rw-r--r--crates/ide/src/completion/complete_macro_in_item_position.rs2
-rw-r--r--crates/ide/src/completion/complete_pattern.rs2
-rw-r--r--crates/ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ide/src/completion/complete_qualified_path.rs2
-rw-r--r--crates/ide/src/completion/complete_record.rs2
-rw-r--r--crates/ide/src/completion/complete_snippet.rs2
-rw-r--r--crates/ide/src/completion/complete_trait_impl.rs2
-rw-r--r--crates/ide/src/completion/complete_unqualified_path.rs2
-rw-r--r--crates/ide/src/completion/completion_context.rs2
-rw-r--r--crates/ide/src/completion/presentation.rs2
-rw-r--r--crates/ide/src/diagnostics.rs2
-rw-r--r--crates/ide/src/display/navigation_target.rs2
-rw-r--r--crates/ide/src/expand_macro.rs2
-rw-r--r--crates/ide/src/file_structure.rs2
-rw-r--r--crates/ide/src/hover.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/references/rename.rs2
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs2
-rw-r--r--crates/ide_db/src/search.rs63
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs2
-rw-r--r--crates/ssr/Cargo.toml2
-rw-r--r--crates/ssr/src/matching.rs8
-rw-r--r--crates/ssr/src/replacing.rs7
-rw-r--r--crates/ssr/src/tests.rs2
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs3
-rw-r--r--crates/syntax/src/tests.rs2
-rw-r--r--editors/code/src/util.ts1
-rw-r--r--xtask/src/codegen/gen_syntax.rs1
66 files changed, 288 insertions, 486 deletions
diff --git a/.cargo/config b/.cargo/config
index 560ab3075..f6b0b66bf 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -3,3 +3,6 @@ xtask = "run --package xtask --bin xtask --"
3install-ra = "run --package xtask --bin xtask -- install" # for backwards compat 3install-ra = "run --package xtask --bin xtask -- install" # for backwards compat
4tq = "test -- -q" 4tq = "test -- -q"
5qt = "tq" 5qt = "tq"
6
7[target.x86_64-pc-windows-msvc]
8linker = "rust-lld"
diff --git a/Cargo.lock b/Cargo.lock
index 5e0dc061f..46d9469c0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -76,9 +76,9 @@ dependencies = [
76 76
77[[package]] 77[[package]]
78name = "autocfg" 78name = "autocfg"
79version = "1.0.0" 79version = "1.0.1"
80source = "registry+https://github.com/rust-lang/crates.io-index" 80source = "registry+https://github.com/rust-lang/crates.io-index"
81checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 81checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
82 82
83[[package]] 83[[package]]
84name = "backtrace" 84name = "backtrace"
@@ -140,9 +140,9 @@ dependencies = [
140 140
141[[package]] 141[[package]]
142name = "cc" 142name = "cc"
143version = "1.0.58" 143version = "1.0.59"
144source = "registry+https://github.com/rust-lang/crates.io-index" 144source = "registry+https://github.com/rust-lang/crates.io-index"
145checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" 145checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
146 146
147[[package]] 147[[package]]
148name = "cfg" 148name = "cfg"
@@ -345,12 +345,13 @@ dependencies = [
345] 345]
346 346
347[[package]] 347[[package]]
348name = "expect" 348name = "expect-test"
349version = "0.0.0" 349version = "0.1.0"
350source = "registry+https://github.com/rust-lang/crates.io-index"
351checksum = "a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8"
350dependencies = [ 352dependencies = [
351 "difference", 353 "difference",
352 "once_cell", 354 "once_cell",
353 "stdx",
354] 355]
355 356
356[[package]] 357[[package]]
@@ -373,9 +374,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
373 374
374[[package]] 375[[package]]
375name = "flate2" 376name = "flate2"
376version = "1.0.16" 377version = "1.0.17"
377source = "registry+https://github.com/rust-lang/crates.io-index" 378source = "registry+https://github.com/rust-lang/crates.io-index"
378checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" 379checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
379dependencies = [ 380dependencies = [
380 "cfg-if", 381 "cfg-if",
381 "crc32fast", 382 "crc32fast",
@@ -508,7 +509,7 @@ dependencies = [
508 "cfg", 509 "cfg",
509 "drop_bomb", 510 "drop_bomb",
510 "either", 511 "either",
511 "expect", 512 "expect-test",
512 "fst", 513 "fst",
513 "hir_expand", 514 "hir_expand",
514 "indexmap", 515 "indexmap",
@@ -553,7 +554,7 @@ dependencies = [
553 "chalk-recursive", 554 "chalk-recursive",
554 "chalk-solve", 555 "chalk-solve",
555 "ena", 556 "ena",
556 "expect", 557 "expect-test",
557 "hir_def", 558 "hir_def",
558 "hir_expand", 559 "hir_expand",
559 "itertools", 560 "itertools",
@@ -587,7 +588,7 @@ dependencies = [
587 "base_db", 588 "base_db",
588 "cfg", 589 "cfg",
589 "either", 590 "either",
590 "expect", 591 "expect-test",
591 "hir", 592 "hir",
592 "ide_db", 593 "ide_db",
593 "indexmap", 594 "indexmap",
@@ -723,9 +724,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
723 724
724[[package]] 725[[package]]
725name = "libc" 726name = "libc"
726version = "0.2.74" 727version = "0.2.76"
727source = "registry+https://github.com/rust-lang/crates.io-index" 728source = "registry+https://github.com/rust-lang/crates.io-index"
728checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" 729checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
729 730
730[[package]] 731[[package]]
731name = "libloading" 732name = "libloading"
@@ -738,9 +739,9 @@ dependencies = [
738 739
739[[package]] 740[[package]]
740name = "libmimalloc-sys" 741name = "libmimalloc-sys"
741version = "0.1.15" 742version = "0.1.16"
742source = "registry+https://github.com/rust-lang/crates.io-index" 743source = "registry+https://github.com/rust-lang/crates.io-index"
743checksum = "a27252ec1d0c4e0dd6142cbc572da50b363ab56fc334f7aa8fadf295b2e24e74" 744checksum = "677c4be79b14bd72496b87789b702ba02cd1a9f16a59369fe847082fd03efd88"
744dependencies = [ 745dependencies = [
745 "cmake", 746 "cmake",
746] 747]
@@ -844,9 +845,9 @@ dependencies = [
844 845
845[[package]] 846[[package]]
846name = "mimalloc" 847name = "mimalloc"
847version = "0.1.19" 848version = "0.1.20"
848source = "registry+https://github.com/rust-lang/crates.io-index" 849source = "registry+https://github.com/rust-lang/crates.io-index"
849checksum = "6c52de2069999f01bd26436564dbe7de3a87898feeb7a0d0ff9eb20a05bb7ca0" 850checksum = "00759bcf69082fa629ae8823fcc72f7454a90c6476110297a1ae5fb3a559e474"
850dependencies = [ 851dependencies = [
851 "libmimalloc-sys", 852 "libmimalloc-sys",
852] 853]
@@ -1225,7 +1226,7 @@ dependencies = [
1225 "cfg", 1226 "cfg",
1226 "crossbeam-channel", 1227 "crossbeam-channel",
1227 "env_logger", 1228 "env_logger",
1228 "expect", 1229 "expect-test",
1229 "flycheck", 1230 "flycheck",
1230 "hir", 1231 "hir",
1231 "hir_def", 1232 "hir_def",
@@ -1452,7 +1453,7 @@ name = "ssr"
1452version = "0.0.0" 1453version = "0.0.0"
1453dependencies = [ 1454dependencies = [
1454 "base_db", 1455 "base_db",
1455 "expect", 1456 "expect-test",
1456 "hir", 1457 "hir",
1457 "ide_db", 1458 "ide_db",
1458 "itertools", 1459 "itertools",
@@ -1494,7 +1495,7 @@ name = "syntax"
1494version = "0.0.0" 1495version = "0.0.0"
1495dependencies = [ 1496dependencies = [
1496 "arrayvec", 1497 "arrayvec",
1497 "expect", 1498 "expect-test",
1498 "itertools", 1499 "itertools",
1499 "once_cell", 1500 "once_cell",
1500 "parser", 1501 "parser",
@@ -1687,9 +1688,9 @@ dependencies = [
1687 1688
1688[[package]] 1689[[package]]
1689name = "ungrammar" 1690name = "ungrammar"
1690version = "1.1.1" 1691version = "1.1.2"
1691source = "registry+https://github.com/rust-lang/crates.io-index" 1692source = "registry+https://github.com/rust-lang/crates.io-index"
1692checksum = "c4e20e58a08ee1bcf8a4695cf74550cf054d6c489105f594beacb2c684210aad" 1693checksum = "bab6142ac77be714b1ea78faca6efaed5478c50724786b0fe80d8528d10692b3"
1693 1694
1694[[package]] 1695[[package]]
1695name = "unicode-bidi" 1696name = "unicode-bidi"
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index b9ec3f10b..c4770f336 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -239,7 +239,7 @@ impl ImportCandidate {
239 return None; 239 return None;
240 } 240 }
241 Some(Self::TraitMethod( 241 Some(Self::TraitMethod(
242 sema.type_of_expr(&method_call.expr()?)?, 242 sema.type_of_expr(&method_call.receiver()?)?,
243 method_call.name_ref()?.syntax().to_string(), 243 method_call.name_ref()?.syntax().to_string(),
244 )) 244 ))
245 } 245 }
diff --git a/crates/assists/src/handlers/merge_imports.rs b/crates/assists/src/handlers/merge_imports.rs
index 47d465404..35b884206 100644
--- a/crates/assists/src/handlers/merge_imports.rs
+++ b/crates/assists/src/handlers/merge_imports.rs
@@ -8,6 +8,7 @@ use syntax::{
8 8
9use crate::{ 9use crate::{
10 assist_context::{AssistContext, Assists}, 10 assist_context::{AssistContext, Assists},
11 utils::next_prev,
11 AssistId, AssistKind, 12 AssistId, AssistKind,
12}; 13};
13 14
@@ -66,10 +67,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
66 ) 67 )
67} 68}
68 69
69fn next_prev() -> impl Iterator<Item = Direction> {
70 [Direction::Next, Direction::Prev].iter().copied()
71}
72
73fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { 70fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> {
74 let lhs_path = old.path()?; 71 let lhs_path = old.path()?;
75 let rhs_path = new.path()?; 72 let rhs_path = new.path()?;
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs
index f3dcca534..4e252edf0 100644
--- a/crates/assists/src/handlers/remove_dbg.rs
+++ b/crates/assists/src/handlers/remove_dbg.rs
@@ -82,9 +82,10 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
82 82
83#[cfg(test)] 83#[cfg(test)]
84mod tests { 84mod tests {
85 use super::*;
86 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 85 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
87 86
87 use super::*;
88
88 #[test] 89 #[test]
89 fn test_remove_dbg() { 90 fn test_remove_dbg() {
90 check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); 91 check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs
new file mode 100644
index 000000000..5fccca54b
--- /dev/null
+++ b/crates/assists/src/handlers/remove_unused_param.rs
@@ -0,0 +1,131 @@
1use ide_db::{defs::Definition, search::Reference};
2use syntax::{
3 algo::find_node_at_range,
4 ast::{self, ArgListOwner},
5 AstNode, SyntaxNode, TextRange, T,
6};
7use test_utils::mark;
8
9use crate::{
10 assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
11};
12
13// Assist: remove_unused_param
14//
15// Removes unused function parameter.
16//
17// ```
18// fn frobnicate(x: i32<|>) {}
19//
20// fn main() {
21// frobnicate(92);
22// }
23// ```
24// ->
25// ```
26// fn frobnicate() {}
27//
28// fn main() {
29// frobnicate();
30// }
31// ```
32pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let param: ast::Param = ctx.find_node_at_offset()?;
34 let ident_pat = match param.pat()? {
35 ast::Pat::IdentPat(it) => it,
36 _ => return None,
37 };
38 let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
39 let param_position = func.param_list()?.params().position(|it| it == param)?;
40
41 let fn_def = {
42 let func = ctx.sema.to_def(&func)?;
43 Definition::ModuleDef(func.into())
44 };
45
46 let param_def = {
47 let local = ctx.sema.to_def(&ident_pat)?;
48 Definition::Local(local)
49 };
50 if param_def.usages(&ctx.sema).at_least_one() {
51 mark::hit!(keep_used);
52 return None;
53 }
54 acc.add(
55 AssistId("remove_unused_param", AssistKind::Refactor),
56 "Remove unused parameter",
57 param.syntax().text_range(),
58 |builder| {
59 builder.delete(range_with_coma(param.syntax()));
60 for usage in fn_def.usages(&ctx.sema).all() {
61 process_usage(ctx, builder, usage, param_position);
62 }
63 },
64 )
65}
66
67fn process_usage(
68 ctx: &AssistContext,
69 builder: &mut AssistBuilder,
70 usage: Reference,
71 arg_to_remove: usize,
72) -> Option<()> {
73 let source_file = ctx.sema.parse(usage.file_range.file_id);
74 let call_expr: ast::CallExpr =
75 find_node_at_range(source_file.syntax(), usage.file_range.range)?;
76 if call_expr.expr()?.syntax().text_range() != usage.file_range.range {
77 return None;
78 }
79 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
80
81 builder.edit_file(usage.file_range.file_id);
82 builder.delete(range_with_coma(arg.syntax()));
83
84 Some(())
85}
86
87fn range_with_coma(node: &SyntaxNode) -> TextRange {
88 let up_to = next_prev().find_map(|dir| {
89 node.siblings_with_tokens(dir)
90 .filter_map(|it| it.into_token())
91 .find(|it| it.kind() == T![,])
92 });
93 let up_to = up_to.map_or(node.text_range(), |it| it.text_range());
94 node.text_range().cover(up_to)
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::tests::{check_assist, check_assist_not_applicable};
100
101 use super::*;
102
103 #[test]
104 fn remove_unused() {
105 check_assist(
106 remove_unused_param,
107 r#"
108fn a() { foo(9, 2) }
109fn foo(x: i32, <|>y: i32) { x; }
110fn b() { foo(9, 2,) }
111"#,
112 r#"
113fn a() { foo(9) }
114fn foo(x: i32) { x; }
115fn b() { foo(9, ) }
116"#,
117 );
118 }
119
120 #[test]
121 fn keep_used() {
122 mark::check!(keep_used);
123 check_assist_not_applicable(
124 remove_unused_param,
125 r#"
126fn foo(x: i32, <|>y: i32) { y; }
127fn main() { foo(9, 2) }
128"#,
129 );
130 }
131}
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs
index 9705f11b7..4043c219c 100644
--- a/crates/assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs
@@ -42,7 +42,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
42 if name.text() != "unwrap" { 42 if name.text() != "unwrap" {
43 return None; 43 return None;
44 } 44 }
45 let caller = method_call.expr()?; 45 let caller = method_call.receiver()?;
46 let ty = ctx.sema.type_of_expr(&caller)?; 46 let ty = ctx.sema.type_of_expr(&caller)?;
47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); 47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
48 let target = method_call.syntax().text_range(); 48 let target = method_call.syntax().text_range();
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 14834480a..2e0d191a6 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -152,6 +152,7 @@ mod handlers {
152 mod raw_string; 152 mod raw_string;
153 mod remove_dbg; 153 mod remove_dbg;
154 mod remove_mut; 154 mod remove_mut;
155 mod remove_unused_param;
155 mod reorder_fields; 156 mod reorder_fields;
156 mod replace_if_let_with_match; 157 mod replace_if_let_with_match;
157 mod replace_let_with_if_let; 158 mod replace_let_with_if_let;
@@ -198,6 +199,7 @@ mod handlers {
198 raw_string::remove_hash, 199 raw_string::remove_hash,
199 remove_dbg::remove_dbg, 200 remove_dbg::remove_dbg,
200 remove_mut::remove_mut, 201 remove_mut::remove_mut,
202 remove_unused_param::remove_unused_param,
201 reorder_fields::reorder_fields, 203 reorder_fields::reorder_fields,
202 replace_if_let_with_match::replace_if_let_with_match, 204 replace_if_let_with_match::replace_if_let_with_match,
203 replace_let_with_if_let::replace_let_with_if_let, 205 replace_let_with_if_let::replace_let_with_if_let,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 173567003..04c8fd1f9 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -751,6 +751,27 @@ impl Walrus {
751} 751}
752 752
753#[test] 753#[test]
754fn doctest_remove_unused_param() {
755 check_doc_test(
756 "remove_unused_param",
757 r#####"
758fn frobnicate(x: i32<|>) {}
759
760fn main() {
761 frobnicate(92);
762}
763"#####,
764 r#####"
765fn frobnicate() {}
766
767fn main() {
768 frobnicate();
769}
770"#####,
771 )
772}
773
774#[test]
754fn doctest_reorder_fields() { 775fn doctest_reorder_fields() {
755 check_doc_test( 776 check_doc_test(
756 "reorder_fields", 777 "reorder_fields",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 84ccacafe..d071d6502 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -9,7 +9,7 @@ use itertools::Itertools;
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10use syntax::{ 10use syntax::{
11 ast::{self, make, NameOwner}, 11 ast::{self, make, NameOwner},
12 AstNode, 12 AstNode, Direction,
13 SyntaxKind::*, 13 SyntaxKind::*,
14 SyntaxNode, TextSize, T, 14 SyntaxNode, TextSize, T,
15}; 15};
@@ -311,3 +311,7 @@ pub use prelude::*;
311 Some(def) 311 Some(def)
312 } 312 }
313} 313}
314
315pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
316 [Direction::Next, Direction::Prev].iter().copied()
317}
diff --git a/crates/expect/Cargo.toml b/crates/expect/Cargo.toml
deleted file mode 100644
index b54d3a60e..000000000
--- a/crates/expect/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
1[package]
2name = "expect"
3version = "0.0.0"
4license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"]
6edition = "2018"
7
8[lib]
9doctest = false
10
11[dependencies]
12once_cell = "1"
13difference = "2"
14
15stdx = { path = "../stdx" }
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
deleted file mode 100644
index bd83895f7..000000000
--- a/crates/expect/src/lib.rs
+++ /dev/null
@@ -1,356 +0,0 @@
1//! Snapshot testing library, see
2//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
3use std::{
4 collections::HashMap,
5 env, fmt, fs, mem,
6 ops::Range,
7 panic,
8 path::{Path, PathBuf},
9 sync::Mutex,
10};
11
12use difference::Changeset;
13use once_cell::sync::Lazy;
14use stdx::{lines_with_ends, trim_indent};
15
16const HELP: &str = "
17You can update all `expect![[]]` tests by running:
18
19 env UPDATE_EXPECT=1 cargo test
20
21To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
22";
23
24fn update_expect() -> bool {
25 env::var("UPDATE_EXPECT").is_ok()
26}
27
28/// expect![[r#"inline snapshot"#]]
29#[macro_export]
30macro_rules! expect {
31 [[$data:literal]] => {$crate::Expect {
32 position: $crate::Position {
33 file: file!(),
34 line: line!(),
35 column: column!(),
36 },
37 data: $data,
38 }};
39 [[]] => { $crate::expect![[""]] };
40}
41
42/// expect_file!["/crates/foo/test_data/bar.html"]
43#[macro_export]
44macro_rules! expect_file {
45 [$path:expr] => {$crate::ExpectFile {
46 path: std::path::PathBuf::from($path)
47 }};
48}
49
50#[derive(Debug)]
51pub struct Expect {
52 pub position: Position,
53 pub data: &'static str,
54}
55
56#[derive(Debug)]
57pub struct ExpectFile {
58 pub path: PathBuf,
59}
60
61#[derive(Debug)]
62pub struct Position {
63 pub file: &'static str,
64 pub line: u32,
65 pub column: u32,
66}
67
68impl fmt::Display for Position {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{}:{}:{}", self.file, self.line, self.column)
71 }
72}
73
74impl Expect {
75 pub fn assert_eq(&self, actual: &str) {
76 let trimmed = self.trimmed();
77 if trimmed == actual {
78 return;
79 }
80 Runtime::fail_expect(self, &trimmed, actual);
81 }
82 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
83 let actual = format!("{:#?}\n", actual);
84 self.assert_eq(&actual)
85 }
86
87 fn trimmed(&self) -> String {
88 if !self.data.contains('\n') {
89 return self.data.to_string();
90 }
91 trim_indent(self.data)
92 }
93
94 fn locate(&self, file: &str) -> Location {
95 let mut target_line = None;
96 let mut line_start = 0;
97 for (i, line) in lines_with_ends(file).enumerate() {
98 if i == self.position.line as usize - 1 {
99 let pat = "expect![[";
100 let offset = line.find(pat).unwrap();
101 let literal_start = line_start + offset + pat.len();
102 let indent = line.chars().take_while(|&it| it == ' ').count();
103 target_line = Some((literal_start, indent));
104 break;
105 }
106 line_start += line.len();
107 }
108 let (literal_start, line_indent) = target_line.unwrap();
109 let literal_length =
110 file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
111 let literal_range = literal_start..literal_start + literal_length;
112 Location { line_indent, literal_range }
113 }
114}
115
116impl ExpectFile {
117 pub fn assert_eq(&self, actual: &str) {
118 let expected = self.read();
119 if actual == expected {
120 return;
121 }
122 Runtime::fail_file(self, &expected, actual);
123 }
124 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
125 let actual = format!("{:#?}\n", actual);
126 self.assert_eq(&actual)
127 }
128 fn read(&self) -> String {
129 fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
130 }
131 fn write(&self, contents: &str) {
132 fs::write(self.abs_path(), contents).unwrap()
133 }
134 fn abs_path(&self) -> PathBuf {
135 WORKSPACE_ROOT.join(&self.path)
136 }
137}
138
139#[derive(Default)]
140struct Runtime {
141 help_printed: bool,
142 per_file: HashMap<&'static str, FileRuntime>,
143}
144static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);
145
146impl Runtime {
147 fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
148 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
149 if update_expect() {
150 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
151 rt.per_file
152 .entry(expect.position.file)
153 .or_insert_with(|| FileRuntime::new(expect))
154 .update(expect, actual);
155 return;
156 }
157 rt.panic(expect.position.to_string(), expected, actual);
158 }
159
160 fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
161 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
162 if update_expect() {
163 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path.display());
164 expect.write(actual);
165 return;
166 }
167 rt.panic(expect.path.display().to_string(), expected, actual);
168 }
169
170 fn panic(&mut self, position: String, expected: &str, actual: &str) {
171 let print_help = !mem::replace(&mut self.help_printed, true);
172 let help = if print_help { HELP } else { "" };
173
174 let diff = Changeset::new(actual, expected, "\n");
175
176 println!(
177 "\n
178\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m
179 \x1b[1m\x1b[34m-->\x1b[0m {}
180{}
181\x1b[1mExpect\x1b[0m:
182----
183{}
184----
185
186\x1b[1mActual\x1b[0m:
187----
188{}
189----
190
191\x1b[1mDiff\x1b[0m:
192----
193{}
194----
195",
196 position, help, expected, actual, diff
197 );
198 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
199 panic::resume_unwind(Box::new(()));
200 }
201}
202
203struct FileRuntime {
204 path: PathBuf,
205 original_text: String,
206 patchwork: Patchwork,
207}
208
209impl FileRuntime {
210 fn new(expect: &Expect) -> FileRuntime {
211 let path = WORKSPACE_ROOT.join(expect.position.file);
212 let original_text = fs::read_to_string(&path).unwrap();
213 let patchwork = Patchwork::new(original_text.clone());
214 FileRuntime { path, original_text, patchwork }
215 }
216 fn update(&mut self, expect: &Expect, actual: &str) {
217 let loc = expect.locate(&self.original_text);
218 let patch = format_patch(loc.line_indent.clone(), actual);
219 self.patchwork.patch(loc.literal_range, &patch);
220 fs::write(&self.path, &self.patchwork.text).unwrap()
221 }
222}
223
224#[derive(Debug)]
225struct Location {
226 line_indent: usize,
227 literal_range: Range<usize>,
228}
229
230#[derive(Debug)]
231struct Patchwork {
232 text: String,
233 indels: Vec<(Range<usize>, usize)>,
234}
235
236impl Patchwork {
237 fn new(text: String) -> Patchwork {
238 Patchwork { text, indels: Vec::new() }
239 }
240 fn patch(&mut self, mut range: Range<usize>, patch: &str) {
241 self.indels.push((range.clone(), patch.len()));
242 self.indels.sort_by_key(|(delete, _insert)| delete.start);
243
244 let (delete, insert) = self
245 .indels
246 .iter()
247 .take_while(|(delete, _)| delete.start < range.start)
248 .map(|(delete, insert)| (delete.end - delete.start, insert))
249 .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));
250
251 for pos in &mut [&mut range.start, &mut range.end] {
252 **pos -= delete;
253 **pos += insert;
254 }
255
256 self.text.replace_range(range, &patch);
257 }
258}
259
260fn format_patch(line_indent: usize, patch: &str) -> String {
261 let mut max_hashes = 0;
262 let mut cur_hashes = 0;
263 for byte in patch.bytes() {
264 if byte != b'#' {
265 cur_hashes = 0;
266 continue;
267 }
268 cur_hashes += 1;
269 max_hashes = max_hashes.max(cur_hashes);
270 }
271 let hashes = &"#".repeat(max_hashes + 1);
272 let indent = &" ".repeat(line_indent);
273 let is_multiline = patch.contains('\n');
274
275 let mut buf = String::new();
276 buf.push('r');
277 buf.push_str(hashes);
278 buf.push('"');
279 if is_multiline {
280 buf.push('\n');
281 }
282 let mut final_newline = false;
283 for line in lines_with_ends(patch) {
284 if is_multiline && !line.trim().is_empty() {
285 buf.push_str(indent);
286 buf.push_str(" ");
287 }
288 buf.push_str(line);
289 final_newline = line.ends_with('\n');
290 }
291 if final_newline {
292 buf.push_str(indent);
293 }
294 buf.push('"');
295 buf.push_str(hashes);
296 buf
297}
298
299static WORKSPACE_ROOT: Lazy<PathBuf> = Lazy::new(|| {
300 let my_manifest =
301 env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned());
302 // Heuristic, see https://github.com/rust-lang/cargo/issues/3946
303 Path::new(&my_manifest)
304 .ancestors()
305 .filter(|it| it.join("Cargo.toml").exists())
306 .last()
307 .unwrap()
308 .to_path_buf()
309});
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn test_format_patch() {
317 let patch = format_patch(0, "hello\nworld\n");
318 expect![[r##"
319 r#"
320 hello
321 world
322 "#"##]]
323 .assert_eq(&patch);
324
325 let patch = format_patch(4, "single line");
326 expect![[r##"r#"single line"#"##]].assert_eq(&patch);
327 }
328
329 #[test]
330 fn test_patchwork() {
331 let mut patchwork = Patchwork::new("one two three".to_string());
332 patchwork.patch(4..7, "zwei");
333 patchwork.patch(0..3, "один");
334 patchwork.patch(8..13, "3");
335 expect![[r#"
336 Patchwork {
337 text: "один zwei 3",
338 indels: [
339 (
340 0..3,
341 8,
342 ),
343 (
344 4..7,
345 4,
346 ),
347 (
348 8..13,
349 1,
350 ),
351 ],
352 }
353 "#]]
354 .assert_debug_eq(&patchwork);
355 }
356}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 8c5f2ff98..1594d4f0f 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -573,7 +573,7 @@ impl<'db> SemanticsImpl<'db> {
573 573
574 fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool { 574 fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
575 method_call_expr 575 method_call_expr
576 .expr() 576 .receiver()
577 .and_then(|expr| { 577 .and_then(|expr| {
578 let field_expr = match expr { 578 let field_expr = match expr {
579 ast::Expr::FieldExpr(field_expr) => field_expr, 579 ast::Expr::FieldExpr(field_expr) => field_expr,
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 403bc2aff..57745322f 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -32,4 +32,4 @@ cfg = { path = "../cfg" }
32tt = { path = "../tt" } 32tt = { path = "../tt" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35expect = { path = "../expect" } 35expect-test = "0.1"
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index a26251cde..30ac12a12 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -329,7 +329,7 @@ impl ExprCollector<'_> {
329 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) 329 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
330 } 330 }
331 ast::Expr::MethodCallExpr(e) => { 331 ast::Expr::MethodCallExpr(e) => {
332 let receiver = self.collect_expr_opt(e.expr()); 332 let receiver = self.collect_expr_opt(e.receiver());
333 let args = if let Some(arg_list) = e.arg_list() { 333 let args = if let Some(arg_list) = e.arg_list() {
334 arg_list.args().map(|e| self.collect_expr(e)).collect() 334 arg_list.args().map(|e| self.collect_expr(e)).collect()
335 } else { 335 } else {
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index d32a0bdaf..a442fb63a 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -328,7 +328,7 @@ pub fn search_dependencies<'a>(
328#[cfg(test)] 328#[cfg(test)]
329mod tests { 329mod tests {
330 use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; 330 use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
331 use expect::{expect, Expect}; 331 use expect_test::{expect, Expect};
332 332
333 use crate::{test_db::TestDB, AssocContainerId, Lookup}; 333 use crate::{test_db::TestDB, AssocContainerId, Lookup};
334 334
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 9c5bf72bd..620e697d4 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -1,5 +1,5 @@
1use base_db::fixture::WithFixture; 1use base_db::fixture::WithFixture;
2use expect::{expect, Expect}; 2use expect_test::{expect, Expect};
3use hir_expand::{db::AstDatabase, HirFileId, InFile}; 3use hir_expand::{db::AstDatabase, HirFileId, InFile};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use std::sync::Arc; 5use std::sync::Arc;
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index b105d56b2..8aaf7a158 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -7,7 +7,7 @@ mod primitives;
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use base_db::{fixture::WithFixture, SourceDatabase}; 9use base_db::{fixture::WithFixture, SourceDatabase};
10use expect::{expect, Expect}; 10use expect_test::{expect, Expect};
11use test_utils::mark; 11use test_utils::mark;
12 12
13use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index a319b0ce8..06da0d0ec 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -30,8 +30,7 @@ syntax = { path = "../syntax" }
30test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils" }
31 31
32[dev-dependencies] 32[dev-dependencies]
33expect-test = "0.1"
33tracing = "0.1" 34tracing = "0.1"
34tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 35tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
35tracing-tree = { version = "0.1.4" } 36tracing-tree = { version = "0.1.4" }
36
37expect = { path = "../expect" }
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 91c9d38c5..0445efc9e 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -11,7 +11,7 @@ mod display_source_code;
11use std::{env, sync::Arc}; 11use std::{env, sync::Arc};
12 12
13use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 13use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
14use expect::Expect; 14use expect_test::Expect;
15use hir_def::{ 15use hir_def::{
16 body::{BodySourceMap, SyntheticSyntax}, 16 body::{BodySourceMap, SyntheticSyntax},
17 child_by_source::ChildBySource, 17 child_by_source::ChildBySource,
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 17efd75cb..7bc6c79f3 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_infer, check_infer_with_mismatches}; 4use super::{check_infer, check_infer_with_mismatches};
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index d887c7a79..597a195d0 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1,6 +1,6 @@
1use std::fs; 1use std::fs;
2 2
3use expect::expect; 3use expect_test::expect;
4use test_utils::project_dir; 4use test_utils::project_dir;
5 5
6use super::{check_infer, check_types}; 6use super::{check_infer, check_types};
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index fa68355aa..23b2601e6 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_types}; 3use super::{check_infer, check_types};
4 4
diff --git a/crates/hir_ty/src/tests/never_type.rs b/crates/hir_ty/src/tests/never_type.rs
index 49538b572..335c474df 100644
--- a/crates/hir_ty/src/tests/never_type.rs
+++ b/crates/hir_ty/src/tests/never_type.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2 2
3use super::{check_infer_with_mismatches, check_types}; 3use super::{check_infer_with_mismatches, check_types};
4 4
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 39fabf7eb..aeb191c79 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_infer, check_infer_with_mismatches}; 4use super::{check_infer, check_infer_with_mismatches};
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index b9ab0f357..94d86b0d1 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_infer, check_types}; 4use super::{check_infer, check_types};
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 59eb59d5f..48db23a34 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_types}; 3use super::{check_infer, check_types};
4 4
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 526e61caf..1f1056962 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1,4 +1,4 @@
1use expect::expect; 1use expect_test::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_infer, check_infer_with_mismatches, check_types}; 4use super::{check_infer, check_infer_with_mismatches, check_types};
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index e4b970c73..700944430 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -32,4 +32,4 @@ ssr = { path = "../ssr" }
32hir = { path = "../hir" } 32hir = { path = "../hir" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35expect = { path = "../expect" } 35expect-test = "0.1"
diff --git a/crates/ide/src/call_info.rs b/crates/ide/src/call_info.rs
index 86abd2d8c..7e83a2381 100644
--- a/crates/ide/src/call_info.rs
+++ b/crates/ide/src/call_info.rs
@@ -229,7 +229,7 @@ impl FnCallNode {
229 229
230#[cfg(test)] 230#[cfg(test)]
231mod tests { 231mod tests {
232 use expect::{expect, Expect}; 232 use expect_test::{expect, Expect};
233 use test_utils::mark; 233 use test_utils::mark;
234 234
235 use crate::mock_analysis::analysis_and_position; 235 use crate::mock_analysis::analysis_and_position;
diff --git a/crates/ide/src/completion/complete_attribute.rs b/crates/ide/src/completion/complete_attribute.rs
index 042c3ecef..0abfaebcb 100644
--- a/crates/ide/src/completion/complete_attribute.rs
+++ b/crates/ide/src/completion/complete_attribute.rs
@@ -383,7 +383,7 @@ const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
383 383
384#[cfg(test)] 384#[cfg(test)]
385mod tests { 385mod tests {
386 use expect::{expect, Expect}; 386 use expect_test::{expect, Expect};
387 387
388 use crate::completion::{test_utils::completion_list, CompletionKind}; 388 use crate::completion::{test_utils::completion_list, CompletionKind};
389 389
diff --git a/crates/ide/src/completion/complete_dot.rs b/crates/ide/src/completion/complete_dot.rs
index 5488db43f..0b9f1798a 100644
--- a/crates/ide/src/completion/complete_dot.rs
+++ b/crates/ide/src/completion/complete_dot.rs
@@ -61,7 +61,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
61 61
62#[cfg(test)] 62#[cfg(test)]
63mod tests { 63mod tests {
64 use expect::{expect, Expect}; 64 use expect_test::{expect, Expect};
65 use test_utils::mark; 65 use test_utils::mark;
66 66
67 use crate::completion::{test_utils::completion_list, CompletionKind}; 67 use crate::completion::{test_utils::completion_list, CompletionKind};
diff --git a/crates/ide/src/completion/complete_fn_param.rs b/crates/ide/src/completion/complete_fn_param.rs
index 7c63ce58f..9efe25461 100644
--- a/crates/ide/src/completion/complete_fn_param.rs
+++ b/crates/ide/src/completion/complete_fn_param.rs
@@ -66,7 +66,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
66 66
67#[cfg(test)] 67#[cfg(test)]
68mod tests { 68mod tests {
69 use expect::{expect, Expect}; 69 use expect_test::{expect, Expect};
70 70
71 use crate::completion::{test_utils::completion_list, CompletionKind}; 71 use crate::completion::{test_utils::completion_list, CompletionKind};
72 72
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index 22ada3cf2..95e4ff1ac 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -174,7 +174,7 @@ fn complete_return(
174 174
175#[cfg(test)] 175#[cfg(test)]
176mod tests { 176mod tests {
177 use expect::{expect, Expect}; 177 use expect_test::{expect, Expect};
178 178
179 use crate::completion::{ 179 use crate::completion::{
180 test_utils::{check_edit, completion_list}, 180 test_utils::{check_edit, completion_list},
diff --git a/crates/ide/src/completion/complete_macro_in_item_position.rs b/crates/ide/src/completion/complete_macro_in_item_position.rs
index 0447f0511..fc8625d8e 100644
--- a/crates/ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ide/src/completion/complete_macro_in_item_position.rs
@@ -15,7 +15,7 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
15 15
16#[cfg(test)] 16#[cfg(test)]
17mod tests { 17mod tests {
18 use expect::{expect, Expect}; 18 use expect_test::{expect, Expect};
19 19
20 use crate::completion::{test_utils::completion_list, CompletionKind}; 20 use crate::completion::{test_utils::completion_list, CompletionKind};
21 21
diff --git a/crates/ide/src/completion/complete_pattern.rs b/crates/ide/src/completion/complete_pattern.rs
index aceb77cb5..5a13574d4 100644
--- a/crates/ide/src/completion/complete_pattern.rs
+++ b/crates/ide/src/completion/complete_pattern.rs
@@ -33,7 +33,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
33 33
34#[cfg(test)] 34#[cfg(test)]
35mod tests { 35mod tests {
36 use expect::{expect, Expect}; 36 use expect_test::{expect, Expect};
37 37
38 use crate::completion::{test_utils::completion_list, CompletionKind}; 38 use crate::completion::{test_utils::completion_list, CompletionKind};
39 39
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/ide/src/completion/complete_postfix.rs
index d50b13c52..84c4e129d 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/ide/src/completion/complete_postfix.rs
@@ -238,7 +238,7 @@ fn postfix_snippet(
238 238
239#[cfg(test)] 239#[cfg(test)]
240mod tests { 240mod tests {
241 use expect::{expect, Expect}; 241 use expect_test::{expect, Expect};
242 242
243 use crate::completion::{ 243 use crate::completion::{
244 test_utils::{check_edit, completion_list}, 244 test_utils::{check_edit, completion_list},
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/ide/src/completion/complete_qualified_path.rs
index 74794dc88..accb09f7e 100644
--- a/crates/ide/src/completion/complete_qualified_path.rs
+++ b/crates/ide/src/completion/complete_qualified_path.rs
@@ -146,7 +146,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
146 146
147#[cfg(test)] 147#[cfg(test)]
148mod tests { 148mod tests {
149 use expect::{expect, Expect}; 149 use expect_test::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{ 152 use crate::completion::{
diff --git a/crates/ide/src/completion/complete_record.rs b/crates/ide/src/completion/complete_record.rs
index 74b94594d..ceb8d16c1 100644
--- a/crates/ide/src/completion/complete_record.rs
+++ b/crates/ide/src/completion/complete_record.rs
@@ -18,7 +18,7 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 use expect::{expect, Expect}; 21 use expect_test::{expect, Expect};
22 22
23 use crate::completion::{test_utils::completion_list, CompletionKind}; 23 use crate::completion::{test_utils::completion_list, CompletionKind};
24 24
diff --git a/crates/ide/src/completion/complete_snippet.rs b/crates/ide/src/completion/complete_snippet.rs
index 4368e4eec..c3b03b199 100644
--- a/crates/ide/src/completion/complete_snippet.rs
+++ b/crates/ide/src/completion/complete_snippet.rs
@@ -70,7 +70,7 @@ fn ${1:feature}() {
70 70
71#[cfg(test)] 71#[cfg(test)]
72mod tests { 72mod tests {
73 use expect::{expect, Expect}; 73 use expect_test::{expect, Expect};
74 74
75 use crate::completion::{test_utils::completion_list, CompletionKind}; 75 use crate::completion::{test_utils::completion_list, CompletionKind};
76 76
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/ide/src/completion/complete_trait_impl.rs
index d0d3a9f34..1a2b1e8a5 100644
--- a/crates/ide/src/completion/complete_trait_impl.rs
+++ b/crates/ide/src/completion/complete_trait_impl.rs
@@ -225,7 +225,7 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
225 225
226#[cfg(test)] 226#[cfg(test)]
227mod tests { 227mod tests {
228 use expect::{expect, Expect}; 228 use expect_test::{expect, Expect};
229 229
230 use crate::completion::{ 230 use crate::completion::{
231 test_utils::{check_edit, completion_list}, 231 test_utils::{check_edit, completion_list},
diff --git a/crates/ide/src/completion/complete_unqualified_path.rs b/crates/ide/src/completion/complete_unqualified_path.rs
index 824227f31..1f1b682a7 100644
--- a/crates/ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ide/src/completion/complete_unqualified_path.rs
@@ -64,7 +64,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
64 64
65#[cfg(test)] 65#[cfg(test)]
66mod tests { 66mod tests {
67 use expect::{expect, Expect}; 67 use expect_test::{expect, Expect};
68 use test_utils::mark; 68 use test_utils::mark;
69 69
70 use crate::completion::{ 70 use crate::completion::{
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index 85456a66f..5adac7ebc 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -457,7 +457,7 @@ impl<'a> CompletionContext<'a> {
457 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 457 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
458 // As above 458 // As above
459 self.dot_receiver = method_call_expr 459 self.dot_receiver = method_call_expr
460 .expr() 460 .receiver()
461 .map(|e| e.syntax().text_range()) 461 .map(|e| e.syntax().text_range())
462 .and_then(|r| find_node_with_range(original_file, r)); 462 .and_then(|r| find_node_with_range(original_file, r));
463 self.is_call = true; 463 self.is_call = true;
diff --git a/crates/ide/src/completion/presentation.rs b/crates/ide/src/completion/presentation.rs
index a73f8ab0b..3371aed2d 100644
--- a/crates/ide/src/completion/presentation.rs
+++ b/crates/ide/src/completion/presentation.rs
@@ -464,7 +464,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
464mod tests { 464mod tests {
465 use std::cmp::Reverse; 465 use std::cmp::Reverse;
466 466
467 use expect::{expect, Expect}; 467 use expect_test::{expect, Expect};
468 use test_utils::mark; 468 use test_utils::mark;
469 469
470 use crate::{ 470 use crate::{
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 92b5adaa2..b2b972b02 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -214,7 +214,7 @@ fn check_struct_shorthand_initialization(
214 214
215#[cfg(test)] 215#[cfg(test)]
216mod tests { 216mod tests {
217 use expect::{expect, Expect}; 217 use expect_test::{expect, Expect};
218 use stdx::trim_indent; 218 use stdx::trim_indent;
219 use test_utils::assert_eq_text; 219 use test_utils::assert_eq_text;
220 220
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index e77106177..1ee80c2dd 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -421,7 +421,7 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) ->
421 421
422#[cfg(test)] 422#[cfg(test)]
423mod tests { 423mod tests {
424 use expect::expect; 424 use expect_test::expect;
425 425
426 use crate::{mock_analysis::single_file, Query}; 426 use crate::{mock_analysis::single_file, Query};
427 427
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 31455709d..8a285bcf7 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -120,7 +120,7 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
120 120
121#[cfg(test)] 121#[cfg(test)]
122mod tests { 122mod tests {
123 use expect::{expect, Expect}; 123 use expect_test::{expect, Expect};
124 124
125 use crate::mock_analysis::analysis_and_position; 125 use crate::mock_analysis::analysis_and_position;
126 126
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index c90247ba6..6168fb837 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -164,7 +164,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
164 164
165#[cfg(test)] 165#[cfg(test)]
166mod tests { 166mod tests {
167 use expect::{expect, Expect}; 167 use expect_test::{expect, Expect};
168 168
169 use super::*; 169 use super::*;
170 170
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 300c00edc..c75b2a510 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -353,7 +353,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
353#[cfg(test)] 353#[cfg(test)]
354mod tests { 354mod tests {
355 use base_db::FileLoader; 355 use base_db::FileLoader;
356 use expect::{expect, Expect}; 356 use expect_test::{expect, Expect};
357 357
358 use crate::mock_analysis::analysis_and_position; 358 use crate::mock_analysis::analysis_and_position;
359 359
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 596bc872d..583f39d85 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -336,7 +336,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call
336 336
337#[cfg(test)] 337#[cfg(test)]
338mod tests { 338mod tests {
339 use expect::{expect, Expect}; 339 use expect_test::{expect, Expect};
340 use test_utils::extract_annotations; 340 use test_utils::extract_annotations;
341 341
342 use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file}; 342 use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file};
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index d73dc9cd0..301629763 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -270,7 +270,7 @@ fn rename_reference(
270 270
271#[cfg(test)] 271#[cfg(test)]
272mod tests { 272mod tests {
273 use expect::{expect, Expect}; 273 use expect_test::{expect, Expect};
274 use stdx::trim_indent; 274 use stdx::trim_indent;
275 use test_utils::{assert_eq_text, mark}; 275 use test_utils::{assert_eq_text, mark};
276 use text_edit::TextEdit; 276 use text_edit::TextEdit;
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index c3e07c8de..4139f329e 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -268,7 +268,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
268 268
269#[cfg(test)] 269#[cfg(test)]
270mod tests { 270mod tests {
271 use expect::{expect, Expect}; 271 use expect_test::{expect, Expect};
272 272
273 use crate::mock_analysis::analysis_and_position; 273 use crate::mock_analysis::analysis_and_position;
274 274
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index be88b2f9c..25d6f7abd 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -724,7 +724,8 @@ fn highlight_method_call(
724 hir::Access::Shared => (), 724 hir::Access::Shared => (),
725 hir::Access::Exclusive => h |= HighlightModifier::Mutable, 725 hir::Access::Exclusive => h |= HighlightModifier::Mutable,
726 hir::Access::Owned => { 726 hir::Access::Owned => {
727 if let Some(receiver_ty) = method_call.expr().and_then(|it| sema.type_of_expr(&it)) 727 if let Some(receiver_ty) =
728 method_call.receiver().and_then(|it| sema.type_of_expr(&it))
728 { 729 {
729 if !receiver_ty.is_copy(sema.db) { 730 if !receiver_ty.is_copy(sema.db) {
730 h |= HighlightModifier::Consuming 731 h |= HighlightModifier::Consuming
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index ccb76f552..1c3fea058 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,6 @@
1use std::fs; 1use std::fs;
2 2
3use expect::{expect_file, ExpectFile}; 3use expect_test::{expect_file, ExpectFile};
4use test_utils::project_dir; 4use test_utils::project_dir;
5 5
6use crate::{mock_analysis::single_file, FileRange, TextRange}; 6use crate::{mock_analysis::single_file, FileRange, TextRange};
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index ce7631c69..edab1d644 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -203,11 +203,25 @@ impl<'a> FindUsages<'a> {
203 } 203 }
204 204
205 pub fn at_least_one(self) -> bool { 205 pub fn at_least_one(self) -> bool {
206 self.all().is_empty() 206 let mut found = false;
207 self.search(&mut |_reference| {
208 found = true;
209 true
210 });
211 found
207 } 212 }
208 213
209 pub fn all(self) -> Vec<Reference> { 214 pub fn all(self) -> Vec<Reference> {
210 let _p = profile::span("Definition::find_usages"); 215 let mut res = Vec::new();
216 self.search(&mut |reference| {
217 res.push(reference);
218 false
219 });
220 res
221 }
222
223 fn search(self, sink: &mut dyn FnMut(Reference) -> bool) {
224 let _p = profile::span("FindUsages:search");
211 let sema = self.sema; 225 let sema = self.sema;
212 226
213 let search_scope = { 227 let search_scope = {
@@ -219,13 +233,11 @@ impl<'a> FindUsages<'a> {
219 }; 233 };
220 234
221 let name = match self.def.name(sema.db) { 235 let name = match self.def.name(sema.db) {
222 None => return Vec::new(),
223 Some(it) => it.to_string(), 236 Some(it) => it.to_string(),
237 None => return,
224 }; 238 };
225 239
226 let pat = name.as_str(); 240 let pat = name.as_str();
227 let mut refs = vec![];
228
229 for (file_id, search_range) in search_scope { 241 for (file_id, search_range) in search_scope {
230 let text = sema.db.file_text(file_id); 242 let text = sema.db.file_text(file_id);
231 let search_range = 243 let search_range =
@@ -240,10 +252,9 @@ impl<'a> FindUsages<'a> {
240 } 252 }
241 253
242 let name_ref: ast::NameRef = 254 let name_ref: ast::NameRef =
243 if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) { 255 match sema.find_node_at_offset_with_descend(&tree, offset) {
244 name_ref 256 Some(it) => it,
245 } else { 257 None => continue,
246 continue;
247 }; 258 };
248 259
249 match classify_name_ref(&sema, &name_ref) { 260 match classify_name_ref(&sema, &name_ref) {
@@ -256,43 +267,45 @@ impl<'a> FindUsages<'a> {
256 ReferenceKind::Other 267 ReferenceKind::Other
257 }; 268 };
258 269
259 let file_range = sema.original_range(name_ref.syntax()); 270 let reference = Reference {
260 refs.push(Reference { 271 file_range: sema.original_range(name_ref.syntax()),
261 file_range,
262 kind, 272 kind,
263 access: reference_access(&def, &name_ref), 273 access: reference_access(&def, &name_ref),
264 }); 274 };
275 if sink(reference) {
276 return;
277 }
265 } 278 }
266 Some(NameRefClass::FieldShorthand { local, field }) => { 279 Some(NameRefClass::FieldShorthand { local, field }) => {
267 match self.def { 280 let reference = match self.def {
268 Definition::Field(_) if &field == self.def => refs.push(Reference { 281 Definition::Field(_) if &field == self.def => Reference {
269 file_range: self.sema.original_range(name_ref.syntax()), 282 file_range: self.sema.original_range(name_ref.syntax()),
270 kind: ReferenceKind::FieldShorthandForField, 283 kind: ReferenceKind::FieldShorthandForField,
271 access: reference_access(&field, &name_ref), 284 access: reference_access(&field, &name_ref),
272 }), 285 },
273 Definition::Local(l) if &local == l => refs.push(Reference { 286 Definition::Local(l) if &local == l => Reference {
274 file_range: self.sema.original_range(name_ref.syntax()), 287 file_range: self.sema.original_range(name_ref.syntax()),
275 kind: ReferenceKind::FieldShorthandForLocal, 288 kind: ReferenceKind::FieldShorthandForLocal,
276 access: reference_access(&Definition::Local(local), &name_ref), 289 access: reference_access(&Definition::Local(local), &name_ref),
277 }), 290 },
278 291 _ => continue, // not a usage
279 _ => {} // not a usage
280 }; 292 };
293 if sink(reference) {
294 return;
295 }
281 } 296 }
282 _ => {} // not a usage 297 _ => {} // not a usage
283 } 298 }
284 } 299 }
285 } 300 }
286 refs
287 } 301 }
288} 302}
289 303
290fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { 304fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
291 // Only Locals and Fields have accesses for now. 305 // Only Locals and Fields have accesses for now.
292 match def { 306 if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
293 Definition::Local(_) | Definition::Field(_) => {} 307 return None;
294 _ => return None, 308 }
295 };
296 309
297 let mode = name_ref.syntax().ancestors().find_map(|node| { 310 let mode = name_ref.syntax().ancestors().find_map(|node| {
298 match_ast! { 311 match_ast! {
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index c7c1eda0f..068a961dc 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -57,7 +57,7 @@ proc_macro_srv = { path = "../proc_macro_srv" }
57winapi = "0.3.8" 57winapi = "0.3.8"
58 58
59[dev-dependencies] 59[dev-dependencies]
60expect = { path = "../expect" } 60expect-test = "0.1"
61test_utils = { path = "../test_utils" } 61test_utils = { path = "../test_utils" }
62mbe = { path = "../mbe" } 62mbe = { path = "../mbe" }
63tt = { path = "../tt" } 63tt = { path = "../tt" }
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index df5583897..e52b97913 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -256,7 +256,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
256mod tests { 256mod tests {
257 use super::*; 257 use super::*;
258 258
259 use expect::{expect_file, ExpectFile}; 259 use expect_test::{expect_file, ExpectFile};
260 260
261 fn check(diagnostics_json: &str, expect: ExpectFile) { 261 fn check(diagnostics_json: &str, expect: ExpectFile) {
262 check_with_config(DiagnosticsMapConfig::default(), diagnostics_json, expect) 262 check_with_config(DiagnosticsMapConfig::default(), diagnostics_json, expect)
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml
index 7c2090de3..22b6af0fa 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -22,4 +22,4 @@ hir = { path = "../hir" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
23 23
24[dev-dependencies] 24[dev-dependencies]
25expect = { path = "../expect" } 25expect-test = "0.1"
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs
index 26968c474..948862a77 100644
--- a/crates/ssr/src/matching.rs
+++ b/crates/ssr/src/matching.rs
@@ -546,10 +546,12 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
546 // information on the placeholder match about autoderef and autoref. This allows us to use 546 // information on the placeholder match about autoderef and autoref. This allows us to use
547 // the placeholder in a context where autoderef and autoref don't apply. 547 // the placeholder in a context where autoderef and autoref don't apply.
548 if code_resolved_function.self_param(self.sema.db).is_some() { 548 if code_resolved_function.self_param(self.sema.db).is_some() {
549 if let (Some(pattern_type), Some(expr)) = (&pattern_ufcs.qualifier_type, &code.expr()) { 549 if let (Some(pattern_type), Some(expr)) =
550 (&pattern_ufcs.qualifier_type, &code.receiver())
551 {
550 let deref_count = self.check_expr_type(pattern_type, expr)?; 552 let deref_count = self.check_expr_type(pattern_type, expr)?;
551 let pattern_receiver = pattern_args.next(); 553 let pattern_receiver = pattern_args.next();
552 self.attempt_match_opt(phase, pattern_receiver.clone(), code.expr())?; 554 self.attempt_match_opt(phase, pattern_receiver.clone(), code.receiver())?;
553 if let Phase::Second(match_out) = phase { 555 if let Phase::Second(match_out) = phase {
554 if let Some(placeholder_value) = pattern_receiver 556 if let Some(placeholder_value) = pattern_receiver
555 .and_then(|n| self.get_placeholder_for_node(n.syntax())) 557 .and_then(|n| self.get_placeholder_for_node(n.syntax()))
@@ -568,7 +570,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
568 } 570 }
569 } 571 }
570 } else { 572 } else {
571 self.attempt_match_opt(phase, pattern_args.next(), code.expr())?; 573 self.attempt_match_opt(phase, pattern_args.next(), code.receiver())?;
572 } 574 }
573 let mut code_args = 575 let mut code_args =
574 code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args(); 576 code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args();
diff --git a/crates/ssr/src/replacing.rs b/crates/ssr/src/replacing.rs
index 29284e3f1..7e7ce37bd 100644
--- a/crates/ssr/src/replacing.rs
+++ b/crates/ssr/src/replacing.rs
@@ -3,7 +3,7 @@
3use crate::{resolving::ResolvedRule, Match, SsrMatches}; 3use crate::{resolving::ResolvedRule, Match, SsrMatches};
4use itertools::Itertools; 4use itertools::Itertools;
5use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::{FxHashMap, FxHashSet};
6use syntax::ast::{self, AstToken}; 6use syntax::ast::{self, AstNode, AstToken};
7use syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize}; 7use syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize};
8use test_utils::mark; 8use test_utils::mark;
9use text_edit::TextEdit; 9use text_edit::TextEdit;
@@ -93,7 +93,6 @@ impl ReplacementRenderer<'_> {
93 } 93 }
94 94
95 fn render_node(&mut self, node: &SyntaxNode) { 95 fn render_node(&mut self, node: &SyntaxNode) {
96 use syntax::ast::AstNode;
97 if let Some(mod_path) = self.match_info.rendered_template_paths.get(&node) { 96 if let Some(mod_path) = self.match_info.rendered_template_paths.get(&node) {
98 self.out.push_str(&mod_path.to_string()); 97 self.out.push_str(&mod_path.to_string());
99 // Emit everything except for the segment's name-ref, since we already effectively 98 // Emit everything except for the segment's name-ref, since we already effectively
@@ -206,11 +205,10 @@ impl ReplacementRenderer<'_> {
206/// method call doesn't count. e.g. if the token is `$a`, then `$a.foo()` will return true, while 205/// method call doesn't count. e.g. if the token is `$a`, then `$a.foo()` will return true, while
207/// `($a + $b).foo()` or `x.foo($a)` will return false. 206/// `($a + $b).foo()` or `x.foo($a)` will return false.
208fn token_is_method_call_receiver(token: &SyntaxToken) -> bool { 207fn token_is_method_call_receiver(token: &SyntaxToken) -> bool {
209 use syntax::ast::AstNode;
210 // Find the first method call among the ancestors of `token`, then check if the only token 208 // Find the first method call among the ancestors of `token`, then check if the only token
211 // within the receiver is `token`. 209 // within the receiver is `token`.
212 if let Some(receiver) = 210 if let Some(receiver) =
213 token.ancestors().find_map(ast::MethodCallExpr::cast).and_then(|call| call.expr()) 211 token.ancestors().find_map(ast::MethodCallExpr::cast).and_then(|call| call.receiver())
214 { 212 {
215 let tokens = receiver.syntax().descendants_with_tokens().filter_map(|node_or_token| { 213 let tokens = receiver.syntax().descendants_with_tokens().filter_map(|node_or_token| {
216 match node_or_token { 214 match node_or_token {
@@ -226,7 +224,6 @@ fn token_is_method_call_receiver(token: &SyntaxToken) -> bool {
226} 224}
227 225
228fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option<SyntaxNode> { 226fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option<SyntaxNode> {
229 use syntax::ast::AstNode;
230 if ast::Expr::can_cast(kind) { 227 if ast::Expr::can_cast(kind) {
231 if let Ok(expr) = ast::Expr::parse(code) { 228 if let Ok(expr) = ast::Expr::parse(code) {
232 return Some(expr.syntax().clone()); 229 return Some(expr.syntax().clone());
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs
index e45c88864..20231a9bc 100644
--- a/crates/ssr/src/tests.rs
+++ b/crates/ssr/src/tests.rs
@@ -1,6 +1,6 @@
1use crate::{MatchFinder, SsrRule}; 1use crate::{MatchFinder, SsrRule};
2use base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt}; 2use base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
3use expect::{expect, Expect}; 3use expect_test::{expect, Expect};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use std::sync::Arc; 5use std::sync::Arc;
6use test_utils::{mark, RangeOrOffset}; 6use test_utils::{mark, RangeOrOffset};
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index ec3132da8..6818f3ad8 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -30,6 +30,6 @@ parser = { path = "../parser" }
30[dev-dependencies] 30[dev-dependencies]
31walkdir = "2.3.1" 31walkdir = "2.3.1"
32rayon = "1" 32rayon = "1"
33expect-test = "0.1"
33 34
34test_utils = { path = "../test_utils" } 35test_utils = { path = "../test_utils" }
35expect = { path = "../expect" }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 3d49309d1..6317407c6 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -66,6 +66,7 @@ impl ParamList {
66 pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) } 66 pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
67 pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) } 67 pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
68 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 68 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
69 pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
69} 70}
70#[derive(Debug, Clone, PartialEq, Eq, Hash)] 71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub struct RetType { 72pub struct RetType {
@@ -809,7 +810,7 @@ pub struct MethodCallExpr {
809impl ast::AttrsOwner for MethodCallExpr {} 810impl ast::AttrsOwner for MethodCallExpr {}
810impl ast::ArgListOwner for MethodCallExpr {} 811impl ast::ArgListOwner for MethodCallExpr {}
811impl MethodCallExpr { 812impl MethodCallExpr {
812 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 813 pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) }
813 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } 814 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
814 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 815 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
815 pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } 816 pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index ddc718369..8c217dfe0 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -4,7 +4,7 @@ use std::{
4 path::{Path, PathBuf}, 4 path::{Path, PathBuf},
5}; 5};
6 6
7use expect::expect_file; 7use expect_test::expect_file;
8use rayon::prelude::*; 8use rayon::prelude::*;
9use test_utils::project_dir; 9use test_utils::project_dir;
10 10
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 49d2d1c6f..ec2087502 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -25,7 +25,6 @@ export const log = new class {
25 debug(...msg: [unknown, ...unknown[]]): void { 25 debug(...msg: [unknown, ...unknown[]]): void {
26 if (!log.enabled) return; 26 if (!log.enabled) return;
27 log.write("DEBUG", ...msg); 27 log.write("DEBUG", ...msg);
28 log.output.toString();
29 } 28 }
30 29
31 info(...msg: [unknown, ...unknown[]]): void { 30 info(...msg: [unknown, ...unknown[]]): void {
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 53ae9f11c..200e8aa50 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -477,6 +477,7 @@ impl Field {
477 "#" => "pound", 477 "#" => "pound",
478 "?" => "question_mark", 478 "?" => "question_mark",
479 "," => "comma", 479 "," => "comma",
480 "|" => "pipe",
480 _ => name, 481 _ => name,
481 }; 482 };
482 format_ident!("{}_token", name) 483 format_ident!("{}_token", name)