aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml24
-rw-r--r--.github/workflows/release.yaml12
-rw-r--r--.github/workflows/rustdoc.yaml9
-rw-r--r--Cargo.lock29
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs24
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs4
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs177
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_db/Cargo.toml1
-rw-r--r--crates/ra_db/src/fixture.rs8
-rw-r--r--crates/ra_db/src/input.rs32
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs16
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs11
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs16
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs2
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs29
-rw-r--r--crates/ra_hir_ty/src/db.rs1
-rw-r--r--crates/ra_ide/src/lib.rs1
-rw-r--r--crates/ra_ide/src/mock_analysis.rs2
-rw-r--r--crates/ra_ide/src/parent_module.rs1
-rw-r--r--crates/ra_ide_db/src/change.rs12
-rw-r--r--crates/ra_mbe/src/lib.rs7
-rw-r--r--crates/ra_proc_macro/Cargo.toml12
-rw-r--r--crates/ra_proc_macro/src/lib.rs59
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs31
-rw-r--r--crates/ra_project_model/src/json_project.rs1
-rw-r--r--crates/ra_project_model/src/lib.rs41
-rw-r--r--crates/ra_syntax/src/ast/generated.rs10
-rw-r--r--crates/ra_syntax/src/ast/make.rs4
-rw-r--r--crates/ra_syntax/src/ast/traits.rs31
-rw-r--r--crates/ra_tt/src/lib.rs15
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs19
-rw-r--r--crates/rust-analyzer/src/world.rs14
-rw-r--r--docs/user/assists.md23
-rw-r--r--editors/code/src/commands/analyzer_status.ts31
-rw-r--r--xtask/src/ast_src.rs1
41 files changed, 578 insertions, 154 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 58c8f083a..5050c558c 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -7,14 +7,17 @@ on:
7 - staging 7 - staging
8 - trying 8 - trying
9 9
10env:
11 CARGO_INCREMENTAL: 0
12 CARGO_NET_RETRY: 10
13 RUN_SLOW_TESTS: 1
14 RUSTFLAGS: -D warnings
15 RUSTUP_MAX_RETRIES: 10
16
10jobs: 17jobs:
11 rust-audit: 18 rust-audit:
12 name: Audit Rust vulnerabilities 19 name: Audit Rust vulnerabilities
13 runs-on: ubuntu-latest 20 runs-on: ubuntu-latest
14 env:
15 RUSTUP_MAX_RETRIES: 10
16 CARGO_NET_RETRY: 10
17
18 steps: 21 steps:
19 - name: Install Rust toolchain 22 - name: Install Rust toolchain
20 uses: actions-rs/toolchain@v1 23 uses: actions-rs/toolchain@v1
@@ -40,20 +43,14 @@ jobs:
40 rust: 43 rust:
41 name: Rust 44 name: Rust
42 runs-on: ${{ matrix.os }} 45 runs-on: ${{ matrix.os }}
46 env:
47 CC: deny_c
43 48
44 strategy: 49 strategy:
45 fail-fast: false 50 fail-fast: false
46 matrix: 51 matrix:
47 os: [ubuntu-latest, windows-latest, macos-latest] 52 os: [ubuntu-latest, windows-latest, macos-latest]
48 53
49 env:
50 RUSTFLAGS: -D warnings
51 CC: deny_c
52 CARGO_INCREMENTAL: 0
53 RUN_SLOW_TESTS: 1
54 RUSTUP_MAX_RETRIES: 10
55 CARGO_NET_RETRY: 10
56
57 steps: 54 steps:
58 - name: Checkout repository 55 - name: Checkout repository
59 uses: actions/checkout@v2 56 uses: actions/checkout@v2
@@ -111,9 +108,6 @@ jobs:
111 typescript: 108 typescript:
112 name: TypeScript 109 name: TypeScript
113 runs-on: ubuntu-latest 110 runs-on: ubuntu-latest
114 env:
115 CXX: g++-4.9
116 CC: gcc-4.9
117 steps: 111 steps:
118 - name: Checkout repository 112 - name: Checkout repository
119 uses: actions/checkout@v2 113 uses: actions/checkout@v2
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index c055d113d..fd184e8f1 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -8,6 +8,12 @@ on:
8 - release 8 - release
9 - nightly 9 - nightly
10 10
11env:
12 CARGO_INCREMENTAL: 0
13 CARGO_NET_RETRY: 10
14 RUSTFLAGS: -D warnings
15 RUSTUP_MAX_RETRIES: 10
16
11jobs: 17jobs:
12 dist: 18 dist:
13 name: dist 19 name: dist
@@ -16,12 +22,6 @@ jobs:
16 matrix: 22 matrix:
17 os: [ubuntu-latest, windows-latest, macos-latest] 23 os: [ubuntu-latest, windows-latest, macos-latest]
18 24
19 env:
20 RUSTFLAGS: -D warnings
21 CARGO_INCREMENTAL: 0
22 RUSTUP_MAX_RETRIES: 10
23 CARGO_NET_RETRY: 10
24
25 steps: 25 steps:
26 - name: Checkout repository 26 - name: Checkout repository
27 uses: actions/checkout@v2 27 uses: actions/checkout@v2
diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml
index c84ce5d48..cf4bca840 100644
--- a/.github/workflows/rustdoc.yaml
+++ b/.github/workflows/rustdoc.yaml
@@ -4,12 +4,15 @@ on:
4 branches: 4 branches:
5 - master 5 - master
6 6
7env:
8 CARGO_INCREMENTAL: 0
9 CARGO_NET_RETRY: 10
10 RUSTFLAGS: -D warnings
11 RUSTUP_MAX_RETRIES: 10
12
7jobs: 13jobs:
8 rustdoc: 14 rustdoc:
9 runs-on: ubuntu-latest 15 runs-on: ubuntu-latest
10 env:
11 RUSTFLAGS: -D warnings
12 CARGO_INCREMENTAL: 0
13 16
14 steps: 17 steps:
15 - name: Checkout repository 18 - name: Checkout repository
diff --git a/Cargo.lock b/Cargo.lock
index 908319f87..3bb1df05b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -46,9 +46,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
46 46
47[[package]] 47[[package]]
48name = "backtrace" 48name = "backtrace"
49version = "0.3.45" 49version = "0.3.46"
50source = "registry+https://github.com/rust-lang/crates.io-index" 50source = "registry+https://github.com/rust-lang/crates.io-index"
51checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" 51checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
52dependencies = [ 52dependencies = [
53 "backtrace-sys", 53 "backtrace-sys",
54 "cfg-if", 54 "cfg-if",
@@ -58,9 +58,9 @@ dependencies = [
58 58
59[[package]] 59[[package]]
60name = "backtrace-sys" 60name = "backtrace-sys"
61version = "0.1.34" 61version = "0.1.35"
62source = "registry+https://github.com/rust-lang/crates.io-index" 62source = "registry+https://github.com/rust-lang/crates.io-index"
63checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" 63checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
64dependencies = [ 64dependencies = [
65 "cc", 65 "cc",
66 "libc", 66 "libc",
@@ -804,9 +804,9 @@ dependencies = [
804 804
805[[package]] 805[[package]]
806name = "paste" 806name = "paste"
807version = "0.1.7" 807version = "0.1.8"
808source = "registry+https://github.com/rust-lang/crates.io-index" 808source = "registry+https://github.com/rust-lang/crates.io-index"
809checksum = "63e1afe738d71b1ebab5f1207c055054015427dbfc7bbe9ee1266894156ec046" 809checksum = "8292c1e1e81ddb552c4c90c36af201a0ce7e34995f55f0480f01052f242811c9"
810dependencies = [ 810dependencies = [
811 "paste-impl", 811 "paste-impl",
812 "proc-macro-hack", 812 "proc-macro-hack",
@@ -814,9 +814,9 @@ dependencies = [
814 814
815[[package]] 815[[package]]
816name = "paste-impl" 816name = "paste-impl"
817version = "0.1.7" 817version = "0.1.8"
818source = "registry+https://github.com/rust-lang/crates.io-index" 818source = "registry+https://github.com/rust-lang/crates.io-index"
819checksum = "6d4dc4a7f6f743211c5aab239640a65091535d97d43d92a52bca435a640892bb" 819checksum = "5e9c43f2645f06ee452544ad032886a75f3d1797b9487dcadcae9100ba58a51c"
820dependencies = [ 820dependencies = [
821 "proc-macro-hack", 821 "proc-macro-hack",
822 "proc-macro2", 822 "proc-macro2",
@@ -928,6 +928,7 @@ dependencies = [
928 "ra_cfg", 928 "ra_cfg",
929 "ra_prof", 929 "ra_prof",
930 "ra_syntax", 930 "ra_syntax",
931 "ra_tt",
931 "relative-path", 932 "relative-path",
932 "rustc-hash", 933 "rustc-hash",
933 "salsa", 934 "salsa",
@@ -1082,6 +1083,13 @@ dependencies = [
1082] 1083]
1083 1084
1084[[package]] 1085[[package]]
1086name = "ra_proc_macro"
1087version = "0.1.0"
1088dependencies = [
1089 "ra_tt",
1090]
1091
1092[[package]]
1085name = "ra_prof" 1093name = "ra_prof"
1086version = "0.1.0" 1094version = "0.1.0"
1087dependencies = [ 1095dependencies = [
@@ -1102,6 +1110,7 @@ dependencies = [
1102 "ra_cargo_watch", 1110 "ra_cargo_watch",
1103 "ra_cfg", 1111 "ra_cfg",
1104 "ra_db", 1112 "ra_db",
1113 "ra_proc_macro",
1105 "rustc-hash", 1114 "rustc-hash",
1106 "serde", 1115 "serde",
1107 "serde_json", 1116 "serde_json",
@@ -1238,9 +1247,9 @@ checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
1238 1247
1239[[package]] 1248[[package]]
1240name = "regex" 1249name = "regex"
1241version = "1.3.5" 1250version = "1.3.6"
1242source = "registry+https://github.com/rust-lang/crates.io-index" 1251source = "registry+https://github.com/rust-lang/crates.io-index"
1243checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" 1252checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
1244dependencies = [ 1253dependencies = [
1245 "aho-corasick", 1254 "aho-corasick",
1246 "memchr", 1255 "memchr",
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 62dcb3808..543224232 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -623,6 +623,30 @@ fn process(map: HashMap<String, String>) {}
623} 623}
624 624
625#[test] 625#[test]
626fn doctest_replace_unwrap_with_match() {
627 check(
628 "replace_unwrap_with_match",
629 r#####"
630enum Result<T, E> { Ok(T), Err(E) }
631fn main() {
632 let x: Result<i32, i32> = Result::Ok(92);
633 let y = x.<|>unwrap();
634}
635"#####,
636 r#####"
637enum Result<T, E> { Ok(T), Err(E) }
638fn main() {
639 let x: Result<i32, i32> = Result::Ok(92);
640 let y = match x {
641 Ok(a) => a,
642 _ => unreachable!(),
643 };
644}
645"#####,
646 )
647}
648
649#[test]
626fn doctest_split_import() { 650fn doctest_split_import() {
627 check( 651 check(
628 "split_import", 652 "split_import",
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index a63ef48b1..d86d804b2 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -130,8 +130,8 @@ mod tests {
130 fn add_explicit_type_works_for_macro_call() { 130 fn add_explicit_type_works_for_macro_call() {
131 check_assist( 131 check_assist(
132 add_explicit_type, 132 add_explicit_type,
133 "macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", 133 r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
134 "macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }", 134 r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }",
135 ); 135 );
136 } 136 }
137 137
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
new file mode 100644
index 000000000..62cb7a763
--- /dev/null
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -0,0 +1,177 @@
1use std::iter;
2
3use ra_syntax::{
4 ast::{self, make},
5 AstNode,
6};
7
8use crate::{Assist, AssistCtx, AssistId};
9use ast::edit::IndentLevel;
10
11// Assist: replace_unwrap_with_match
12//
13// Replaces `unwrap` a `match` expression. Works for Result and Option.
14//
15// ```
16// enum Result<T, E> { Ok(T), Err(E) }
17// fn main() {
18// let x: Result<i32, i32> = Result::Ok(92);
19// let y = x.<|>unwrap();
20// }
21// ```
22// ->
23// ```
24// enum Result<T, E> { Ok(T), Err(E) }
25// fn main() {
26// let x: Result<i32, i32> = Result::Ok(92);
27// let y = match x {
28// Ok(a) => a,
29// _ => unreachable!(),
30// };
31// }
32// ```
33pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> {
34 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
35 let name = method_call.name_ref()?;
36 if name.text() != "unwrap" {
37 return None;
38 }
39 let caller = method_call.expr()?;
40 let ty = ctx.sema.type_of_expr(&caller)?;
41
42 let type_name = ty.as_adt()?.name(ctx.sema.db).to_string();
43
44 for (unwrap_type, variant_name) in [("Result", "Ok"), ("Option", "Some")].iter() {
45 if &type_name == unwrap_type {
46 return ctx.add_assist(
47 AssistId("replace_unwrap_with_match"),
48 "Replace unwrap with match",
49 |edit| {
50 let ok_path =
51 make::path_unqualified(make::path_segment(make::name_ref(variant_name)));
52 let it = make::bind_pat(make::name("a")).into();
53 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
54
55 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
56 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
57
58 let unreachable_call = make::unreachable_macro_call().into();
59 let err_arm = make::match_arm(
60 iter::once(make::placeholder_pat().into()),
61 unreachable_call,
62 );
63
64 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
65 let match_expr = make::expr_match(caller.clone(), match_arm_list);
66 let match_expr =
67 IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
68
69 edit.target(method_call.syntax().text_range());
70 edit.set_cursor(caller.syntax().text_range().start());
71 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
72 },
73 );
74 }
75 }
76 None
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::helpers::{check_assist, check_assist_target};
83
84 #[test]
85 fn test_replace_result_unwrap_with_match() {
86 check_assist(
87 replace_unwrap_with_match,
88 r"
89enum Result<T, E> { Ok(T), Err(E) }
90fn i<T>(a: T) -> T { a }
91fn main() {
92 let x: Result<i32, i32> = Result::Ok(92);
93 let y = i(x).<|>unwrap();
94}
95 ",
96 r"
97enum Result<T, E> { Ok(T), Err(E) }
98fn i<T>(a: T) -> T { a }
99fn main() {
100 let x: Result<i32, i32> = Result::Ok(92);
101 let y = <|>match i(x) {
102 Ok(a) => a,
103 _ => unreachable!(),
104 };
105}
106 ",
107 )
108 }
109
110 #[test]
111 fn test_replace_option_unwrap_with_match() {
112 check_assist(
113 replace_unwrap_with_match,
114 r"
115enum Option<T> { Some(T), None }
116fn i<T>(a: T) -> T { a }
117fn main() {
118 let x = Option::Some(92);
119 let y = i(x).<|>unwrap();
120}
121 ",
122 r"
123enum Option<T> { Some(T), None }
124fn i<T>(a: T) -> T { a }
125fn main() {
126 let x = Option::Some(92);
127 let y = <|>match i(x) {
128 Some(a) => a,
129 _ => unreachable!(),
130 };
131}
132 ",
133 );
134 }
135
136 #[test]
137 fn test_replace_result_unwrap_with_match_chaining() {
138 check_assist(
139 replace_unwrap_with_match,
140 r"
141enum Result<T, E> { Ok(T), Err(E) }
142fn i<T>(a: T) -> T { a }
143fn main() {
144 let x: Result<i32, i32> = Result::Ok(92);
145 let y = i(x).<|>unwrap().count_zeroes();
146}
147 ",
148 r"
149enum Result<T, E> { Ok(T), Err(E) }
150fn i<T>(a: T) -> T { a }
151fn main() {
152 let x: Result<i32, i32> = Result::Ok(92);
153 let y = <|>match i(x) {
154 Ok(a) => a,
155 _ => unreachable!(),
156 }.count_zeroes();
157}
158 ",
159 )
160 }
161
162 #[test]
163 fn replace_unwrap_with_match_target() {
164 check_assist_target(
165 replace_unwrap_with_match,
166 r"
167enum Option<T> { Some(T), None }
168fn i<T>(a: T) -> T { a }
169fn main() {
170 let x = Option::Some(92);
171 let y = i(x).<|>unwrap();
172}
173 ",
174 r"i(x).unwrap()",
175 );
176 }
177}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index bcc9b3f10..becd5e99d 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -119,6 +119,7 @@ mod handlers {
119 mod remove_mut; 119 mod remove_mut;
120 mod replace_if_let_with_match; 120 mod replace_if_let_with_match;
121 mod replace_qualified_name_with_use; 121 mod replace_qualified_name_with_use;
122 mod replace_unwrap_with_match;
122 mod split_import; 123 mod split_import;
123 124
124 pub(crate) fn all() -> &'static [AssistHandler] { 125 pub(crate) fn all() -> &'static [AssistHandler] {
@@ -154,6 +155,7 @@ mod handlers {
154 remove_mut::remove_mut, 155 remove_mut::remove_mut,
155 replace_if_let_with_match::replace_if_let_with_match, 156 replace_if_let_with_match::replace_if_let_with_match,
156 replace_qualified_name_with_use::replace_qualified_name_with_use, 157 replace_qualified_name_with_use::replace_qualified_name_with_use,
158 replace_unwrap_with_match::replace_unwrap_with_match,
157 split_import::split_import, 159 split_import::split_import,
158 ] 160 ]
159 } 161 }
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index 878c22ba9..8ab409158 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -15,4 +15,5 @@ rustc-hash = "1.1.0"
15ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
16ra_cfg = { path = "../ra_cfg" } 16ra_cfg = { path = "../ra_cfg" }
17ra_prof = { path = "../ra_prof" } 17ra_prof = { path = "../ra_prof" }
18ra_tt = { path = "../ra_tt" }
18test_utils = { path = "../test_utils" } 19test_utils = { path = "../test_utils" }
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 3464f43df..7777ce81e 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -28,9 +28,9 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
28 db 28 db
29 } 29 }
30 30
31 fn with_position(fixture: &str) -> (Self, FilePosition) { 31 fn with_position(ra_fixture: &str) -> (Self, FilePosition) {
32 let mut db = Self::default(); 32 let mut db = Self::default();
33 let pos = with_files(&mut db, fixture); 33 let pos = with_files(&mut db, ra_fixture);
34 (db, pos.unwrap()) 34 (db, pos.unwrap())
35 } 35 }
36 36
@@ -70,6 +70,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId
70 meta.cfg, 70 meta.cfg,
71 meta.env, 71 meta.env,
72 Default::default(), 72 Default::default(),
73 Default::default(),
73 ); 74 );
74 crate_graph 75 crate_graph
75 } else { 76 } else {
@@ -81,6 +82,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId
81 CfgOptions::default(), 82 CfgOptions::default(),
82 Env::default(), 83 Env::default(),
83 Default::default(), 84 Default::default(),
85 Default::default(),
84 ); 86 );
85 crate_graph 87 crate_graph
86 }; 88 };
@@ -130,6 +132,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
130 meta.cfg, 132 meta.cfg,
131 meta.env, 133 meta.env,
132 Default::default(), 134 Default::default(),
135 Default::default(),
133 ); 136 );
134 let prev = crates.insert(krate.clone(), crate_id); 137 let prev = crates.insert(krate.clone(), crate_id);
135 assert!(prev.is_none()); 138 assert!(prev.is_none());
@@ -167,6 +170,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
167 CfgOptions::default(), 170 CfgOptions::default(),
168 Env::default(), 171 Env::default(),
169 Default::default(), 172 Default::default(),
173 Default::default(),
170 ); 174 );
171 } else { 175 } else {
172 for (from, to) in crate_deps { 176 for (from, to) in crate_deps {
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index e371f849d..5ddce98c6 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -10,6 +10,7 @@ use std::{
10 fmt, ops, 10 fmt, ops,
11 path::{Path, PathBuf}, 11 path::{Path, PathBuf},
12 str::FromStr, 12 str::FromStr,
13 sync::Arc,
13}; 14};
14 15
15use ra_cfg::CfgOptions; 16use ra_cfg::CfgOptions;
@@ -19,6 +20,7 @@ use rustc_hash::FxHashSet;
19 20
20use crate::{RelativePath, RelativePathBuf}; 21use crate::{RelativePath, RelativePathBuf};
21use fmt::Display; 22use fmt::Display;
23use ra_tt::TokenExpander;
22 24
23/// `FileId` is an integer which uniquely identifies a file. File paths are 25/// `FileId` is an integer which uniquely identifies a file. File paths are
24/// messy and system-dependent, so most of the code should work directly with 26/// messy and system-dependent, so most of the code should work directly with
@@ -115,6 +117,22 @@ impl Display for CrateName {
115 } 117 }
116} 118}
117 119
120#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
121pub struct ProcMacroId(pub u32);
122
123#[derive(Debug, Clone)]
124pub struct ProcMacro {
125 pub name: SmolStr,
126 pub expander: Arc<dyn TokenExpander>,
127}
128
129impl Eq for ProcMacro {}
130impl PartialEq for ProcMacro {
131 fn eq(&self, other: &ProcMacro) -> bool {
132 self.name == other.name && Arc::ptr_eq(&self.expander, &other.expander)
133 }
134}
135
118#[derive(Debug, Clone, PartialEq, Eq)] 136#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct CrateData { 137pub struct CrateData {
120 pub root_file_id: FileId, 138 pub root_file_id: FileId,
@@ -127,6 +145,7 @@ pub struct CrateData {
127 pub env: Env, 145 pub env: Env,
128 pub extern_source: ExternSource, 146 pub extern_source: ExternSource,
129 pub dependencies: Vec<Dependency>, 147 pub dependencies: Vec<Dependency>,
148 pub proc_macro: Vec<ProcMacro>,
130} 149}
131 150
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -166,7 +185,11 @@ impl CrateGraph {
166 cfg_options: CfgOptions, 185 cfg_options: CfgOptions,
167 env: Env, 186 env: Env,
168 extern_source: ExternSource, 187 extern_source: ExternSource,
188 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
169 ) -> CrateId { 189 ) -> CrateId {
190 let proc_macro =
191 proc_macro.into_iter().map(|(name, it)| ProcMacro { name, expander: it }).collect();
192
170 let data = CrateData { 193 let data = CrateData {
171 root_file_id: file_id, 194 root_file_id: file_id,
172 edition, 195 edition,
@@ -174,6 +197,7 @@ impl CrateGraph {
174 cfg_options, 197 cfg_options,
175 env, 198 env,
176 extern_source, 199 extern_source,
200 proc_macro,
177 dependencies: Vec::new(), 201 dependencies: Vec::new(),
178 }; 202 };
179 let crate_id = CrateId(self.arena.len() as u32); 203 let crate_id = CrateId(self.arena.len() as u32);
@@ -345,6 +369,7 @@ mod tests {
345 CfgOptions::default(), 369 CfgOptions::default(),
346 Env::default(), 370 Env::default(),
347 Default::default(), 371 Default::default(),
372 Default::default(),
348 ); 373 );
349 let crate2 = graph.add_crate_root( 374 let crate2 = graph.add_crate_root(
350 FileId(2u32), 375 FileId(2u32),
@@ -353,6 +378,7 @@ mod tests {
353 CfgOptions::default(), 378 CfgOptions::default(),
354 Env::default(), 379 Env::default(),
355 Default::default(), 380 Default::default(),
381 Default::default(),
356 ); 382 );
357 let crate3 = graph.add_crate_root( 383 let crate3 = graph.add_crate_root(
358 FileId(3u32), 384 FileId(3u32),
@@ -361,6 +387,7 @@ mod tests {
361 CfgOptions::default(), 387 CfgOptions::default(),
362 Env::default(), 388 Env::default(),
363 Default::default(), 389 Default::default(),
390 Default::default(),
364 ); 391 );
365 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 392 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
366 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 393 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
@@ -377,6 +404,7 @@ mod tests {
377 CfgOptions::default(), 404 CfgOptions::default(),
378 Env::default(), 405 Env::default(),
379 Default::default(), 406 Default::default(),
407 Default::default(),
380 ); 408 );
381 let crate2 = graph.add_crate_root( 409 let crate2 = graph.add_crate_root(
382 FileId(2u32), 410 FileId(2u32),
@@ -385,6 +413,7 @@ mod tests {
385 CfgOptions::default(), 413 CfgOptions::default(),
386 Env::default(), 414 Env::default(),
387 Default::default(), 415 Default::default(),
416 Default::default(),
388 ); 417 );
389 let crate3 = graph.add_crate_root( 418 let crate3 = graph.add_crate_root(
390 FileId(3u32), 419 FileId(3u32),
@@ -393,6 +422,7 @@ mod tests {
393 CfgOptions::default(), 422 CfgOptions::default(),
394 Env::default(), 423 Env::default(),
395 Default::default(), 424 Default::default(),
425 Default::default(),
396 ); 426 );
397 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 427 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
398 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 428 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
@@ -408,6 +438,7 @@ mod tests {
408 CfgOptions::default(), 438 CfgOptions::default(),
409 Env::default(), 439 Env::default(),
410 Default::default(), 440 Default::default(),
441 Default::default(),
411 ); 442 );
412 let crate2 = graph.add_crate_root( 443 let crate2 = graph.add_crate_root(
413 FileId(2u32), 444 FileId(2u32),
@@ -416,6 +447,7 @@ mod tests {
416 CfgOptions::default(), 447 CfgOptions::default(),
417 Env::default(), 448 Env::default(),
418 Default::default(), 449 Default::default(),
450 Default::default(),
419 ); 451 );
420 assert!(graph 452 assert!(graph
421 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) 453 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index bac24e218..a06f59c14 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -12,7 +12,7 @@ pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{ 13 input::{
14 CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, 14 CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId,
15 FileId, SourceRoot, SourceRootId, 15 FileId, ProcMacroId, SourceRoot, SourceRootId,
16 }, 16 },
17}; 17};
18pub use relative_path::{RelativePath, RelativePathBuf}; 18pub use relative_path::{RelativePath, RelativePathBuf};
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index fcba95091..ec931b34f 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -10,15 +10,16 @@ pub use hir_def::db::{
10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, 10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternMacroQuery, MacroArgQuery, MacroDefQuery, 13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery,
14 MacroExpandQuery, ParseMacroQuery, 14 MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery,
15}; 15};
16pub use hir_ty::db::{ 16pub use hir_ty::db::{
17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, 17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, 18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, 19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery,
20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, 20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21 InternTypeCtorQuery, StructDatumQuery, TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, 21 InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery,
22 TraitSolveQuery, TyQuery, ValueTyQuery,
22}; 23};
23 24
24#[test] 25#[test]
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 3cf0c66ea..e8443dde8 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -563,7 +563,8 @@ impl ExprCollector<'_> {
563 ast::ModuleItem::ImplDef(_) 563 ast::ModuleItem::ImplDef(_)
564 | ast::ModuleItem::UseItem(_) 564 | ast::ModuleItem::UseItem(_)
565 | ast::ModuleItem::ExternCrateItem(_) 565 | ast::ModuleItem::ExternCrateItem(_)
566 | ast::ModuleItem::Module(_) => continue, 566 | ast::ModuleItem::Module(_)
567 | ast::ModuleItem::MacroCall(_) => continue,
567 }; 568 };
568 self.body.item_scope.define_def(def); 569 self.body.item_scope.define_def(def);
569 if let Some(name) = name { 570 if let Some(name) = name {
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 7f8c1ea21..5dc7395f5 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -48,6 +48,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
48 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 48 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
49 49
50 #[salsa::invoke(crate_def_map_wait)] 50 #[salsa::invoke(crate_def_map_wait)]
51 #[salsa::transparent]
51 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; 52 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
52 53
53 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 54 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
@@ -109,12 +110,6 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
109 fn documentation(&self, def: AttrDefId) -> Option<Documentation>; 110 fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
110} 111}
111 112
112// impl<T: DefDatabase> Upcast<dyn AstDatabase> for T {
113// fn upcast(&self) -> &dyn AstDatabase {
114// &*self
115// }
116// }
117
118fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { 113fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> {
119 let _p = profile("crate_def_map:wait"); 114 let _p = profile("crate_def_map:wait");
120 db.crate_def_map_query(krate) 115 db.crate_def_map_query(krate)
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 9c125f32f..8fe3f8617 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -11,7 +11,7 @@ use hir_expand::{
11 HirFileId, MacroCallId, MacroDefId, MacroDefKind, 11 HirFileId, MacroCallId, MacroDefId, MacroDefKind,
12}; 12};
13use ra_cfg::CfgOptions; 13use ra_cfg::CfgOptions;
14use ra_db::{CrateId, FileId}; 14use ra_db::{CrateId, FileId, ProcMacroId};
15use ra_syntax::ast; 15use ra_syntax::ast;
16use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
17use test_utils::tested_by; 17use test_utils::tested_by;
@@ -53,6 +53,16 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr
53 } 53 }
54 54
55 let cfg_options = &crate_graph[def_map.krate].cfg_options; 55 let cfg_options = &crate_graph[def_map.krate].cfg_options;
56 let proc_macros = &crate_graph[def_map.krate].proc_macro;
57 let proc_macros = proc_macros
58 .iter()
59 .enumerate()
60 .map(|(idx, it)| {
61 // FIXME: a hacky way to create a Name from string.
62 let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
63 (name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32)))
64 })
65 .collect();
56 66
57 let mut collector = DefCollector { 67 let mut collector = DefCollector {
58 db, 68 db,
@@ -65,9 +75,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr
65 unexpanded_attribute_macros: Vec::new(), 75 unexpanded_attribute_macros: Vec::new(),
66 mod_dirs: FxHashMap::default(), 76 mod_dirs: FxHashMap::default(),
67 cfg_options, 77 cfg_options,
68 78 proc_macros,
69 // FIXME: pass proc-macro from crate-graph
70 proc_macros: Default::default(),
71 }; 79 };
72 collector.collect(); 80 collector.collect();
73 collector.finish() 81 collector.finish()
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 1631e87b8..8f190e7f9 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -209,11 +209,8 @@ impl RawItemsCollector {
209 current_module: Option<Idx<ModuleData>>, 209 current_module: Option<Idx<ModuleData>>,
210 body: impl ast::ModuleItemOwner, 210 body: impl ast::ModuleItemOwner,
211 ) { 211 ) {
212 for item_or_macro in body.items_with_macros() { 212 for item in body.items() {
213 match item_or_macro { 213 self.add_item(current_module, item)
214 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
215 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
216 }
217 } 214 }
218 } 215 }
219 216
@@ -265,6 +262,10 @@ impl RawItemsCollector {
265 ast::ModuleItem::StaticDef(it) => { 262 ast::ModuleItem::StaticDef(it) => {
266 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) 263 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
267 } 264 }
265 ast::ModuleItem::MacroCall(it) => {
266 self.add_macro(current_module, it);
267 return;
268 }
268 }; 269 };
269 if let Some(name) = name { 270 if let Some(name) = name {
270 let name = name.as_name(); 271 let name = name.as_name();
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 83f429c29..496fc6b08 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -4,8 +4,8 @@ use ra_db::SourceDatabaseExt;
4 4
5use super::*; 5use super::*;
6 6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { 7fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
8 let (mut db, pos) = TestDB::with_position(initial); 8 let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
9 let krate = db.test_crate(); 9 let krate = db.test_crate();
10 { 10 {
11 let events = db.log_executed(|| { 11 let events = db.log_executed(|| {
@@ -13,7 +13,7 @@ fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
13 }); 13 });
14 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 14 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
15 } 15 }
16 db.set_file_text(pos.file_id, Arc::new(file_change.to_string())); 16 db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string()));
17 17
18 { 18 {
19 let events = db.log_executed(|| { 19 let events = db.log_executed(|| {
@@ -26,7 +26,7 @@ fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
26#[test] 26#[test]
27fn typing_inside_a_function_should_not_invalidate_def_map() { 27fn typing_inside_a_function_should_not_invalidate_def_map() {
28 check_def_map_is_not_recomputed( 28 check_def_map_is_not_recomputed(
29 " 29 r"
30 //- /lib.rs 30 //- /lib.rs
31 mod foo;<|> 31 mod foo;<|>
32 32
@@ -41,7 +41,7 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
41 //- /foo/bar.rs 41 //- /foo/bar.rs
42 pub struct Baz; 42 pub struct Baz;
43 ", 43 ",
44 " 44 r"
45 mod foo; 45 mod foo;
46 46
47 use crate::foo::bar::Baz; 47 use crate::foo::bar::Baz;
@@ -54,7 +54,7 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
54#[test] 54#[test]
55fn adding_inner_items_should_not_invalidate_def_map() { 55fn adding_inner_items_should_not_invalidate_def_map() {
56 check_def_map_is_not_recomputed( 56 check_def_map_is_not_recomputed(
57 " 57 r"
58 //- /lib.rs 58 //- /lib.rs
59 struct S { a: i32} 59 struct S { a: i32}
60 enum E { A } 60 enum E { A }
@@ -72,7 +72,7 @@ fn adding_inner_items_should_not_invalidate_def_map() {
72 //- /foo/bar.rs 72 //- /foo/bar.rs
73 pub struct Baz; 73 pub struct Baz;
74 ", 74 ",
75 " 75 r"
76 struct S { a: i32, b: () } 76 struct S { a: i32, b: () }
77 enum E { A, B } 77 enum E { A, B }
78 trait T { 78 trait T {
@@ -92,7 +92,7 @@ fn adding_inner_items_should_not_invalidate_def_map() {
92#[test] 92#[test]
93fn typing_inside_a_macro_should_not_invalidate_def_map() { 93fn typing_inside_a_macro_should_not_invalidate_def_map() {
94 let (mut db, pos) = TestDB::with_position( 94 let (mut db, pos) = TestDB::with_position(
95 " 95 r"
96 //- /lib.rs 96 //- /lib.rs
97 macro_rules! m { 97 macro_rules! m {
98 ($ident:ident) => { 98 ($ident:ident) => {
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index a6644d55f..5643ecdce 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -68,8 +68,6 @@ impl AstIdMap {
68 bfs(node, |it| { 68 bfs(node, |it| {
69 if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { 69 if let Some(module_item) = ast::ModuleItem::cast(it.clone()) {
70 res.alloc(module_item.syntax()); 70 res.alloc(module_item.syntax());
71 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
72 res.alloc(macro_call.syntax());
73 } 71 }
74 }); 72 });
75 res 73 res
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs
index a8dee2052..4d270e0de 100644
--- a/crates/ra_hir_expand/src/proc_macro.rs
+++ b/crates/ra_hir_expand/src/proc_macro.rs
@@ -1,33 +1,32 @@
1//! Proc Macro Expander stub 1//! Proc Macro Expander stub
2 2
3use crate::{db::AstDatabase, LazyMacroId, MacroCallKind, MacroCallLoc}; 3use crate::{db::AstDatabase, LazyMacroId};
4use ra_db::CrateId; 4use ra_db::{CrateId, ProcMacroId};
5 5
6#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] 6#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
7pub struct ProcMacroExpander { 7pub struct ProcMacroExpander {
8 krate: CrateId, 8 krate: CrateId,
9 proc_macro_id: ProcMacroId,
9} 10}
10 11
11impl ProcMacroExpander { 12impl ProcMacroExpander {
12 pub fn new(krate: CrateId) -> ProcMacroExpander { 13 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander {
13 ProcMacroExpander { krate } 14 ProcMacroExpander { krate, proc_macro_id }
14 } 15 }
15 16
16 pub fn expand( 17 pub fn expand(
17 &self, 18 &self,
18 db: &dyn AstDatabase, 19 db: &dyn AstDatabase,
19 id: LazyMacroId, 20 _id: LazyMacroId,
20 _tt: &tt::Subtree, 21 tt: &tt::Subtree,
21 ) -> Result<tt::Subtree, mbe::ExpandError> { 22 ) -> Result<tt::Subtree, mbe::ExpandError> {
22 let loc: MacroCallLoc = db.lookup_intern_macro(id); 23 let krate_graph = db.crate_graph();
23 let name = match loc.kind { 24 let proc_macro = krate_graph[self.krate]
24 MacroCallKind::FnLike(_) => return Err(mbe::ExpandError::ConversionError), 25 .proc_macro
25 MacroCallKind::Attr(_, name) => name, 26 .get(self.proc_macro_id.0 as usize)
26 }; 27 .clone()
28 .ok_or_else(|| mbe::ExpandError::ConversionError)?;
27 29
28 log::debug!("Proc-macro-expanding name = {}", name); 30 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
29
30 // Return nothing for now
31 return Ok(tt::Subtree::default());
32 } 31 }
33} 32}
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 11fc2ac3d..1462b053f 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -22,6 +22,7 @@ use hir_expand::name::Name;
22#[salsa::requires(salsa::Database)] 22#[salsa::requires(salsa::Database)]
23pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { 23pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
24 #[salsa::invoke(infer_wait)] 24 #[salsa::invoke(infer_wait)]
25 #[salsa::transparent]
25 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; 26 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
26 27
27 #[salsa::invoke(crate::infer::infer_query)] 28 #[salsa::invoke(crate::infer::infer_query)]
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 5ab06c6cf..e43414985 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -213,6 +213,7 @@ impl Analysis {
213 cfg_options, 213 cfg_options,
214 Env::default(), 214 Env::default(),
215 Default::default(), 215 Default::default(),
216 Default::default(),
216 ); 217 );
217 change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text)); 218 change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text));
218 change.set_crate_graph(crate_graph); 219 change.set_crate_graph(crate_graph);
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs
index 2cf77a31f..2c13f206a 100644
--- a/crates/ra_ide/src/mock_analysis.rs
+++ b/crates/ra_ide/src/mock_analysis.rs
@@ -103,6 +103,7 @@ impl MockAnalysis {
103 cfg_options, 103 cfg_options,
104 Env::default(), 104 Env::default(),
105 Default::default(), 105 Default::default(),
106 Default::default(),
106 )); 107 ));
107 } else if path.ends_with("/lib.rs") { 108 } else if path.ends_with("/lib.rs") {
108 let crate_name = path.parent().unwrap().file_name().unwrap(); 109 let crate_name = path.parent().unwrap().file_name().unwrap();
@@ -113,6 +114,7 @@ impl MockAnalysis {
113 cfg_options, 114 cfg_options,
114 Env::default(), 115 Env::default(),
115 Default::default(), 116 Default::default(),
117 Default::default(),
116 ); 118 );
117 if let Some(root_crate) = root_crate { 119 if let Some(root_crate) = root_crate {
118 crate_graph 120 crate_graph
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs
index 76d130b9b..958b92bed 100644
--- a/crates/ra_ide/src/parent_module.rs
+++ b/crates/ra_ide/src/parent_module.rs
@@ -137,6 +137,7 @@ mod tests {
137 CfgOptions::default(), 137 CfgOptions::default(),
138 Env::default(), 138 Env::default(),
139 Default::default(), 139 Default::default(),
140 Default::default(),
140 ); 141 );
141 let mut change = AnalysisChange::new(); 142 let mut change = AnalysisChange::new();
142 change.set_crate_graph(crate_graph); 143 change.set_crate_graph(crate_graph);
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 628cf6416..8446ef88e 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -311,6 +311,7 @@ impl RootDatabase {
311 hir::db::MacroDefQuery 311 hir::db::MacroDefQuery
312 hir::db::ParseMacroQuery 312 hir::db::ParseMacroQuery
313 hir::db::MacroExpandQuery 313 hir::db::MacroExpandQuery
314 hir::db::InternEagerExpansionQuery
314 315
315 // DefDatabase 316 // DefDatabase
316 hir::db::RawItemsQuery 317 hir::db::RawItemsQuery
@@ -359,14 +360,21 @@ impl RootDatabase {
359 hir::db::ImplsInCrateQuery 360 hir::db::ImplsInCrateQuery
360 hir::db::ImplsForTraitQuery 361 hir::db::ImplsForTraitQuery
361 hir::db::InternTypeCtorQuery 362 hir::db::InternTypeCtorQuery
363 hir::db::InternTypeParamIdQuery
362 hir::db::InternChalkImplQuery 364 hir::db::InternChalkImplQuery
363 hir::db::InternAssocTyValueQuery 365 hir::db::InternAssocTyValueQuery
364 hir::db::AssociatedTyDataQuery 366 hir::db::AssociatedTyDataQuery
365 hir::db::AssociatedTyValueQuery
366 hir::db::TraitSolveQuery
367 hir::db::TraitDatumQuery 367 hir::db::TraitDatumQuery
368 hir::db::StructDatumQuery 368 hir::db::StructDatumQuery
369 hir::db::ImplDatumQuery 369 hir::db::ImplDatumQuery
370 hir::db::AssociatedTyValueQuery
371 hir::db::TraitSolveQuery
372
373 // SymbolsDatabase
374 crate::symbol_index::FileSymbolsQuery
375
376 // LineIndexDatabase
377 crate::LineIndexQuery
370 ]; 378 ];
371 acc.sort_by_key(|it| std::cmp::Reverse(it.1)); 379 acc.sort_by_key(|it| std::cmp::Reverse(it.1));
372 acc 380 acc
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 6a9037bfc..535b7daa0 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -28,6 +28,13 @@ pub enum ExpandError {
28 BindingError(String), 28 BindingError(String),
29 ConversionError, 29 ConversionError,
30 InvalidRepeat, 30 InvalidRepeat,
31 ProcMacroError(tt::ExpansionError),
32}
33
34impl From<tt::ExpansionError> for ExpandError {
35 fn from(it: tt::ExpansionError) -> Self {
36 ExpandError::ProcMacroError(it)
37 }
31} 38}
32 39
33pub use crate::syntax_bridge::{ 40pub use crate::syntax_bridge::{
diff --git a/crates/ra_proc_macro/Cargo.toml b/crates/ra_proc_macro/Cargo.toml
new file mode 100644
index 000000000..bc2c37296
--- /dev/null
+++ b/crates/ra_proc_macro/Cargo.toml
@@ -0,0 +1,12 @@
1[package]
2edition = "2018"
3name = "ra_proc_macro"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6publish = false
7
8[lib]
9doctest = false
10
11[dependencies]
12ra_tt = { path = "../ra_tt" }
diff --git a/crates/ra_proc_macro/src/lib.rs b/crates/ra_proc_macro/src/lib.rs
new file mode 100644
index 000000000..5e21dd487
--- /dev/null
+++ b/crates/ra_proc_macro/src/lib.rs
@@ -0,0 +1,59 @@
1//! Client-side Proc-Macro crate
2//!
3//! We separate proc-macro expanding logic to an extern program to allow
4//! different implementations (e.g. wasm or dylib loading). And this crate
5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program)
7
8use ra_tt::{SmolStr, Subtree};
9use std::{
10 path::{Path, PathBuf},
11 sync::Arc,
12};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ProcMacroProcessExpander {
16 process: Arc<ProcMacroProcessSrv>,
17 name: SmolStr,
18}
19
20impl ra_tt::TokenExpander for ProcMacroProcessExpander {
21 fn expand(
22 &self,
23 _subtree: &Subtree,
24 _attr: Option<&Subtree>,
25 ) -> Result<Subtree, ra_tt::ExpansionError> {
26 // FIXME: do nothing for now
27 Ok(Subtree::default())
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct ProcMacroProcessSrv {
33 path: PathBuf,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum ProcMacroClient {
38 Process { process: Arc<ProcMacroProcessSrv> },
39 Dummy,
40}
41
42impl ProcMacroClient {
43 pub fn extern_process(process_path: &Path) -> ProcMacroClient {
44 let process = ProcMacroProcessSrv { path: process_path.into() };
45 ProcMacroClient::Process { process: Arc::new(process) }
46 }
47
48 pub fn dummy() -> ProcMacroClient {
49 ProcMacroClient::Dummy
50 }
51
52 pub fn by_dylib_path(
53 &self,
54 _dylib_path: &Path,
55 ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> {
56 // FIXME: return empty for now
57 vec![]
58 }
59}
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index 22300548a..cdcdd63c9 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -17,6 +17,7 @@ ra_arena = { path = "../ra_arena" }
17ra_db = { path = "../ra_db" } 17ra_db = { path = "../ra_db" }
18ra_cfg = { path = "../ra_cfg" } 18ra_cfg = { path = "../ra_cfg" }
19ra_cargo_watch = { path = "../ra_cargo_watch" } 19ra_cargo_watch = { path = "../ra_cargo_watch" }
20ra_proc_macro = { path = "../ra_proc_macro" }
20 21
21serde = { version = "1.0.104", features = ["derive"] } 22serde = { version = "1.0.104", features = ["derive"] }
22serde_json = "1.0.48" 23serde_json = "1.0.48"
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index c7f9bd873..291594e2a 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -83,6 +83,7 @@ pub struct PackageData {
83 pub edition: Edition, 83 pub edition: Edition,
84 pub features: Vec<String>, 84 pub features: Vec<String>,
85 pub out_dir: Option<PathBuf>, 85 pub out_dir: Option<PathBuf>,
86 pub proc_macro_dylib_path: Option<PathBuf>,
86} 87}
87 88
88#[derive(Debug, Clone)] 89#[derive(Debug, Clone)]
@@ -158,8 +159,11 @@ impl CargoWorkspace {
158 })?; 159 })?;
159 160
160 let mut out_dir_by_id = FxHashMap::default(); 161 let mut out_dir_by_id = FxHashMap::default();
162 let mut proc_macro_dylib_paths = FxHashMap::default();
161 if cargo_features.load_out_dirs_from_check { 163 if cargo_features.load_out_dirs_from_check {
162 out_dir_by_id = load_out_dirs(cargo_toml, cargo_features); 164 let resources = load_extern_resources(cargo_toml, cargo_features);
165 out_dir_by_id = resources.out_dirs;
166 proc_macro_dylib_paths = resources.proc_dylib_paths;
163 } 167 }
164 168
165 let mut pkg_by_id = FxHashMap::default(); 169 let mut pkg_by_id = FxHashMap::default();
@@ -183,6 +187,7 @@ impl CargoWorkspace {
183 dependencies: Vec::new(), 187 dependencies: Vec::new(),
184 features: Vec::new(), 188 features: Vec::new(),
185 out_dir: out_dir_by_id.get(&id).cloned(), 189 out_dir: out_dir_by_id.get(&id).cloned(),
190 proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
186 }); 191 });
187 let pkg_data = &mut packages[pkg]; 192 let pkg_data = &mut packages[pkg];
188 pkg_by_id.insert(id, pkg); 193 pkg_by_id.insert(id, pkg);
@@ -246,10 +251,13 @@ impl CargoWorkspace {
246 } 251 }
247} 252}
248 253
249pub fn load_out_dirs( 254#[derive(Debug, Clone, Default)]
250 cargo_toml: &Path, 255pub struct ExternResources {
251 cargo_features: &CargoFeatures, 256 out_dirs: FxHashMap<PackageId, PathBuf>,
252) -> FxHashMap<PackageId, PathBuf> { 257 proc_dylib_paths: FxHashMap<PackageId, PathBuf>,
258}
259
260pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) -> ExternResources {
253 let mut args: Vec<String> = vec![ 261 let mut args: Vec<String> = vec![
254 "check".to_string(), 262 "check".to_string(),
255 "--message-format=json".to_string(), 263 "--message-format=json".to_string(),
@@ -267,14 +275,21 @@ pub fn load_out_dirs(
267 args.extend(cargo_features.features.iter().cloned()); 275 args.extend(cargo_features.features.iter().cloned());
268 } 276 }
269 277
270 let mut acc = FxHashMap::default(); 278 let mut acc = ExternResources::default();
271 let res = run_cargo(&args, cargo_toml.parent(), &mut |message| { 279 let res = run_cargo(&args, cargo_toml.parent(), &mut |message| {
272 match message { 280 match message {
273 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { 281 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
274 acc.insert(package_id, out_dir); 282 acc.out_dirs.insert(package_id, out_dir);
275 } 283 }
276 284
277 Message::CompilerArtifact(_) => (), 285 Message::CompilerArtifact(message) => {
286 if message.target.kind.contains(&"proc-macro".to_string()) {
287 let package_id = message.package_id;
288 if let Some(filename) = message.filenames.get(0) {
289 acc.proc_dylib_paths.insert(package_id, filename.clone());
290 }
291 }
292 }
278 Message::CompilerMessage(_) => (), 293 Message::CompilerMessage(_) => (),
279 Message::Unknown => (), 294 Message::Unknown => (),
280 } 295 }
diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs
index 336446e58..b030c8a6a 100644
--- a/crates/ra_project_model/src/json_project.rs
+++ b/crates/ra_project_model/src/json_project.rs
@@ -23,6 +23,7 @@ pub struct Crate {
23 pub(crate) atom_cfgs: FxHashSet<String>, 23 pub(crate) atom_cfgs: FxHashSet<String>,
24 pub(crate) key_value_cfgs: FxHashMap<String, String>, 24 pub(crate) key_value_cfgs: FxHashMap<String, String>,
25 pub(crate) out_dir: Option<PathBuf>, 25 pub(crate) out_dir: Option<PathBuf>,
26 pub(crate) proc_macro_dylib_path: Option<PathBuf>,
26} 27}
27 28
28#[derive(Clone, Copy, Debug, Deserialize)] 29#[derive(Clone, Copy, Debug, Deserialize)]
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index a3ef9acdc..444d3bb3f 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -23,6 +23,7 @@ pub use crate::{
23 json_project::JsonProject, 23 json_project::JsonProject,
24 sysroot::Sysroot, 24 sysroot::Sysroot,
25}; 25};
26pub use ra_proc_macro::ProcMacroClient;
26 27
27#[derive(Clone, PartialEq, Eq, Hash, Debug)] 28#[derive(Clone, PartialEq, Eq, Hash, Debug)]
28pub struct CargoTomlNotFoundError { 29pub struct CargoTomlNotFoundError {
@@ -173,6 +174,29 @@ impl ProjectWorkspace {
173 } 174 }
174 } 175 }
175 176
177 pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> {
178 match self {
179 ProjectWorkspace::Json { project } => {
180 let mut proc_macro_dylib_paths = Vec::with_capacity(project.crates.len());
181 for krate in &project.crates {
182 if let Some(out_dir) = &krate.proc_macro_dylib_path {
183 proc_macro_dylib_paths.push(out_dir.to_path_buf());
184 }
185 }
186 proc_macro_dylib_paths
187 }
188 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => {
189 let mut proc_macro_dylib_paths = Vec::with_capacity(cargo.packages().len());
190 for pkg in cargo.packages() {
191 if let Some(dylib_path) = &cargo[pkg].proc_macro_dylib_path {
192 proc_macro_dylib_paths.push(dylib_path.to_path_buf());
193 }
194 }
195 proc_macro_dylib_paths
196 }
197 }
198 }
199
176 pub fn n_packages(&self) -> usize { 200 pub fn n_packages(&self) -> usize {
177 match self { 201 match self {
178 ProjectWorkspace::Json { project } => project.crates.len(), 202 ProjectWorkspace::Json { project } => project.crates.len(),
@@ -186,6 +210,7 @@ impl ProjectWorkspace {
186 &self, 210 &self,
187 default_cfg_options: &CfgOptions, 211 default_cfg_options: &CfgOptions,
188 extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>, 212 extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>,
213 proc_macro_client: &ProcMacroClient,
189 load: &mut dyn FnMut(&Path) -> Option<FileId>, 214 load: &mut dyn FnMut(&Path) -> Option<FileId>,
190 ) -> CrateGraph { 215 ) -> CrateGraph {
191 let mut crate_graph = CrateGraph::default(); 216 let mut crate_graph = CrateGraph::default();
@@ -219,7 +244,10 @@ impl ProjectWorkspace {
219 extern_source.set_extern_path(&out_dir, extern_source_id); 244 extern_source.set_extern_path(&out_dir, extern_source_id);
220 } 245 }
221 } 246 }
222 247 let proc_macro = krate
248 .proc_macro_dylib_path
249 .clone()
250 .map(|it| proc_macro_client.by_dylib_path(&it));
223 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env 251 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
224 crates.insert( 252 crates.insert(
225 crate_id, 253 crate_id,
@@ -231,6 +259,7 @@ impl ProjectWorkspace {
231 cfg_options, 259 cfg_options,
232 env, 260 env,
233 extern_source, 261 extern_source,
262 proc_macro.unwrap_or_default(),
234 ), 263 ),
235 ); 264 );
236 } 265 }
@@ -270,6 +299,8 @@ impl ProjectWorkspace {
270 299
271 let env = Env::default(); 300 let env = Env::default();
272 let extern_source = ExternSource::default(); 301 let extern_source = ExternSource::default();
302 let proc_macro = vec![];
303
273 let crate_id = crate_graph.add_crate_root( 304 let crate_id = crate_graph.add_crate_root(
274 file_id, 305 file_id,
275 Edition::Edition2018, 306 Edition::Edition2018,
@@ -280,6 +311,7 @@ impl ProjectWorkspace {
280 cfg_options, 311 cfg_options,
281 env, 312 env,
282 extern_source, 313 extern_source,
314 proc_macro,
283 ); 315 );
284 sysroot_crates.insert(krate, crate_id); 316 sysroot_crates.insert(krate, crate_id);
285 } 317 }
@@ -327,6 +359,12 @@ impl ProjectWorkspace {
327 extern_source.set_extern_path(&out_dir, extern_source_id); 359 extern_source.set_extern_path(&out_dir, extern_source_id);
328 } 360 }
329 } 361 }
362 let proc_macro = cargo[pkg]
363 .proc_macro_dylib_path
364 .as_ref()
365 .map(|it| proc_macro_client.by_dylib_path(&it))
366 .unwrap_or_default();
367
330 let crate_id = crate_graph.add_crate_root( 368 let crate_id = crate_graph.add_crate_root(
331 file_id, 369 file_id,
332 edition, 370 edition,
@@ -334,6 +372,7 @@ impl ProjectWorkspace {
334 cfg_options, 372 cfg_options,
335 env, 373 env,
336 extern_source, 374 extern_source,
375 proc_macro.clone(),
337 ); 376 );
338 if cargo[tgt].kind == TargetKind::Lib { 377 if cargo[tgt].kind == TargetKind::Lib {
339 lib_tgt = Some((crate_id, cargo[tgt].name.clone())); 378 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 002f453cd..7204ca5b1 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4135,6 +4135,7 @@ pub enum ModuleItem {
4135 ConstDef(ConstDef), 4135 ConstDef(ConstDef),
4136 StaticDef(StaticDef), 4136 StaticDef(StaticDef),
4137 Module(Module), 4137 Module(Module),
4138 MacroCall(MacroCall),
4138} 4139}
4139impl From<StructDef> for ModuleItem { 4140impl From<StructDef> for ModuleItem {
4140 fn from(node: StructDef) -> ModuleItem { 4141 fn from(node: StructDef) -> ModuleItem {
@@ -4196,6 +4197,11 @@ impl From<Module> for ModuleItem {
4196 ModuleItem::Module(node) 4197 ModuleItem::Module(node)
4197 } 4198 }
4198} 4199}
4200impl From<MacroCall> for ModuleItem {
4201 fn from(node: MacroCall) -> ModuleItem {
4202 ModuleItem::MacroCall(node)
4203 }
4204}
4199impl std::fmt::Display for ModuleItem { 4205impl std::fmt::Display for ModuleItem {
4200 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 4206 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4201 std::fmt::Display::fmt(self.syntax(), f) 4207 std::fmt::Display::fmt(self.syntax(), f)
@@ -4205,7 +4211,7 @@ impl AstNode for ModuleItem {
4205 fn can_cast(kind: SyntaxKind) -> bool { 4211 fn can_cast(kind: SyntaxKind) -> bool {
4206 match kind { 4212 match kind {
4207 STRUCT_DEF | UNION_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | TYPE_ALIAS_DEF | IMPL_DEF 4213 STRUCT_DEF | UNION_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | TYPE_ALIAS_DEF | IMPL_DEF
4208 | USE_ITEM | EXTERN_CRATE_ITEM | CONST_DEF | STATIC_DEF | MODULE => true, 4214 | USE_ITEM | EXTERN_CRATE_ITEM | CONST_DEF | STATIC_DEF | MODULE | MACRO_CALL => true,
4209 _ => false, 4215 _ => false,
4210 } 4216 }
4211 } 4217 }
@@ -4223,6 +4229,7 @@ impl AstNode for ModuleItem {
4223 CONST_DEF => ModuleItem::ConstDef(ConstDef { syntax }), 4229 CONST_DEF => ModuleItem::ConstDef(ConstDef { syntax }),
4224 STATIC_DEF => ModuleItem::StaticDef(StaticDef { syntax }), 4230 STATIC_DEF => ModuleItem::StaticDef(StaticDef { syntax }),
4225 MODULE => ModuleItem::Module(Module { syntax }), 4231 MODULE => ModuleItem::Module(Module { syntax }),
4232 MACRO_CALL => ModuleItem::MacroCall(MacroCall { syntax }),
4226 _ => return None, 4233 _ => return None,
4227 }; 4234 };
4228 Some(res) 4235 Some(res)
@@ -4241,6 +4248,7 @@ impl AstNode for ModuleItem {
4241 ModuleItem::ConstDef(it) => &it.syntax, 4248 ModuleItem::ConstDef(it) => &it.syntax,
4242 ModuleItem::StaticDef(it) => &it.syntax, 4249 ModuleItem::StaticDef(it) => &it.syntax,
4243 ModuleItem::Module(it) => &it.syntax, 4250 ModuleItem::Module(it) => &it.syntax,
4251 ModuleItem::MacroCall(it) => &it.syntax,
4244 } 4252 }
4245 } 4253 }
4246} 4254}
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 1145b69e8..e29600439 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -250,6 +250,10 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
250 .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) 250 .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
251} 251}
252 252
253pub fn unreachable_macro_call() -> ast::MacroCall {
254 ast_from_text(&format!("unreachable!()"))
255}
256
253fn ast_from_text<N: AstNode>(text: &str) -> N { 257fn ast_from_text<N: AstNode>(text: &str) -> N {
254 let parse = SourceFile::parse(text); 258 let parse = SourceFile::parse(text);
255 let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 259 let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index f8cf1e3eb..576378306 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -6,8 +6,7 @@ use itertools::Itertools;
6 6
7use crate::{ 7use crate::{
8 ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, 8 ast::{self, child_opt, children, AstChildren, AstNode, AstToken},
9 match_ast, 9 syntax_node::SyntaxElementChildren,
10 syntax_node::{SyntaxElementChildren, SyntaxNodeChildren},
11}; 10};
12 11
13pub trait TypeAscriptionOwner: AstNode { 12pub trait TypeAscriptionOwner: AstNode {
@@ -46,38 +45,10 @@ pub trait FnDefOwner: AstNode {
46 } 45 }
47} 46}
48 47
49#[derive(Debug, Clone, PartialEq, Eq)]
50pub enum ItemOrMacro {
51 Item(ast::ModuleItem),
52 Macro(ast::MacroCall),
53}
54
55pub trait ModuleItemOwner: AstNode { 48pub trait ModuleItemOwner: AstNode {
56 fn items(&self) -> AstChildren<ast::ModuleItem> { 49 fn items(&self) -> AstChildren<ast::ModuleItem> {
57 children(self) 50 children(self)
58 } 51 }
59 fn items_with_macros(&self) -> ItemOrMacroIter {
60 ItemOrMacroIter(self.syntax().children())
61 }
62}
63
64#[derive(Debug)]
65pub struct ItemOrMacroIter(SyntaxNodeChildren);
66
67impl Iterator for ItemOrMacroIter {
68 type Item = ItemOrMacro;
69 fn next(&mut self) -> Option<ItemOrMacro> {
70 loop {
71 let n = self.0.next()?;
72 match_ast! {
73 match n {
74 ast::ModuleItem(it) => { return Some(ItemOrMacro::Item(it)) },
75 ast::MacroCall(it) => { return Some(ItemOrMacro::Macro(it)) },
76 _ => {},
77 }
78 }
79 }
80 }
81} 52}
82 53
83pub trait TypeParamsOwner: AstNode { 54pub trait TypeParamsOwner: AstNode {
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 1e2fb8b91..1015ce0a6 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -14,9 +14,12 @@ macro_rules! impl_froms {
14 } 14 }
15} 15}
16 16
17use std::fmt; 17use std::{
18 fmt::{self, Debug},
19 panic::RefUnwindSafe,
20};
18 21
19use smol_str::SmolStr; 22pub use smol_str::SmolStr;
20 23
21/// Represents identity of the token. 24/// Represents identity of the token.
22/// 25///
@@ -184,3 +187,11 @@ impl Subtree {
184} 187}
185 188
186pub mod buffer; 189pub mod buffer;
190
191#[derive(Debug, PartialEq, Eq)]
192pub enum ExpansionError {}
193
194pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe {
195 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
196 -> Result<Subtree, ExpansionError>;
197}
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 54e2fa1a7..832f04226 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -7,7 +7,9 @@ use anyhow::Result;
7use crossbeam_channel::{unbounded, Receiver}; 7use crossbeam_channel::{unbounded, Receiver};
8use ra_db::{ExternSourceId, FileId, SourceRootId}; 8use ra_db::{ExternSourceId, FileId, SourceRootId};
9use ra_ide::{AnalysisChange, AnalysisHost}; 9use ra_ide::{AnalysisChange, AnalysisHost};
10use ra_project_model::{get_rustc_cfg_options, CargoFeatures, PackageRoot, ProjectWorkspace}; 10use ra_project_model::{
11 get_rustc_cfg_options, CargoFeatures, PackageRoot, ProcMacroClient, ProjectWorkspace,
12};
11use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; 13use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
12use rustc_hash::{FxHashMap, FxHashSet}; 14use rustc_hash::{FxHashMap, FxHashSet};
13 15
@@ -67,7 +69,9 @@ pub(crate) fn load_cargo(
67 (source_root_id, project_root) 69 (source_root_id, project_root)
68 }) 70 })
69 .collect::<FxHashMap<_, _>>(); 71 .collect::<FxHashMap<_, _>>();
70 let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs); 72
73 let proc_macro_client = ProcMacroClient::dummy();
74 let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client);
71 Ok((host, source_roots)) 75 Ok((host, source_roots))
72} 76}
73 77
@@ -77,6 +81,7 @@ pub(crate) fn load(
77 vfs: &mut Vfs, 81 vfs: &mut Vfs,
78 receiver: Receiver<VfsTask>, 82 receiver: Receiver<VfsTask>,
79 extern_dirs: FxHashSet<PathBuf>, 83 extern_dirs: FxHashSet<PathBuf>,
84 proc_macro_client: &ProcMacroClient,
80) -> AnalysisHost { 85) -> AnalysisHost {
81 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); 86 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
82 let mut host = AnalysisHost::new(lru_cap); 87 let mut host = AnalysisHost::new(lru_cap);
@@ -143,12 +148,16 @@ pub(crate) fn load(
143 opts 148 opts
144 }; 149 };
145 150
146 let crate_graph = 151 let crate_graph = ws.to_crate_graph(
147 ws.to_crate_graph(&default_cfg_options, &extern_source_roots, &mut |path: &Path| { 152 &default_cfg_options,
153 &extern_source_roots,
154 proc_macro_client,
155 &mut |path: &Path| {
148 let vfs_file = vfs.load(path); 156 let vfs_file = vfs.load(path);
149 log::debug!("vfs file {:?} -> {:?}", path, vfs_file); 157 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
150 vfs_file.map(vfs_file_to_id) 158 vfs_file.map(vfs_file_to_id)
151 }); 159 },
160 );
152 log::debug!("crate graph: {:?}", crate_graph); 161 log::debug!("crate graph: {:?}", crate_graph);
153 analysis_change.set_crate_graph(crate_graph); 162 analysis_change.set_crate_graph(crate_graph);
154 163
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index c4244fee2..de85bb017 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -16,7 +16,7 @@ use ra_ide::{
16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, InlayHintsOptions, LibraryData, 16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, InlayHintsOptions, LibraryData,
17 SourceRootId, 17 SourceRootId,
18}; 18};
19use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; 19use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace};
20use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 20use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
21use relative_path::RelativePathBuf; 21use relative_path::RelativePathBuf;
22 22
@@ -150,9 +150,19 @@ impl WorldState {
150 vfs_file.map(|f| FileId(f.0)) 150 vfs_file.map(|f| FileId(f.0))
151 }; 151 };
152 152
153 let proc_macro_client =
154 ProcMacroClient::extern_process(std::path::Path::new("ra_proc_macro_srv"));
155
153 workspaces 156 workspaces
154 .iter() 157 .iter()
155 .map(|ws| ws.to_crate_graph(&default_cfg_options, &extern_source_roots, &mut load)) 158 .map(|ws| {
159 ws.to_crate_graph(
160 &default_cfg_options,
161 &extern_source_roots,
162 &proc_macro_client,
163 &mut load,
164 )
165 })
156 .for_each(|graph| { 166 .for_each(|graph| {
157 crate_graph.extend(graph); 167 crate_graph.extend(graph);
158 }); 168 });
diff --git a/docs/user/assists.md b/docs/user/assists.md
index f3ce6b0e0..b2568a954 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -597,6 +597,29 @@ use std::collections::HashMap;
597fn process(map: HashMap<String, String>) {} 597fn process(map: HashMap<String, String>) {}
598``` 598```
599 599
600## `replace_unwrap_with_match`
601
602Replaces `unwrap` a `match` expression. Works for Result and Option.
603
604```rust
605// BEFORE
606enum Result<T, E> { Ok(T), Err(E) }
607fn main() {
608 let x: Result<i32, i32> = Result::Ok(92);
609 let y = x.┃unwrap();
610}
611
612// AFTER
613enum Result<T, E> { Ok(T), Err(E) }
614fn main() {
615 let x: Result<i32, i32> = Result::Ok(92);
616 let y = match x {
617 Ok(a) => a,
618 _ => unreachable!(),
619 };
620}
621```
622
600## `split_import` 623## `split_import`
601 624
602Wraps the tail of import into braces. 625Wraps the tail of import into braces.
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
index 1c6ea399b..09daa3402 100644
--- a/editors/code/src/commands/analyzer_status.ts
+++ b/editors/code/src/commands/analyzer_status.ts
@@ -5,7 +5,7 @@ import { Ctx, Cmd } from '../ctx';
5 5
6// Shows status of rust-analyzer (for debugging) 6// Shows status of rust-analyzer (for debugging)
7export function analyzerStatus(ctx: Ctx): Cmd { 7export function analyzerStatus(ctx: Ctx): Cmd {
8 let poller: NodeJS.Timer | null = null; 8 let poller: NodeJS.Timer | undefined = undefined;
9 const tdcp = new TextDocumentContentProvider(ctx); 9 const tdcp = new TextDocumentContentProvider(ctx);
10 10
11 ctx.pushCleanup( 11 ctx.pushCleanup(
@@ -17,41 +17,32 @@ export function analyzerStatus(ctx: Ctx): Cmd {
17 17
18 ctx.pushCleanup({ 18 ctx.pushCleanup({
19 dispose() { 19 dispose() {
20 if (poller != null) { 20 if (poller !== undefined) {
21 clearInterval(poller); 21 clearInterval(poller);
22 } 22 }
23 }, 23 },
24 }); 24 });
25 25
26 return async function handle() { 26 return async () => {
27 if (poller == null) { 27 if (poller === undefined) {
28 poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); 28 poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
29 } 29 }
30 const document = await vscode.workspace.openTextDocument(tdcp.uri); 30 const document = await vscode.workspace.openTextDocument(tdcp.uri);
31 return vscode.window.showTextDocument( 31 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
32 document,
33 vscode.ViewColumn.Two,
34 true,
35 );
36 }; 32 };
37} 33}
38 34
39class TextDocumentContentProvider 35class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
40 implements vscode.TextDocumentContentProvider { 36 readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
41 uri = vscode.Uri.parse('rust-analyzer-status://status'); 37 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
42 eventEmitter = new vscode.EventEmitter<vscode.Uri>();
43 38
44 constructor(private readonly ctx: Ctx) { 39 constructor(private readonly ctx: Ctx) {
45 } 40 }
46 41
47 provideTextDocumentContent( 42 provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
48 _uri: vscode.Uri, 43 if (!vscode.window.activeTextEditor) return '';
49 ): vscode.ProviderResult<string> {
50 const editor = vscode.window.activeTextEditor;
51 const client = this.ctx.client;
52 if (!editor || !client) return '';
53 44
54 return client.sendRequest(ra.analyzerStatus, null); 45 return this.ctx.client.sendRequest(ra.analyzerStatus, null);
55 } 46 }
56 47
57 get onDidChange(): vscode.Event<vscode.Uri> { 48 get onDidChange(): vscode.Event<vscode.Uri> {
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 9b58aad97..99bd60198 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -566,6 +566,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
566 ConstDef, 566 ConstDef,
567 StaticDef, 567 StaticDef,
568 Module, 568 Module,
569 MacroCall,
569 } 570 }
570 571
571 enum ImplItem: AttrsOwner { 572 enum ImplItem: AttrsOwner {