aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/publish.yml44
-rw-r--r--Cargo.lock27
-rw-r--r--crates/arena/Cargo.toml1
-rw-r--r--crates/assists/Cargo.toml17
-rw-r--r--crates/assists/src/handlers/auto_import.rs2
-rw-r--r--crates/assists/src/handlers/invert_if.rs18
-rw-r--r--crates/assists/src/handlers/replace_unwrap_with_match.rs2
-rw-r--r--crates/assists/src/utils.rs21
-rw-r--r--crates/base_db/Cargo.toml15
-rw-r--r--crates/cfg/Cargo.toml3
-rw-r--r--crates/expect/Cargo.toml15
-rw-r--r--crates/expect/src/lib.rs356
-rw-r--r--crates/flycheck/Cargo.toml3
-rw-r--r--crates/hir/Cargo.toml15
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir_def/Cargo.toml23
-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_expand/Cargo.toml17
-rw-r--r--crates/hir_ty/Cargo.toml20
-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.toml25
-rw-r--r--crates/ide/src/call_info.rs2
-rw-r--r--crates/ide/src/completion.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.rs28
-rw-r--r--crates/ide/src/syntax_highlighting.rs9
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs2
-rw-r--r--crates/ide/test_data/highlighting.html4
-rw-r--r--crates/ide_db/Cargo.toml15
-rw-r--r--crates/mbe/Cargo.toml7
-rw-r--r--crates/parser/Cargo.toml1
-rw-r--r--crates/paths/Cargo.toml1
-rw-r--r--crates/proc_macro_api/Cargo.toml3
-rw-r--r--crates/proc_macro_srv/Cargo.toml9
-rw-r--r--crates/proc_macro_test/Cargo.toml1
-rw-r--r--crates/profile/Cargo.toml3
-rw-r--r--crates/project_model/Cargo.toml15
-rw-r--r--crates/rust-analyzer/Cargo.toml3
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs2
-rw-r--r--crates/ssr/Cargo.toml14
-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/stdx/Cargo.toml1
-rw-r--r--crates/syntax/Cargo.toml8
-rw-r--r--crates/syntax/src/algo.rs2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs3
-rw-r--r--crates/syntax/src/ast/make.rs8
-rw-r--r--crates/syntax/src/tests.rs2
-rw-r--r--crates/test_utils/Cargo.toml3
-rw-r--r--crates/text_edit/Cargo.toml1
-rw-r--r--crates/toolchain/Cargo.toml1
-rw-r--r--crates/tt/Cargo.toml3
-rw-r--r--crates/vfs-notify/Cargo.toml5
-rw-r--r--crates/vfs/Cargo.toml3
-rw-r--r--docs/dev/style.md61
-rw-r--r--editors/code/src/util.ts1
-rw-r--r--xtask/src/codegen/gen_syntax.rs1
89 files changed, 376 insertions, 559 deletions
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..be2c7a8ca
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,44 @@
1name: publish
2on:
3 workflow_dispatch: # We can add version input when 1.0 is released and scheduled releases are removed
4
5 schedule:
6 - cron: "0 0 * * *" # midnight UTC
7
8 push:
9 branches:
10 - release
11
12jobs:
13 publish:
14 name: publish
15 runs-on: ubuntu-16.04
16 steps:
17 - name: Checkout repository
18 uses: actions/checkout@v2
19 with:
20 fetch-depth: 0
21
22 - name: Install Rust toolchain
23 uses: actions-rs/toolchain@v1
24 with:
25 toolchain: stable
26 profile: minimal
27 override: true
28
29 - name: Install cargo-workspaces
30 uses: actions-rs/[email protected]
31 with:
32 crate: cargo-workspaces
33
34 - name: Release
35 env:
36 CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
37 PATCH: ${{ github.run_number }}
38 shell: bash
39 run: |
40 git config --global user.email "[email protected]"
41 git config --global user.name "Github Action"
42 rm Cargo.lock
43 cargo workspaces rename ra_ap_%n
44 cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
diff --git a/Cargo.lock b/Cargo.lock
index bc9a989fe..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"
@@ -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]]
@@ -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",
@@ -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/arena/Cargo.toml b/crates/arena/Cargo.toml
index f2bb5cc45..863eedf76 100644
--- a/crates/arena/Cargo.toml
+++ b/crates/arena/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "arena" 2name = "arena"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index a560a35c7..264125651 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "assists" 2name = "assists"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,11 +14,11 @@ rustc-hash = "1.1.0"
13itertools = "0.9.0" 14itertools = "0.9.0"
14either = "1.5.3" 15either = "1.5.3"
15 16
16stdx = { path = "../stdx" } 17stdx = { path = "../stdx", version = "0.0.0" }
17syntax = { path = "../syntax" } 18syntax = { path = "../syntax", version = "0.0.0" }
18text_edit = { path = "../text_edit" } 19text_edit = { path = "../text_edit", version = "0.0.0" }
19profile = { path = "../profile" } 20profile = { path = "../profile", version = "0.0.0" }
20base_db = { path = "../base_db" } 21base_db = { path = "../base_db", version = "0.0.0" }
21ide_db = { path = "../ide_db" } 22ide_db = { path = "../ide_db", version = "0.0.0" }
22hir = { path = "../hir" } 23hir = { path = "../hir", version = "0.0.0" }
23test_utils = { path = "../test_utils" } 24test_utils = { path = "../test_utils", version = "0.0.0" }
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/invert_if.rs b/crates/assists/src/handlers/invert_if.rs
index f0e047538..294256297 100644
--- a/crates/assists/src/handlers/invert_if.rs
+++ b/crates/assists/src/handlers/invert_if.rs
@@ -106,4 +106,22 @@ mod tests {
106 "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }", 106 "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }",
107 ) 107 )
108 } 108 }
109
110 #[test]
111 fn invert_if_option_case() {
112 check_assist(
113 invert_if,
114 "fn f() { if<|> doc_style.is_some() { Class::DocComment } else { Class::Comment } }",
115 "fn f() { if doc_style.is_none() { Class::Comment } else { Class::DocComment } }",
116 )
117 }
118
119 #[test]
120 fn invert_if_result_case() {
121 check_assist(
122 invert_if,
123 "fn f() { i<|>f doc_style.is_err() { Class::Err } else { Class::Ok } }",
124 "fn f() { if doc_style.is_ok() { Class::Ok } else { Class::Err } }",
125 )
126 }
109} 127}
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/utils.rs b/crates/assists/src/utils.rs
index d071d6502..e15c982e7 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -11,7 +11,7 @@ use syntax::{
11 ast::{self, make, NameOwner}, 11 ast::{self, make, NameOwner},
12 AstNode, Direction, 12 AstNode, Direction,
13 SyntaxKind::*, 13 SyntaxKind::*,
14 SyntaxNode, TextSize, T, 14 SyntaxNode, SyntaxText, TextSize, T,
15}; 15};
16 16
17use crate::assist_config::SnippetCap; 17use crate::assist_config::SnippetCap;
@@ -179,6 +179,25 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
179 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), 179 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
180 _ => None, 180 _ => None,
181 }, 181 },
182 ast::Expr::MethodCallExpr(mce) => {
183 const IS_SOME_TEXT: &str = "is_some";
184 const IS_NONE_TEXT: &str = "is_none";
185 const IS_OK_TEXT: &str = "is_ok";
186 const IS_ERR_TEXT: &str = "is_err";
187
188 let name = mce.name_ref()?;
189 let name_text = name.text();
190
191 let caller = || -> Option<SyntaxText> { Some(mce.receiver()?.syntax().text()) };
192
193 match name_text {
194 x if x == IS_SOME_TEXT => make::expr_method_call(IS_NONE_TEXT, caller),
195 x if x == IS_NONE_TEXT => make::expr_method_call(IS_SOME_TEXT, caller),
196 x if x == IS_OK_TEXT => make::expr_method_call(IS_ERR_TEXT, caller),
197 x if x == IS_ERR_TEXT => make::expr_method_call(IS_OK_TEXT, caller),
198 _ => None,
199 }
200 }
182 ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), 201 ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
183 // FIXME: 202 // FIXME:
184 // ast::Expr::Literal(true | false ) 203 // ast::Expr::Literal(true | false )
diff --git a/crates/base_db/Cargo.toml b/crates/base_db/Cargo.toml
index 7347d7528..f7bfcb0d7 100644
--- a/crates/base_db/Cargo.toml
+++ b/crates/base_db/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "base_db" 2name = "base_db"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -12,10 +13,10 @@ doctest = false
12salsa = "0.15.2" 13salsa = "0.15.2"
13rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
14 15
15syntax = { path = "../syntax" } 16syntax = { path = "../syntax", version = "0.0.0" }
16cfg = { path = "../cfg" } 17cfg = { path = "../cfg", version = "0.0.0" }
17profile = { path = "../profile" } 18profile = { path = "../profile", version = "0.0.0" }
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
19test_utils = { path = "../test_utils" } 20test_utils = { path = "../test_utils", version = "0.0.0" }
20vfs = { path = "../vfs" } 21vfs = { path = "../vfs", version = "0.0.0" }
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index d2ea551d1..a6785ee8e 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "cfg" 2name = "cfg"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -11,7 +12,7 @@ doctest = false
11[dependencies] 12[dependencies]
12rustc-hash = "1.1.0" 13rustc-hash = "1.1.0"
13 14
14tt = { path = "../tt" } 15tt = { path = "../tt", version = "0.0.0" }
15 16
16[dev-dependencies] 17[dev-dependencies]
17mbe = { path = "../mbe" } 18mbe = { path = "../mbe" }
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/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 262a66e4e..c230fc1e2 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "flycheck" 2name = "flycheck"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ cargo_metadata = "0.11.1"
15serde_json = "1.0.48" 16serde_json = "1.0.48"
16jod-thread = "0.1.1" 17jod-thread = "0.1.1"
17 18
18toolchain = { path = "../toolchain" } 19toolchain = { path = "../toolchain", version = "0.0.0" }
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index dbb2986b6..60a48170e 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir" 2name = "hir"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,10 +16,10 @@ either = "1.5.3"
15arrayvec = "0.5.1" 16arrayvec = "0.5.1"
16itertools = "0.9.0" 17itertools = "0.9.0"
17 18
18stdx = { path = "../stdx" } 19stdx = { path = "../stdx", version = "0.0.0" }
19syntax = { path = "../syntax" } 20syntax = { path = "../syntax", version = "0.0.0" }
20base_db = { path = "../base_db" } 21base_db = { path = "../base_db", version = "0.0.0" }
21profile = { path = "../profile" } 22profile = { path = "../profile", version = "0.0.0" }
22hir_expand = { path = "../hir_expand" } 23hir_expand = { path = "../hir_expand", version = "0.0.0" }
23hir_def = { path = "../hir_def" } 24hir_def = { path = "../hir_def", version = "0.0.0" }
24hir_ty = { path = "../hir_ty" } 25hir_ty = { path = "../hir_ty", version = "0.0.0" }
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..011e4612c 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_def" 2name = "hir_def"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -20,16 +21,16 @@ itertools = "0.9.0"
20indexmap = "1.4.0" 21indexmap = "1.4.0"
21smallvec = "1.4.0" 22smallvec = "1.4.0"
22 23
23stdx = { path = "../stdx" } 24stdx = { path = "../stdx", version = "0.0.0" }
24arena = { path = "../arena" } 25arena = { path = "../arena", version = "0.0.0" }
25base_db = { path = "../base_db" } 26base_db = { path = "../base_db", version = "0.0.0" }
26syntax = { path = "../syntax" } 27syntax = { path = "../syntax", version = "0.0.0" }
27profile = { path = "../profile" } 28profile = { path = "../profile", version = "0.0.0" }
28hir_expand = { path = "../hir_expand" } 29hir_expand = { path = "../hir_expand", version = "0.0.0" }
29test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils", version = "0.0.0" }
30mbe = { path = "../mbe" } 31mbe = { path = "../mbe", version = "0.0.0" }
31cfg = { path = "../cfg" } 32cfg = { path = "../cfg", version = "0.0.0" }
32tt = { path = "../tt" } 33tt = { path = "../tt", version = "0.0.0" }
33 34
34[dev-dependencies] 35[dev-dependencies]
35expect = { path = "../expect" } 36expect-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_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index 1c4699291..9fad2ab94 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_expand" 2name = "hir_expand"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,11 +14,11 @@ log = "0.4.8"
13either = "1.5.3" 14either = "1.5.3"
14rustc-hash = "1.0.0" 15rustc-hash = "1.0.0"
15 16
16arena = { path = "../arena" } 17arena = { path = "../arena", version = "0.0.0" }
17base_db = { path = "../base_db" } 18base_db = { path = "../base_db", version = "0.0.0" }
18syntax = { path = "../syntax" } 19syntax = { path = "../syntax", version = "0.0.0" }
19parser = { path = "../parser" } 20parser = { path = "../parser", version = "0.0.0" }
20profile = { path = "../profile" } 21profile = { path = "../profile", version = "0.0.0" }
21tt = { path = "../tt" } 22tt = { path = "../tt", version = "0.0.0" }
22mbe = { path = "../mbe" } 23mbe = { path = "../mbe", version = "0.0.0" }
23test_utils = { path = "../test_utils"} 24test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index a319b0ce8..33e155a70 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_ty" 2name = "hir_ty"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -20,18 +21,17 @@ chalk-solve = { version = "0.23.0" }
20chalk-ir = { version = "0.23.0" } 21chalk-ir = { version = "0.23.0" }
21chalk-recursive = { version = "0.23.0" } 22chalk-recursive = { version = "0.23.0" }
22 23
23stdx = { path = "../stdx" } 24stdx = { path = "../stdx", version = "0.0.0" }
24hir_def = { path = "../hir_def" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
25hir_expand = { path = "../hir_expand" } 26hir_expand = { path = "../hir_expand", version = "0.0.0" }
26arena = { path = "../arena" } 27arena = { path = "../arena", version = "0.0.0" }
27base_db = { path = "../base_db" } 28base_db = { path = "../base_db", version = "0.0.0" }
28profile = { path = "../profile" } 29profile = { path = "../profile", version = "0.0.0" }
29syntax = { path = "../syntax" } 30syntax = { path = "../syntax", version = "0.0.0" }
30test_utils = { path = "../test_utils" } 31test_utils = { path = "../test_utils", version = "0.0.0" }
31 32
32[dev-dependencies] 33[dev-dependencies]
34expect-test = "0.1"
33tracing = "0.1" 35tracing = "0.1"
34tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
35tracing-tree = { version = "0.1.4" } 37tracing-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..336e9d2aa 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "ide" 2name = "ide"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,20 +17,20 @@ log = "0.4.8"
16rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
17oorandom = "11.1.2" 18oorandom = "11.1.2"
18 19
19stdx = { path = "../stdx" } 20stdx = { path = "../stdx", version = "0.0.0" }
20syntax = { path = "../syntax" } 21syntax = { path = "../syntax", version = "0.0.0" }
21text_edit = { path = "../text_edit" } 22text_edit = { path = "../text_edit", version = "0.0.0" }
22base_db = { path = "../base_db" } 23base_db = { path = "../base_db", version = "0.0.0" }
23ide_db = { path = "../ide_db" } 24ide_db = { path = "../ide_db", version = "0.0.0" }
24cfg = { path = "../cfg" } 25cfg = { path = "../cfg", version = "0.0.0" }
25profile = { path = "../profile" } 26profile = { path = "../profile", version = "0.0.0" }
26test_utils = { path = "../test_utils" } 27test_utils = { path = "../test_utils", version = "0.0.0" }
27assists = { path = "../assists" } 28assists = { path = "../assists", version = "0.0.0" }
28ssr = { path = "../ssr" } 29ssr = { path = "../ssr", version = "0.0.0" }
29 30
30# ide should depend only on the top-level `hir` package. if you need 31# ide should depend only on the top-level `hir` package. if you need
31# something from some `hir_xxx` subpackage, reexport the API via `hir`. 32# something from some `hir_xxx` subpackage, reexport the API via `hir`.
32hir = { path = "../hir" } 33hir = { path = "../hir", version = "0.0.0" }
33 34
34[dev-dependencies] 35[dev-dependencies]
35expect = { path = "../expect" } 36expect-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.rs b/crates/ide/src/completion.rs
index 25e580d80..33bed6991 100644
--- a/crates/ide/src/completion.rs
+++ b/crates/ide/src/completion.rs
@@ -92,7 +92,7 @@ pub use crate::completion::{
92/// already present, it should give all possible variants for the identifier at 92/// already present, it should give all possible variants for the identifier at
93/// the caret. In other words, for 93/// the caret. In other words, for
94/// 94///
95/// ```no-run 95/// ```no_run
96/// fn f() { 96/// fn f() {
97/// let foo = 92; 97/// let foo = 92;
98/// let _ = bar<|> 98/// let _ = bar<|>
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..dd59d9e70 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -160,7 +160,7 @@ fn runnable_fn(
160 RunnableKind::Test { test_id, attr } 160 RunnableKind::Test { test_id, attr }
161 } else if fn_def.has_atom_attr("bench") { 161 } else if fn_def.has_atom_attr("bench") {
162 RunnableKind::Bench { test_id } 162 RunnableKind::Bench { test_id }
163 } else if has_doc_test(&fn_def) { 163 } else if has_runnable_doc_test(&fn_def) {
164 RunnableKind::DocTest { test_id } 164 RunnableKind::DocTest { test_id }
165 } else { 165 } else {
166 return None; 166 return None;
@@ -211,8 +211,13 @@ fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
211 .any(|attribute_text| attribute_text.contains("test")) 211 .any(|attribute_text| attribute_text.contains("test"))
212} 212}
213 213
214fn has_doc_test(fn_def: &ast::Fn) -> bool { 214fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool {
215 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) 215 fn_def.doc_comment_text().map_or(false, |comments_text| {
216 comments_text.contains("```")
217 && !comments_text.contains("```ignore")
218 && !comments_text.contains("```no_run")
219 && !comments_text.contains("```compile_fail")
220 })
216} 221}
217 222
218fn runnable_mod( 223fn runnable_mod(
@@ -268,7 +273,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
268 273
269#[cfg(test)] 274#[cfg(test)]
270mod tests { 275mod tests {
271 use expect::{expect, Expect}; 276 use expect_test::{expect, Expect};
272 277
273 use crate::mock_analysis::analysis_and_position; 278 use crate::mock_analysis::analysis_and_position;
274 279
@@ -417,6 +422,21 @@ fn main() {}
417/// let x = 5; 422/// let x = 5;
418/// ``` 423/// ```
419fn foo() {} 424fn foo() {}
425
426/// ```no_run
427/// let z = 55;
428/// ```
429fn should_have_no_runnable() {}
430
431/// ```ignore
432/// let z = 55;
433/// ```
434fn should_have_no_runnable_2() {}
435
436/// ```compile_fail
437/// let z = 55;
438/// ```
439fn should_have_no_runnable_3() {}
420"#, 440"#,
421 &[&BIN, &DOCTEST], 441 &[&BIN, &DOCTEST],
422 expect![[r#" 442 expect![[r#"
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index dd8cfe42d..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
@@ -747,12 +748,6 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
747 if func.is_unsafe(db) { 748 if func.is_unsafe(db) {
748 h |= HighlightModifier::Unsafe; 749 h |= HighlightModifier::Unsafe;
749 } 750 }
750 if let Some(self_param) = func.self_param(db) {
751 match self_param.access(db) {
752 hir::Access::Exclusive => h |= HighlightModifier::Mutable,
753 hir::Access::Shared | hir::Access::Owned => (),
754 }
755 }
756 return h; 751 return h;
757 } 752 }
758 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, 753 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
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/test_data/highlighting.html b/crates/ide/test_data/highlighting.html
index a6b79589b..d0df2e0ec 100644
--- a/crates/ide/test_data/highlighting.html
+++ b/crates/ide/test_data/highlighting.html
@@ -65,7 +65,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
65 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span> 65 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
66 <span class="punctuation">}</span> 66 <span class="punctuation">}</span>
67 67
68 <span class="keyword">fn</span> <span class="function declaration mutable">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> 68 <span class="keyword">fn</span> <span class="function declaration">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>
69 <span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 69 <span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
70 <span class="punctuation">}</span> 70 <span class="punctuation">}</span>
71 71
@@ -84,7 +84,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
84 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span> 84 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
85 <span class="punctuation">}</span> 85 <span class="punctuation">}</span>
86 86
87 <span class="keyword">fn</span> <span class="function declaration mutable">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> 87 <span class="keyword">fn</span> <span class="function declaration">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>
88 <span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 88 <span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
89 <span class="punctuation">}</span> 89 <span class="punctuation">}</span>
90 90
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 692fb6415..320fb15e5 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "ide_db" 2name = "ide_db"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -19,12 +20,12 @@ rustc-hash = "1.1.0"
19once_cell = "1.3.1" 20once_cell = "1.3.1"
20either = "1.5.3" 21either = "1.5.3"
21 22
22stdx = { path = "../stdx" } 23stdx = { path = "../stdx", version = "0.0.0" }
23syntax = { path = "../syntax" } 24syntax = { path = "../syntax", version = "0.0.0" }
24text_edit = { path = "../text_edit" } 25text_edit = { path = "../text_edit", version = "0.0.0" }
25base_db = { path = "../base_db" } 26base_db = { path = "../base_db", version = "0.0.0" }
26profile = { path = "../profile" } 27profile = { path = "../profile", version = "0.0.0" }
27test_utils = { path = "../test_utils" } 28test_utils = { path = "../test_utils", version = "0.0.0" }
28# ide should depend only on the top-level `hir` package. if you need 29# ide should depend only on the top-level `hir` package. if you need
29# something from some `hir_xxx` subpackage, reexport the API via `hir`. 30# something from some `hir_xxx` subpackage, reexport the API via `hir`.
30hir = { path = "../hir" } 31hir = { path = "../hir", version = "0.0.0" }
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 1aba8b7c4..af80e2be3 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "mbe" 2name = "mbe"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,9 +14,9 @@ rustc-hash = "1.1.0"
13smallvec = "1.2.0" 14smallvec = "1.2.0"
14log = "0.4.8" 15log = "0.4.8"
15 16
16syntax = { path = "../syntax" } 17syntax = { path = "../syntax", version = "0.0.0" }
17parser = { path = "../parser" } 18parser = { path = "../parser", version = "0.0.0" }
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
19 20
20[dev-dependencies] 21[dev-dependencies]
21test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 358be92d1..1610e0d23 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "parser" 2name = "parser"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml
index 5ac18d63b..da26938c1 100644
--- a/crates/paths/Cargo.toml
+++ b/crates/paths/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "paths" 2name = "paths"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index a3a4c1103..75f67a22e 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "proc_macro_api" 2name = "proc_macro_api"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ log = "0.4.8"
15crossbeam-channel = "0.4.0" 16crossbeam-channel = "0.4.0"
16jod-thread = "0.1.1" 17jod-thread = "0.1.1"
17 18
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml
index a468b5560..fb84e04ae 100644
--- a/crates/proc_macro_srv/Cargo.toml
+++ b/crates/proc_macro_srv/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "proc_macro_srv" 2name = "proc_macro_srv"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,10 +14,10 @@ goblin = "0.2.1"
13libloading = "0.6.0" 14libloading = "0.6.0"
14memmap = "0.7" 15memmap = "0.7"
15 16
16tt = { path = "../tt" } 17tt = { path = "../tt", version = "0.0.0" }
17mbe = { path = "../mbe" } 18mbe = { path = "../mbe", version = "0.0.0" }
18proc_macro_api = { path = "../proc_macro_api" } 19proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
19test_utils = { path = "../test_utils" } 20test_utils = { path = "../test_utils", version = "0.0.0" }
20 21
21[dev-dependencies] 22[dev-dependencies]
22cargo_metadata = "0.11.1" 23cargo_metadata = "0.11.1"
diff --git a/crates/proc_macro_test/Cargo.toml b/crates/proc_macro_test/Cargo.toml
index 7b0f64f31..753443be2 100644
--- a/crates/proc_macro_test/Cargo.toml
+++ b/crates/proc_macro_test/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.0"
4license = "MIT OR Apache-2.0" 4license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6edition = "2018" 6edition = "2018"
7publish = false
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml
index e271e3a56..261172d61 100644
--- a/crates/profile/Cargo.toml
+++ b/crates/profile/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "profile" 2name = "profile"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -14,7 +15,7 @@ cfg-if = "0.1.10"
14libc = "0.2.73" 15libc = "0.2.73"
15backtrace = { version = "0.3.44", optional = true } 16backtrace = { version = "0.3.44", optional = true }
16 17
17arena = { path = "../arena" } 18arena = { path = "../arena", version = "0.0.0" }
18 19
19[target.'cfg(target_os = "linux")'.dependencies] 20[target.'cfg(target_os = "linux")'.dependencies]
20perf-event = "0.4" 21perf-event = "0.4"
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml
index 386f72f41..8bee398d9 100644
--- a/crates/project_model/Cargo.toml
+++ b/crates/project_model/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "project_model" 2name = "project_model"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,10 +17,10 @@ serde = { version = "1.0.106", features = ["derive"] }
16serde_json = "1.0.48" 17serde_json = "1.0.48"
17anyhow = "1.0.26" 18anyhow = "1.0.26"
18 19
19arena = { path = "../arena" } 20arena = { path = "../arena", version = "0.0.0" }
20cfg = { path = "../cfg" } 21cfg = { path = "../cfg", version = "0.0.0" }
21base_db = { path = "../base_db" } 22base_db = { path = "../base_db", version = "0.0.0" }
22toolchain = { path = "../toolchain" } 23toolchain = { path = "../toolchain", version = "0.0.0" }
23proc_macro_api = { path = "../proc_macro_api" } 24proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
24paths = { path = "../paths" } 25paths = { path = "../paths", version = "0.0.0" }
25stdx = { path = "../stdx" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index c7c1eda0f..7e280b1f7 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -5,6 +5,7 @@ license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6autobins = false 6autobins = false
7edition = "2018" 7edition = "2018"
8publish = false
8 9
9[lib] 10[lib]
10doctest = false 11doctest = false
@@ -57,7 +58,7 @@ proc_macro_srv = { path = "../proc_macro_srv" }
57winapi = "0.3.8" 58winapi = "0.3.8"
58 59
59[dev-dependencies] 60[dev-dependencies]
60expect = { path = "../expect" } 61expect-test = "0.1"
61test_utils = { path = "../test_utils" } 62test_utils = { path = "../test_utils" }
62mbe = { path = "../mbe" } 63mbe = { path = "../mbe" }
63tt = { path = "../tt" } 64tt = { 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..6f0f53d70 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -14,12 +14,12 @@ doctest = false
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15itertools = "0.9.0" 15itertools = "0.9.0"
16 16
17text_edit = { path = "../text_edit" } 17text_edit = { path = "../text_edit", version = "0.0.0" }
18syntax = { path = "../syntax" } 18syntax = { path = "../syntax", version = "0.0.0" }
19base_db = { path = "../base_db" } 19base_db = { path = "../base_db", version = "0.0.0" }
20ide_db = { path = "../ide_db" } 20ide_db = { path = "../ide_db", version = "0.0.0" }
21hir = { path = "../hir" } 21hir = { path = "../hir", version = "0.0.0" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils", version = "0.0.0" }
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/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index b186b46f2..8d7a51156 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "stdx" 2name = "stdx"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index ec3132da8..2c1bdb295 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -23,13 +23,13 @@ once_cell = "1.3.1"
23smol_str = { version = "0.1.15", features = ["serde"] } 23smol_str = { version = "0.1.15", features = ["serde"] }
24serde = { version = "1.0.106", features = ["derive"] } 24serde = { version = "1.0.106", features = ["derive"] }
25 25
26stdx = { path = "../stdx" } 26stdx = { path = "../stdx", version = "0.0.0" }
27text_edit = { path = "../text_edit" } 27text_edit = { path = "../text_edit", version = "0.0.0" }
28parser = { path = "../parser" } 28parser = { path = "../parser", version = "0.0.0" }
29 29
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/algo.rs b/crates/syntax/src/algo.rs
index 6254b38ba..ea199f9b8 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -32,7 +32,7 @@ pub fn ancestors_at_offset(
32/// imprecise: if the cursor is strictly between two nodes of the desired type, 32/// imprecise: if the cursor is strictly between two nodes of the desired type,
33/// as in 33/// as in
34/// 34///
35/// ```no-run 35/// ```no_run
36/// struct Foo {}|struct Bar; 36/// struct Foo {}|struct Bar;
37/// ``` 37/// ```
38/// 38///
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/ast/make.rs b/crates/syntax/src/ast/make.rs
index d20c085aa..7958721e2 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -7,7 +7,7 @@
7use itertools::Itertools; 7use itertools::Itertools;
8use stdx::format_to; 8use stdx::format_to;
9 9
10use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; 10use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxText, SyntaxToken};
11 11
12pub fn name(text: &str) -> ast::Name { 12pub fn name(text: &str) -> ast::Name {
13 ast_from_text(&format!("mod {};", text)) 13 ast_from_text(&format!("mod {};", text))
@@ -137,6 +137,12 @@ pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
137pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { 137pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
138 expr_from_text(&format!("{}{}", f, arg_list)) 138 expr_from_text(&format!("{}{}", f, arg_list))
139} 139}
140pub fn expr_method_call<F>(text: &str, caller: F) -> Option<ast::Expr>
141where
142 F: FnOnce() -> Option<SyntaxText>,
143{
144 try_expr_from_text(&format!("{}.{}()", caller()?, text))
145}
140fn expr_from_text(text: &str) -> ast::Expr { 146fn expr_from_text(text: &str) -> ast::Expr {
141 ast_from_text(&format!("const C: () = {};", text)) 147 ast_from_text(&format!("const C: () = {};", text))
142} 148}
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/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 45e5fb97f..93eecc678 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "test_utils" 2name = "test_utils"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ text-size = "1.0.0"
15serde_json = "1.0.48" 16serde_json = "1.0.48"
16rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
17 18
18stdx = { path = "../stdx" } 19stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/text_edit/Cargo.toml b/crates/text_edit/Cargo.toml
index a69b1ef2b..8aadc1875 100644
--- a/crates/text_edit/Cargo.toml
+++ b/crates/text_edit/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "text_edit" 2name = "text_edit"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/toolchain/Cargo.toml b/crates/toolchain/Cargo.toml
index 4856668f8..dcf0bfca0 100644
--- a/crates/toolchain/Cargo.toml
+++ b/crates/toolchain/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "toolchain" 2name = "toolchain"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml
index dfcdcf03e..5b8972ea3 100644
--- a/crates/tt/Cargo.toml
+++ b/crates/tt/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "tt" 2name = "tt"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,4 +14,4 @@ doctest = false
13# to reduce number of compilations 14# to reduce number of compilations
14smol_str = { version = "0.1.15", features = ["serde"] } 15smol_str = { version = "0.1.15", features = ["serde"] }
15 16
16stdx = { path = "../stdx" } 17stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml
index c1e53f4b1..54b51faab 100644
--- a/crates/vfs-notify/Cargo.toml
+++ b/crates/vfs-notify/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "vfs-notify" 2name = "vfs-notify"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,5 +17,5 @@ walkdir = "2.3.1"
16crossbeam-channel = "0.4.0" 17crossbeam-channel = "0.4.0"
17notify = "5.0.0-pre.3" 18notify = "5.0.0-pre.3"
18 19
19vfs = { path = "../vfs" } 20vfs = { path = "../vfs", version = "0.0.0" }
20paths = { path = "../paths" } 21paths = { path = "../paths", version = "0.0.0" }
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index 9ae8f19b6..c318a68f7 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "vfs" 2name = "vfs"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -12,4 +13,4 @@ doctest = false
12rustc-hash = "1.0" 13rustc-hash = "1.0"
13fst = "0.4" 14fst = "0.4"
14 15
15paths = { path = "../paths" } 16paths = { path = "../paths", version = "0.0.0" }
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 44f0956c2..bb99c4855 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -181,6 +181,30 @@ fn frobnicate(walrus: Option<Walrus>) {
181} 181}
182``` 182```
183 183
184# Early Returns
185
186Do use early returns
187
188```rust
189// Good
190fn foo() -> Option<Bar> {
191 if !condition() {
192 return None;
193 }
194
195 Some(...)
196}
197
198// Not as good
199fn foo() -> Option<Bar> {
200 if condition() {
201 Some(...)
202 } else {
203 None
204 }
205}
206```
207
184# Getters & Setters 208# Getters & Setters
185 209
186If a field can have any value without breaking invariants, make the field public. 210If a field can have any value without breaking invariants, make the field public.
@@ -189,7 +213,7 @@ Never provide setters.
189 213
190Getters should return borrowed data: 214Getters should return borrowed data:
191 215
192``` 216```rust
193struct Person { 217struct Person {
194 // Invariant: never empty 218 // Invariant: never empty
195 first_name: String, 219 first_name: String,
@@ -231,6 +255,41 @@ if words.len() != 2 {
231} 255}
232``` 256```
233 257
258# Avoid Monomorphization
259
260Rust uses monomorphization to compile generic code, meaning that for each instantiation of a generic functions with concrete types, the function is compiled afresh, *per crate*.
261This allows for exceptionally good performance, but leads to increased compile times.
262Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot.
263Compile time **does not** obey this rule -- all code has to be compiled.
264For this reason, avoid making a lot of code type parametric, *especially* on the boundaries between crates.
265
266```rust
267// Good
268fn frbonicate(f: impl FnMut()) {
269 frobnicate_impl(&mut f)
270}
271fn frobnicate_impl(f: &mut dyn FnMut()) {
272 // lots of code
273}
274
275// Not as good
276fn frbonicate(f: impl FnMut()) {
277 // lots of code
278}
279```
280
281Avoid `AsRef` polymorphism, it pays back only for widely used libraries:
282
283```rust
284// Good
285fn frbonicate(f: &Path) {
286}
287
288// Not as good
289fn frbonicate(f: impl AsRef<Path>) {
290}
291```
292
234# Documentation 293# Documentation
235 294
236For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. 295For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines.
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)