diff options
114 files changed, 2439 insertions, 1985 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 919d58925..7b9fbe6b8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -15,12 +15,11 @@ env: | |||
15 | RUSTUP_MAX_RETRIES: 10 | 15 | RUSTUP_MAX_RETRIES: 10 |
16 | 16 | ||
17 | jobs: | 17 | jobs: |
18 | dist: | 18 | dist-windows: |
19 | name: dist | 19 | name: dist (Windows) |
20 | runs-on: ${{ matrix.os }} | 20 | runs-on: windows-latest |
21 | strategy: | 21 | env: |
22 | matrix: | 22 | RA_TARGET: x86_64-pc-windows-msvc |
23 | os: [ubuntu-16.04, windows-latest, macos-latest] | ||
24 | 23 | ||
25 | steps: | 24 | steps: |
26 | - name: Checkout repository | 25 | - name: Checkout repository |
@@ -30,8 +29,7 @@ jobs: | |||
30 | # which takes a long time. The fastest way to do this is to rename the | 29 | # which takes a long time. The fastest way to do this is to rename the |
31 | # existing folder, as deleting it takes about as much time as not doing | 30 | # existing folder, as deleting it takes about as much time as not doing |
32 | # anything and just updating rust-docs. | 31 | # anything and just updating rust-docs. |
33 | - name: Rename existing rust toolchain (Windows) | 32 | - name: Rename existing rust toolchain |
34 | if: matrix.os == 'windows-latest' | ||
35 | run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old | 33 | run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old |
36 | 34 | ||
37 | - name: Install Rust toolchain | 35 | - name: Install Rust toolchain |
@@ -41,38 +39,112 @@ jobs: | |||
41 | profile: minimal | 39 | profile: minimal |
42 | override: true | 40 | override: true |
43 | 41 | ||
42 | - name: Dist | ||
43 | run: cargo xtask dist | ||
44 | |||
45 | - name: Upload artifacts | ||
46 | uses: actions/upload-artifact@v1 | ||
47 | with: | ||
48 | name: dist-windows-latest | ||
49 | path: ./dist | ||
50 | |||
51 | dist-ubuntu: | ||
52 | name: dist (Ubuntu 16.04) | ||
53 | runs-on: ubuntu-16.04 | ||
54 | env: | ||
55 | RA_TARGET: x86_64-unknown-linux-gnu | ||
56 | |||
57 | steps: | ||
58 | - name: Checkout repository | ||
59 | uses: actions/checkout@v2 | ||
60 | |||
61 | - name: Install Rust toolchain | ||
62 | uses: actions-rs/toolchain@v1 | ||
63 | with: | ||
64 | toolchain: stable | ||
65 | profile: minimal | ||
66 | override: true | ||
67 | |||
44 | - name: Install Nodejs | 68 | - name: Install Nodejs |
45 | if: matrix.os == 'ubuntu-16.04' | ||
46 | uses: actions/setup-node@v1 | 69 | uses: actions/setup-node@v1 |
47 | with: | 70 | with: |
48 | node-version: 12.x | 71 | node-version: 12.x |
49 | 72 | ||
50 | - name: Dist | 73 | - name: Dist |
51 | if: matrix.os == 'ubuntu-16.04' && github.ref == 'refs/heads/release' | 74 | if: github.ref == 'refs/heads/release' |
52 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER | 75 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER |
53 | 76 | ||
54 | - name: Dist | 77 | - name: Dist |
55 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' | 78 | if: github.ref != 'refs/heads/release' |
56 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly | 79 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly |
57 | 80 | ||
81 | - name: Nightly analysis-stats check | ||
82 | if: github.ref != 'refs/heads/release' | ||
83 | run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats . | ||
84 | |||
85 | - name: Upload artifacts | ||
86 | uses: actions/upload-artifact@v1 | ||
87 | with: | ||
88 | name: dist-ubuntu-16.04 | ||
89 | path: ./dist | ||
90 | |||
91 | dist-macos-latest: | ||
92 | name: dist (MacOS latest) | ||
93 | runs-on: macos-latest | ||
94 | env: | ||
95 | RA_TARGET: x86_64-apple-darwin | ||
96 | |||
97 | steps: | ||
98 | - name: Checkout repository | ||
99 | uses: actions/checkout@v2 | ||
100 | |||
101 | - name: Install Rust toolchain | ||
102 | uses: actions-rs/toolchain@v1 | ||
103 | with: | ||
104 | toolchain: stable | ||
105 | profile: minimal | ||
106 | override: true | ||
107 | |||
58 | - name: Dist | 108 | - name: Dist |
59 | if: matrix.os != 'ubuntu-16.04' | ||
60 | run: cargo xtask dist | 109 | run: cargo xtask dist |
61 | 110 | ||
62 | - name: Nightly analysis-stats check | 111 | - name: Upload artifacts |
63 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' | 112 | uses: actions/upload-artifact@v1 |
64 | run: ./dist/rust-analyzer-linux analysis-stats . | 113 | with: |
114 | name: dist-macos-latest | ||
115 | path: ./dist | ||
116 | |||
117 | dist-macos-11: | ||
118 | name: dist (MacOS 11.0) | ||
119 | runs-on: macos-11.0 | ||
120 | env: | ||
121 | RA_TARGET: aarch64-apple-darwin | ||
122 | |||
123 | steps: | ||
124 | - name: Checkout repository | ||
125 | uses: actions/checkout@v2 | ||
126 | |||
127 | - name: Install Rust toolchain (beta) | ||
128 | uses: actions-rs/toolchain@v1 | ||
129 | with: | ||
130 | toolchain: beta | ||
131 | target: aarch64-apple-darwin | ||
132 | profile: minimal | ||
133 | override: true | ||
134 | |||
135 | - name: Dist | ||
136 | run: cargo xtask dist | ||
65 | 137 | ||
66 | - name: Upload artifacts | 138 | - name: Upload artifacts |
67 | uses: actions/upload-artifact@v1 | 139 | uses: actions/upload-artifact@v1 |
68 | with: | 140 | with: |
69 | name: dist-${{ matrix.os }} | 141 | name: dist-macos-11.0 |
70 | path: ./dist | 142 | path: ./dist |
71 | 143 | ||
72 | publish: | 144 | publish: |
73 | name: publish | 145 | name: publish |
74 | runs-on: ubuntu-16.04 | 146 | runs-on: ubuntu-16.04 |
75 | needs: ['dist'] | 147 | needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11'] |
76 | steps: | 148 | steps: |
77 | - name: Install Nodejs | 149 | - name: Install Nodejs |
78 | uses: actions/setup-node@v1 | 150 | uses: actions/setup-node@v1 |
@@ -93,6 +165,10 @@ jobs: | |||
93 | 165 | ||
94 | - uses: actions/download-artifact@v1 | 166 | - uses: actions/download-artifact@v1 |
95 | with: | 167 | with: |
168 | name: dist-macos-11.0 | ||
169 | path: dist | ||
170 | - uses: actions/download-artifact@v1 | ||
171 | with: | ||
96 | name: dist-macos-latest | 172 | name: dist-macos-latest |
97 | path: dist | 173 | path: dist |
98 | - uses: actions/download-artifact@v1 | 174 | - uses: actions/download-artifact@v1 |
@@ -103,7 +179,7 @@ jobs: | |||
103 | with: | 179 | with: |
104 | name: dist-windows-latest | 180 | name: dist-windows-latest |
105 | path: dist | 181 | path: dist |
106 | - run: ls -all ./dist | 182 | - run: ls -al ./dist |
107 | 183 | ||
108 | - name: Publish Release | 184 | - name: Publish Release |
109 | uses: ./.github/actions/github-release | 185 | uses: ./.github/actions/github-release |
diff --git a/Cargo.lock b/Cargo.lock index 1051c4ec6..fd04ec3c5 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | |||
168 | 168 | ||
169 | [[package]] | 169 | [[package]] |
170 | name = "chalk-derive" | 170 | name = "chalk-derive" |
171 | version = "0.43.0" | 171 | version = "0.45.0" |
172 | source = "registry+https://github.com/rust-lang/crates.io-index" | 172 | source = "registry+https://github.com/rust-lang/crates.io-index" |
173 | checksum = "e2d9e0c8adcced1ab0fea5cb8a38647922893d5b495e363e1814299fd380469b" | 173 | checksum = "ec7dacf94958d1a930b95d049d9443860859af59eadc77849392093eb577bcee" |
174 | dependencies = [ | 174 | dependencies = [ |
175 | "proc-macro2", | 175 | "proc-macro2", |
176 | "quote", | 176 | "quote", |
@@ -180,19 +180,20 @@ dependencies = [ | |||
180 | 180 | ||
181 | [[package]] | 181 | [[package]] |
182 | name = "chalk-ir" | 182 | name = "chalk-ir" |
183 | version = "0.43.0" | 183 | version = "0.45.0" |
184 | source = "registry+https://github.com/rust-lang/crates.io-index" | 184 | source = "registry+https://github.com/rust-lang/crates.io-index" |
185 | checksum = "c5218266a5709bc4943de997e64d3fab41c9e9f68efd54a898de53135e987bd3" | 185 | checksum = "a1a5b38ede247def17da87f4badb62396a5753db6048e2011d3089d8b3796c67" |
186 | dependencies = [ | 186 | dependencies = [ |
187 | "bitflags", | ||
187 | "chalk-derive", | 188 | "chalk-derive", |
188 | "lazy_static", | 189 | "lazy_static", |
189 | ] | 190 | ] |
190 | 191 | ||
191 | [[package]] | 192 | [[package]] |
192 | name = "chalk-recursive" | 193 | name = "chalk-recursive" |
193 | version = "0.43.0" | 194 | version = "0.45.0" |
194 | source = "registry+https://github.com/rust-lang/crates.io-index" | 195 | source = "registry+https://github.com/rust-lang/crates.io-index" |
195 | checksum = "ed8f34f13fd4f30251f9f6f1dc56f80363201390ecbcac2fdfc8e33036cd9c4a" | 196 | checksum = "7a18db146d7a023edc20ad094e8c2284451f7888719645004979617d1f17c041" |
196 | dependencies = [ | 197 | dependencies = [ |
197 | "chalk-derive", | 198 | "chalk-derive", |
198 | "chalk-ir", | 199 | "chalk-ir", |
@@ -203,9 +204,9 @@ dependencies = [ | |||
203 | 204 | ||
204 | [[package]] | 205 | [[package]] |
205 | name = "chalk-solve" | 206 | name = "chalk-solve" |
206 | version = "0.43.0" | 207 | version = "0.45.0" |
207 | source = "registry+https://github.com/rust-lang/crates.io-index" | 208 | source = "registry+https://github.com/rust-lang/crates.io-index" |
208 | checksum = "379c9f584488346044709d4c638c38d61a06fe593d4de2ac5f15fd2b0ba4cd9d" | 209 | checksum = "7f73e0de04a0f394e47ed8118e00541bcf681d7c3c2ef500fa743eb4cf3a4850" |
209 | dependencies = [ | 210 | dependencies = [ |
210 | "chalk-derive", | 211 | "chalk-derive", |
211 | "chalk-ir", | 212 | "chalk-ir", |
@@ -507,9 +508,9 @@ checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" | |||
507 | 508 | ||
508 | [[package]] | 509 | [[package]] |
509 | name = "heck" | 510 | name = "heck" |
510 | version = "0.3.1" | 511 | version = "0.3.2" |
511 | source = "registry+https://github.com/rust-lang/crates.io-index" | 512 | source = "registry+https://github.com/rust-lang/crates.io-index" |
512 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" | 513 | checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" |
513 | dependencies = [ | 514 | dependencies = [ |
514 | "unicode-segmentation", | 515 | "unicode-segmentation", |
515 | ] | 516 | ] |
@@ -1074,9 +1075,9 @@ dependencies = [ | |||
1074 | 1075 | ||
1075 | [[package]] | 1076 | [[package]] |
1076 | name = "parking_lot_core" | 1077 | name = "parking_lot_core" |
1077 | version = "0.8.1" | 1078 | version = "0.8.2" |
1078 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1079 | checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0" | 1080 | checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" |
1080 | dependencies = [ | 1081 | dependencies = [ |
1081 | "cfg-if 1.0.0", | 1082 | "cfg-if 1.0.0", |
1082 | "instant", | 1083 | "instant", |
@@ -1251,9 +1252,9 @@ dependencies = [ | |||
1251 | 1252 | ||
1252 | [[package]] | 1253 | [[package]] |
1253 | name = "quote" | 1254 | name = "quote" |
1254 | version = "1.0.7" | 1255 | version = "1.0.8" |
1255 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1256 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" | 1257 | checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" |
1257 | dependencies = [ | 1258 | dependencies = [ |
1258 | "proc-macro2", | 1259 | "proc-macro2", |
1259 | ] | 1260 | ] |
@@ -1358,6 +1359,7 @@ dependencies = [ | |||
1358 | "rustc-hash", | 1359 | "rustc-hash", |
1359 | "serde", | 1360 | "serde", |
1360 | "serde_json", | 1361 | "serde_json", |
1362 | "serde_path_to_error", | ||
1361 | "ssr", | 1363 | "ssr", |
1362 | "stdx", | 1364 | "stdx", |
1363 | "syntax", | 1365 | "syntax", |
@@ -1376,9 +1378,9 @@ dependencies = [ | |||
1376 | 1378 | ||
1377 | [[package]] | 1379 | [[package]] |
1378 | name = "rustc-ap-rustc_lexer" | 1380 | name = "rustc-ap-rustc_lexer" |
1379 | version = "691.0.0" | 1381 | version = "695.0.0" |
1380 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1381 | checksum = "44bc89d9ca7a78fb82e103b389362c55f03800745f8ba14e068b805cfaf783ec" | 1383 | checksum = "390bad134705b0bff02cd9541ac66df751a91c3cc734c3369cd6151ca269caed" |
1382 | dependencies = [ | 1384 | dependencies = [ |
1383 | "unicode-xid", | 1385 | "unicode-xid", |
1384 | ] | 1386 | ] |
@@ -1527,6 +1529,15 @@ dependencies = [ | |||
1527 | ] | 1529 | ] |
1528 | 1530 | ||
1529 | [[package]] | 1531 | [[package]] |
1532 | name = "serde_path_to_error" | ||
1533 | version = "0.1.4" | ||
1534 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1535 | checksum = "42f6109f0506e20f7e0f910e51a0079acf41da8e0694e6442527c4ddf5a2b158" | ||
1536 | dependencies = [ | ||
1537 | "serde", | ||
1538 | ] | ||
1539 | |||
1540 | [[package]] | ||
1530 | name = "serde_repr" | 1541 | name = "serde_repr" |
1531 | version = "0.1.6" | 1542 | version = "0.1.6" |
1532 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1588,9 +1599,9 @@ version = "0.0.0" | |||
1588 | 1599 | ||
1589 | [[package]] | 1600 | [[package]] |
1590 | name = "syn" | 1601 | name = "syn" |
1591 | version = "1.0.54" | 1602 | version = "1.0.55" |
1592 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1593 | checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" | 1604 | checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" |
1594 | dependencies = [ | 1605 | dependencies = [ |
1595 | "proc-macro2", | 1606 | "proc-macro2", |
1596 | "quote", | 1607 | "quote", |
@@ -1827,9 +1838,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" | |||
1827 | 1838 | ||
1828 | [[package]] | 1839 | [[package]] |
1829 | name = "ungrammar" | 1840 | name = "ungrammar" |
1830 | version = "1.4.0" | 1841 | version = "1.5.0" |
1831 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1832 | checksum = "68951379f3ced25754472ca5addbf74d7dab58c9818f49290a3d8caa3ab44fb7" | 1843 | checksum = "c11bffada52edc8f2a56160b286ea4640acf90ffcb21bded361ccb8ed43a1457" |
1833 | 1844 | ||
1834 | [[package]] | 1845 | [[package]] |
1835 | name = "unicase" | 1846 | name = "unicase" |
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 69499ea32..4f59d39a9 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -4,10 +4,10 @@ use std::mem; | |||
4 | 4 | ||
5 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use ide_db::base_db::{FileId, FileRange}; | 7 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange}; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | label::Label, | 9 | label::Label, |
10 | source_change::{SourceChange, SourceFileEdit}, | 10 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use syntax::{ | 13 | use syntax::{ |
@@ -19,7 +19,7 @@ use text_edit::{TextEdit, TextEditBuilder}; | |||
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | assist_config::{AssistConfig, SnippetCap}, | 21 | assist_config::{AssistConfig, SnippetCap}, |
22 | Assist, AssistId, AssistKind, GroupLabel, ResolvedAssist, | 22 | Assist, AssistId, AssistKind, GroupLabel, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 25 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
@@ -105,46 +105,23 @@ impl<'a> AssistContext<'a> { | |||
105 | pub(crate) struct Assists { | 105 | pub(crate) struct Assists { |
106 | resolve: bool, | 106 | resolve: bool, |
107 | file: FileId, | 107 | file: FileId, |
108 | buf: Vec<(Assist, Option<SourceChange>)>, | 108 | buf: Vec<Assist>, |
109 | allowed: Option<Vec<AssistKind>>, | 109 | allowed: Option<Vec<AssistKind>>, |
110 | } | 110 | } |
111 | 111 | ||
112 | impl Assists { | 112 | impl Assists { |
113 | pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists { | 113 | pub(crate) fn new(ctx: &AssistContext, resolve: bool) -> Assists { |
114 | Assists { | 114 | Assists { |
115 | resolve: true, | 115 | resolve, |
116 | file: ctx.frange.file_id, | 116 | file: ctx.frange.file_id, |
117 | buf: Vec::new(), | 117 | buf: Vec::new(), |
118 | allowed: ctx.config.allowed.clone(), | 118 | allowed: ctx.config.allowed.clone(), |
119 | } | 119 | } |
120 | } | 120 | } |
121 | 121 | ||
122 | pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists { | 122 | pub(crate) fn finish(mut self) -> Vec<Assist> { |
123 | Assists { | 123 | self.buf.sort_by_key(|assist| assist.target.len()); |
124 | resolve: false, | 124 | self.buf |
125 | file: ctx.frange.file_id, | ||
126 | buf: Vec::new(), | ||
127 | allowed: ctx.config.allowed.clone(), | ||
128 | } | ||
129 | } | ||
130 | |||
131 | pub(crate) fn finish_unresolved(self) -> Vec<Assist> { | ||
132 | assert!(!self.resolve); | ||
133 | self.finish() | ||
134 | .into_iter() | ||
135 | .map(|(label, edit)| { | ||
136 | assert!(edit.is_none()); | ||
137 | label | ||
138 | }) | ||
139 | .collect() | ||
140 | } | ||
141 | |||
142 | pub(crate) fn finish_resolved(self) -> Vec<ResolvedAssist> { | ||
143 | assert!(self.resolve); | ||
144 | self.finish() | ||
145 | .into_iter() | ||
146 | .map(|(label, edit)| ResolvedAssist { assist: label, source_change: edit.unwrap() }) | ||
147 | .collect() | ||
148 | } | 125 | } |
149 | 126 | ||
150 | pub(crate) fn add( | 127 | pub(crate) fn add( |
@@ -158,7 +135,7 @@ impl Assists { | |||
158 | return None; | 135 | return None; |
159 | } | 136 | } |
160 | let label = Label::new(label.into()); | 137 | let label = Label::new(label.into()); |
161 | let assist = Assist { id, label, group: None, target }; | 138 | let assist = Assist { id, label, group: None, target, source_change: None }; |
162 | self.add_impl(assist, f) | 139 | self.add_impl(assist, f) |
163 | } | 140 | } |
164 | 141 | ||
@@ -174,11 +151,11 @@ impl Assists { | |||
174 | return None; | 151 | return None; |
175 | } | 152 | } |
176 | let label = Label::new(label.into()); | 153 | let label = Label::new(label.into()); |
177 | let assist = Assist { id, label, group: Some(group.clone()), target }; | 154 | let assist = Assist { id, label, group: Some(group.clone()), target, source_change: None }; |
178 | self.add_impl(assist, f) | 155 | self.add_impl(assist, f) |
179 | } | 156 | } |
180 | 157 | ||
181 | fn add_impl(&mut self, assist: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 158 | fn add_impl(&mut self, mut assist: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
182 | let source_change = if self.resolve { | 159 | let source_change = if self.resolve { |
183 | let mut builder = AssistBuilder::new(self.file); | 160 | let mut builder = AssistBuilder::new(self.file); |
184 | f(&mut builder); | 161 | f(&mut builder); |
@@ -186,16 +163,12 @@ impl Assists { | |||
186 | } else { | 163 | } else { |
187 | None | 164 | None |
188 | }; | 165 | }; |
166 | assist.source_change = source_change.clone(); | ||
189 | 167 | ||
190 | self.buf.push((assist, source_change)); | 168 | self.buf.push(assist); |
191 | Some(()) | 169 | Some(()) |
192 | } | 170 | } |
193 | 171 | ||
194 | fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> { | ||
195 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); | ||
196 | self.buf | ||
197 | } | ||
198 | |||
199 | fn is_allowed(&self, id: &AssistId) -> bool { | 172 | fn is_allowed(&self, id: &AssistId) -> bool { |
200 | match &self.allowed { | 173 | match &self.allowed { |
201 | Some(allowed) => allowed.iter().any(|kind| kind.contains(id.1)), | 174 | Some(allowed) => allowed.iter().any(|kind| kind.contains(id.1)), |
@@ -209,6 +182,7 @@ pub(crate) struct AssistBuilder { | |||
209 | file_id: FileId, | 182 | file_id: FileId, |
210 | is_snippet: bool, | 183 | is_snippet: bool, |
211 | source_file_edits: Vec<SourceFileEdit>, | 184 | source_file_edits: Vec<SourceFileEdit>, |
185 | file_system_edits: Vec<FileSystemEdit>, | ||
212 | } | 186 | } |
213 | 187 | ||
214 | impl AssistBuilder { | 188 | impl AssistBuilder { |
@@ -218,6 +192,7 @@ impl AssistBuilder { | |||
218 | file_id, | 192 | file_id, |
219 | is_snippet: false, | 193 | is_snippet: false, |
220 | source_file_edits: Vec::default(), | 194 | source_file_edits: Vec::default(), |
195 | file_system_edits: Vec::default(), | ||
221 | } | 196 | } |
222 | } | 197 | } |
223 | 198 | ||
@@ -282,12 +257,17 @@ impl AssistBuilder { | |||
282 | algo::diff(&node, &new).into_text_edit(&mut self.edit); | 257 | algo::diff(&node, &new).into_text_edit(&mut self.edit); |
283 | } | 258 | } |
284 | } | 259 | } |
260 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { | ||
261 | let file_system_edit = | ||
262 | FileSystemEdit::CreateFile { dst: dst.clone(), initial_contents: content.into() }; | ||
263 | self.file_system_edits.push(file_system_edit); | ||
264 | } | ||
285 | 265 | ||
286 | fn finish(mut self) -> SourceChange { | 266 | fn finish(mut self) -> SourceChange { |
287 | self.commit(); | 267 | self.commit(); |
288 | SourceChange { | 268 | SourceChange { |
289 | source_file_edits: mem::take(&mut self.source_file_edits), | 269 | source_file_edits: mem::take(&mut self.source_file_edits), |
290 | file_system_edits: Default::default(), | 270 | file_system_edits: mem::take(&mut self.file_system_edits), |
291 | is_snippet: self.is_snippet, | 271 | is_snippet: self.is_snippet, |
292 | } | 272 | } |
293 | } | 273 | } |
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index e413505d3..7df05b841 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | // | 15 | // |
16 | // ``` | 16 | // ``` |
17 | // trait Trait<T> { | 17 | // trait Trait<T> { |
18 | // Type X; | 18 | // type X; |
19 | // fn foo(&self) -> T; | 19 | // fn foo(&self) -> T; |
20 | // fn bar(&self) {} | 20 | // fn bar(&self) {} |
21 | // } | 21 | // } |
@@ -27,14 +27,16 @@ use crate::{ | |||
27 | // -> | 27 | // -> |
28 | // ``` | 28 | // ``` |
29 | // trait Trait<T> { | 29 | // trait Trait<T> { |
30 | // Type X; | 30 | // type X; |
31 | // fn foo(&self) -> T; | 31 | // fn foo(&self) -> T; |
32 | // fn bar(&self) {} | 32 | // fn bar(&self) {} |
33 | // } | 33 | // } |
34 | // | 34 | // |
35 | // impl Trait<u32> for () { | 35 | // impl Trait<u32> for () { |
36 | // $0type X; | ||
37 | // | ||
36 | // fn foo(&self) -> u32 { | 38 | // fn foo(&self) -> u32 { |
37 | // ${0:todo!()} | 39 | // todo!() |
38 | // } | 40 | // } |
39 | // } | 41 | // } |
40 | // ``` | 42 | // ``` |
@@ -54,13 +56,13 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
54 | // | 56 | // |
55 | // ``` | 57 | // ``` |
56 | // trait Trait { | 58 | // trait Trait { |
57 | // Type X; | 59 | // type X; |
58 | // fn foo(&self); | 60 | // fn foo(&self); |
59 | // fn bar(&self) {} | 61 | // fn bar(&self) {} |
60 | // } | 62 | // } |
61 | // | 63 | // |
62 | // impl Trait for () { | 64 | // impl Trait for () { |
63 | // Type X = (); | 65 | // type X = (); |
64 | // fn foo(&self) {}<|> | 66 | // fn foo(&self) {}<|> |
65 | // | 67 | // |
66 | // } | 68 | // } |
@@ -68,13 +70,13 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
68 | // -> | 70 | // -> |
69 | // ``` | 71 | // ``` |
70 | // trait Trait { | 72 | // trait Trait { |
71 | // Type X; | 73 | // type X; |
72 | // fn foo(&self); | 74 | // fn foo(&self); |
73 | // fn bar(&self) {} | 75 | // fn bar(&self) {} |
74 | // } | 76 | // } |
75 | // | 77 | // |
76 | // impl Trait for () { | 78 | // impl Trait for () { |
77 | // Type X = (); | 79 | // type X = (); |
78 | // fn foo(&self) {} | 80 | // fn foo(&self) {} |
79 | // | 81 | // |
80 | // $0fn bar(&self) {} | 82 | // $0fn bar(&self) {} |
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs new file mode 100644 index 000000000..50bf67ef7 --- /dev/null +++ b/crates/assists/src/handlers/extract_module_to_file.rs | |||
@@ -0,0 +1,133 @@ | |||
1 | use ast::edit::IndentLevel; | ||
2 | use ide_db::base_db::AnchoredPathBuf; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, NameOwner}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | |||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
9 | |||
10 | // Assist: extract_module_to_file | ||
11 | // | ||
12 | // This assist extract module to file. | ||
13 | // | ||
14 | // ``` | ||
15 | // mod foo {<|> | ||
16 | // fn t() {} | ||
17 | // } | ||
18 | // ``` | ||
19 | // -> | ||
20 | // ``` | ||
21 | // mod foo; | ||
22 | // ``` | ||
23 | pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
24 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; | ||
25 | let module_name = module_ast.name()?; | ||
26 | |||
27 | let module_def = ctx.sema.to_def(&module_ast)?; | ||
28 | let parent_module = module_def.parent(ctx.db())?; | ||
29 | |||
30 | let module_items = module_ast.item_list()?; | ||
31 | let target = module_ast.syntax().text_range(); | ||
32 | let anchor_file_id = ctx.frange.file_id; | ||
33 | |||
34 | acc.add( | ||
35 | AssistId("extract_module_to_file", AssistKind::RefactorExtract), | ||
36 | "Extract module to file", | ||
37 | target, | ||
38 | |builder| { | ||
39 | let path = { | ||
40 | let dir = match parent_module.name(ctx.db()) { | ||
41 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), | ||
42 | _ => String::new(), | ||
43 | }; | ||
44 | format!("./{}{}.rs", dir, module_name) | ||
45 | }; | ||
46 | let contents = { | ||
47 | let items = module_items.dedent(IndentLevel(1)).to_string(); | ||
48 | let mut items = | ||
49 | items.trim_start_matches('{').trim_end_matches('}').trim().to_string(); | ||
50 | if !items.is_empty() { | ||
51 | items.push('\n'); | ||
52 | } | ||
53 | items | ||
54 | }; | ||
55 | |||
56 | builder.replace(target, format!("mod {};", module_name)); | ||
57 | |||
58 | let dst = AnchoredPathBuf { anchor: anchor_file_id, path }; | ||
59 | builder.create_file(dst, contents); | ||
60 | }, | ||
61 | ) | ||
62 | } | ||
63 | |||
64 | #[cfg(test)] | ||
65 | mod tests { | ||
66 | use crate::tests::check_assist; | ||
67 | |||
68 | use super::*; | ||
69 | |||
70 | #[test] | ||
71 | fn extract_from_root() { | ||
72 | check_assist( | ||
73 | extract_module_to_file, | ||
74 | r#" | ||
75 | mod tests {<|> | ||
76 | #[test] fn t() {} | ||
77 | } | ||
78 | "#, | ||
79 | r#" | ||
80 | //- /main.rs | ||
81 | mod tests; | ||
82 | //- /tests.rs | ||
83 | #[test] fn t() {} | ||
84 | "#, | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn extract_from_submodule() { | ||
90 | check_assist( | ||
91 | extract_module_to_file, | ||
92 | r#" | ||
93 | //- /main.rs | ||
94 | mod submod; | ||
95 | //- /submod.rs | ||
96 | mod inner<|> { | ||
97 | fn f() {} | ||
98 | } | ||
99 | fn g() {} | ||
100 | "#, | ||
101 | r#" | ||
102 | //- /submod.rs | ||
103 | mod inner; | ||
104 | fn g() {} | ||
105 | //- /submod/inner.rs | ||
106 | fn f() {} | ||
107 | "#, | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn extract_from_mod_rs() { | ||
113 | check_assist( | ||
114 | extract_module_to_file, | ||
115 | r#" | ||
116 | //- /main.rs | ||
117 | mod submodule; | ||
118 | //- /submodule/mod.rs | ||
119 | mod inner<|> { | ||
120 | fn f() {} | ||
121 | } | ||
122 | fn g() {} | ||
123 | "#, | ||
124 | r#" | ||
125 | //- /submodule/mod.rs | ||
126 | mod inner; | ||
127 | fn g() {} | ||
128 | //- /submodule/inner.rs | ||
129 | fn f() {} | ||
130 | "#, | ||
131 | ); | ||
132 | } | ||
133 | } | ||
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index 91e2f5c8c..f9c33b3f7 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs | |||
@@ -78,6 +78,15 @@ mod tests { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | #[test] | 80 | #[test] |
81 | fn invert_if_remove_not_parentheses() { | ||
82 | check_assist( | ||
83 | invert_if, | ||
84 | "fn f() { i<|>f !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", | ||
85 | "fn f() { if x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", | ||
86 | ) | ||
87 | } | ||
88 | |||
89 | #[test] | ||
81 | fn invert_if_remove_inequality() { | 90 | fn invert_if_remove_inequality() { |
82 | check_assist( | 91 | check_assist( |
83 | invert_if, | 92 | invert_if, |
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs index 1ff5e92b0..f72dd49ed 100644 --- a/crates/assists/src/handlers/remove_unused_param.rs +++ b/crates/assists/src/handlers/remove_unused_param.rs | |||
@@ -2,9 +2,10 @@ use ide_db::{defs::Definition, search::Reference}; | |||
2 | use syntax::{ | 2 | use syntax::{ |
3 | algo::find_node_at_range, | 3 | algo::find_node_at_range, |
4 | ast::{self, ArgListOwner}, | 4 | ast::{self, ArgListOwner}, |
5 | AstNode, SyntaxNode, TextRange, T, | 5 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | use SyntaxKind::WHITESPACE; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, | 11 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, |
@@ -56,7 +57,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
56 | "Remove unused parameter", | 57 | "Remove unused parameter", |
57 | param.syntax().text_range(), | 58 | param.syntax().text_range(), |
58 | |builder| { | 59 | |builder| { |
59 | builder.delete(range_with_coma(param.syntax())); | 60 | builder.delete(range_to_remove(param.syntax())); |
60 | for usage in fn_def.usages(&ctx.sema).all() { | 61 | for usage in fn_def.usages(&ctx.sema).all() { |
61 | process_usage(ctx, builder, usage, param_position); | 62 | process_usage(ctx, builder, usage, param_position); |
62 | } | 63 | } |
@@ -80,19 +81,34 @@ fn process_usage( | |||
80 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; | 81 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; |
81 | 82 | ||
82 | builder.edit_file(usage.file_range.file_id); | 83 | builder.edit_file(usage.file_range.file_id); |
83 | builder.delete(range_with_coma(arg.syntax())); | 84 | builder.delete(range_to_remove(arg.syntax())); |
84 | 85 | ||
85 | Some(()) | 86 | Some(()) |
86 | } | 87 | } |
87 | 88 | ||
88 | fn range_with_coma(node: &SyntaxNode) -> TextRange { | 89 | fn range_to_remove(node: &SyntaxNode) -> TextRange { |
89 | let up_to = next_prev().find_map(|dir| { | 90 | let up_to_comma = next_prev().find_map(|dir| { |
90 | node.siblings_with_tokens(dir) | 91 | node.siblings_with_tokens(dir) |
91 | .filter_map(|it| it.into_token()) | 92 | .filter_map(|it| it.into_token()) |
92 | .find(|it| it.kind() == T![,]) | 93 | .find(|it| it.kind() == T![,]) |
94 | .map(|it| (dir, it)) | ||
93 | }); | 95 | }); |
94 | let up_to = up_to.map_or(node.text_range(), |it| it.text_range()); | 96 | if let Some((dir, token)) = up_to_comma { |
95 | node.text_range().cover(up_to) | 97 | if node.next_sibling().is_some() { |
98 | let up_to_space = token | ||
99 | .siblings_with_tokens(dir) | ||
100 | .skip(1) | ||
101 | .take_while(|it| it.kind() == WHITESPACE) | ||
102 | .last() | ||
103 | .and_then(|it| it.into_token()); | ||
104 | return node | ||
105 | .text_range() | ||
106 | .cover(up_to_space.map_or(token.text_range(), |it| it.text_range())); | ||
107 | } | ||
108 | node.text_range().cover(token.text_range()) | ||
109 | } else { | ||
110 | node.text_range() | ||
111 | } | ||
96 | } | 112 | } |
97 | 113 | ||
98 | #[cfg(test)] | 114 | #[cfg(test)] |
@@ -119,6 +135,57 @@ fn b() { foo(9, ) } | |||
119 | } | 135 | } |
120 | 136 | ||
121 | #[test] | 137 | #[test] |
138 | fn remove_unused_first_param() { | ||
139 | check_assist( | ||
140 | remove_unused_param, | ||
141 | r#" | ||
142 | fn foo(<|>x: i32, y: i32) { y; } | ||
143 | fn a() { foo(1, 2) } | ||
144 | fn b() { foo(1, 2,) } | ||
145 | "#, | ||
146 | r#" | ||
147 | fn foo(y: i32) { y; } | ||
148 | fn a() { foo(2) } | ||
149 | fn b() { foo(2,) } | ||
150 | "#, | ||
151 | ); | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn remove_unused_single_param() { | ||
156 | check_assist( | ||
157 | remove_unused_param, | ||
158 | r#" | ||
159 | fn foo(<|>x: i32) { 0; } | ||
160 | fn a() { foo(1) } | ||
161 | fn b() { foo(1, ) } | ||
162 | "#, | ||
163 | r#" | ||
164 | fn foo() { 0; } | ||
165 | fn a() { foo() } | ||
166 | fn b() { foo( ) } | ||
167 | "#, | ||
168 | ); | ||
169 | } | ||
170 | |||
171 | #[test] | ||
172 | fn remove_unused_surrounded_by_parms() { | ||
173 | check_assist( | ||
174 | remove_unused_param, | ||
175 | r#" | ||
176 | fn foo(x: i32, <|>y: i32, z: i32) { x; } | ||
177 | fn a() { foo(1, 2, 3) } | ||
178 | fn b() { foo(1, 2, 3,) } | ||
179 | "#, | ||
180 | r#" | ||
181 | fn foo(x: i32, z: i32) { x; } | ||
182 | fn a() { foo(1, 3) } | ||
183 | fn b() { foo(1, 3,) } | ||
184 | "#, | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
122 | fn remove_unused_qualified_call() { | 189 | fn remove_unused_qualified_call() { |
123 | check_assist( | 190 | check_assist( |
124 | remove_unused_param, | 191 | remove_unused_param, |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 6e736ccb3..fdec886e9 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -73,45 +73,32 @@ pub struct Assist { | |||
73 | /// Target ranges are used to sort assists: the smaller the target range, | 73 | /// Target ranges are used to sort assists: the smaller the target range, |
74 | /// the more specific assist is, and so it should be sorted first. | 74 | /// the more specific assist is, and so it should be sorted first. |
75 | pub target: TextRange, | 75 | pub target: TextRange, |
76 | } | 76 | /// Computing source change sometimes is much more costly then computing the |
77 | 77 | /// other fields. Additionally, the actual change is not required to show | |
78 | #[derive(Debug, Clone)] | 78 | /// the lightbulb UI, it only is needed when the user tries to apply an |
79 | pub struct ResolvedAssist { | 79 | /// assist. So, we compute it lazily: the API allow requesting assists with |
80 | pub assist: Assist, | 80 | /// or without source change. We could (and in fact, used to) distinguish |
81 | pub source_change: SourceChange, | 81 | /// between resolved and unresolved assists at the type level, but this is |
82 | /// cumbersome, especially if you want to embed an assist into another data | ||
83 | /// structure, such as a diagnostic. | ||
84 | pub source_change: Option<SourceChange>, | ||
82 | } | 85 | } |
83 | 86 | ||
84 | impl Assist { | 87 | impl Assist { |
85 | /// Return all the assists applicable at the given position. | 88 | /// Return all the assists applicable at the given position. |
86 | /// | 89 | pub fn get( |
87 | /// Assists are returned in the "unresolved" state, that is only labels are | ||
88 | /// returned, without actual edits. | ||
89 | pub fn unresolved(db: &RootDatabase, config: &AssistConfig, range: FileRange) -> Vec<Assist> { | ||
90 | let sema = Semantics::new(db); | ||
91 | let ctx = AssistContext::new(sema, config, range); | ||
92 | let mut acc = Assists::new_unresolved(&ctx); | ||
93 | handlers::all().iter().for_each(|handler| { | ||
94 | handler(&mut acc, &ctx); | ||
95 | }); | ||
96 | acc.finish_unresolved() | ||
97 | } | ||
98 | |||
99 | /// Return all the assists applicable at the given position. | ||
100 | /// | ||
101 | /// Assists are returned in the "resolved" state, that is with edit fully | ||
102 | /// computed. | ||
103 | pub fn resolved( | ||
104 | db: &RootDatabase, | 90 | db: &RootDatabase, |
105 | config: &AssistConfig, | 91 | config: &AssistConfig, |
92 | resolve: bool, | ||
106 | range: FileRange, | 93 | range: FileRange, |
107 | ) -> Vec<ResolvedAssist> { | 94 | ) -> Vec<Assist> { |
108 | let sema = Semantics::new(db); | 95 | let sema = Semantics::new(db); |
109 | let ctx = AssistContext::new(sema, config, range); | 96 | let ctx = AssistContext::new(sema, config, range); |
110 | let mut acc = Assists::new_resolved(&ctx); | 97 | let mut acc = Assists::new(&ctx, resolve); |
111 | handlers::all().iter().for_each(|handler| { | 98 | handlers::all().iter().for_each(|handler| { |
112 | handler(&mut acc, &ctx); | 99 | handler(&mut acc, &ctx); |
113 | }); | 100 | }); |
114 | acc.finish_resolved() | 101 | acc.finish() |
115 | } | 102 | } |
116 | } | 103 | } |
117 | 104 | ||
@@ -129,6 +116,7 @@ mod handlers { | |||
129 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
130 | mod early_return; | 117 | mod early_return; |
131 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_module_to_file; | ||
132 | mod extract_struct_from_enum_variant; | 120 | mod extract_struct_from_enum_variant; |
133 | mod extract_variable; | 121 | mod extract_variable; |
134 | mod fill_match_arms; | 122 | mod fill_match_arms; |
@@ -179,6 +167,7 @@ mod handlers { | |||
179 | convert_integer_literal::convert_integer_literal, | 167 | convert_integer_literal::convert_integer_literal, |
180 | early_return::convert_to_guarded_return, | 168 | early_return::convert_to_guarded_return, |
181 | expand_glob_import::expand_glob_import, | 169 | expand_glob_import::expand_glob_import, |
170 | extract_module_to_file::extract_module_to_file, | ||
182 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 171 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
183 | extract_variable::extract_variable, | 172 | extract_variable::extract_variable, |
184 | fill_match_arms::fill_match_arms, | 173 | fill_match_arms::fill_match_arms, |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 709a34d03..21e448fb8 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -2,6 +2,7 @@ mod generated; | |||
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
5 | use ide_db::source_change::FileSystemEdit; | ||
5 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
6 | use syntax::TextRange; | 7 | use syntax::TextRange; |
7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 8 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
@@ -47,25 +48,29 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
47 | let before = db.file_text(file_id).to_string(); | 48 | let before = db.file_text(file_id).to_string(); |
48 | let frange = FileRange { file_id, range: selection.into() }; | 49 | let frange = FileRange { file_id, range: selection.into() }; |
49 | 50 | ||
50 | let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) | 51 | let assist = Assist::get(&db, &AssistConfig::default(), true, frange) |
51 | .into_iter() | 52 | .into_iter() |
52 | .find(|assist| assist.assist.id.0 == assist_id) | 53 | .find(|assist| assist.id.0 == assist_id) |
53 | .unwrap_or_else(|| { | 54 | .unwrap_or_else(|| { |
54 | panic!( | 55 | panic!( |
55 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 56 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
56 | assist_id, | 57 | assist_id, |
57 | Assist::resolved(&db, &AssistConfig::default(), frange) | 58 | Assist::get(&db, &AssistConfig::default(), false, frange) |
58 | .into_iter() | 59 | .into_iter() |
59 | .map(|assist| assist.assist.id.0) | 60 | .map(|assist| assist.id.0) |
60 | .collect::<Vec<_>>() | 61 | .collect::<Vec<_>>() |
61 | .join(", ") | 62 | .join(", ") |
62 | ) | 63 | ) |
63 | }); | 64 | }); |
64 | 65 | ||
65 | let actual = { | 66 | let actual = { |
66 | let change = assist.source_change.source_file_edits.pop().unwrap(); | 67 | let source_change = assist.source_change.unwrap(); |
67 | let mut actual = before; | 68 | let mut actual = before; |
68 | change.edit.apply(&mut actual); | 69 | for source_file_edit in source_change.source_file_edits { |
70 | if source_file_edit.file_id == file_id { | ||
71 | source_file_edit.edit.apply(&mut actual) | ||
72 | } | ||
73 | } | ||
69 | actual | 74 | actual |
70 | }; | 75 | }; |
71 | assert_eq_text!(&after, &actual); | 76 | assert_eq_text!(&after, &actual); |
@@ -86,20 +91,21 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
86 | let sema = Semantics::new(&db); | 91 | let sema = Semantics::new(&db); |
87 | let config = AssistConfig::default(); | 92 | let config = AssistConfig::default(); |
88 | let ctx = AssistContext::new(sema, &config, frange); | 93 | let ctx = AssistContext::new(sema, &config, frange); |
89 | let mut acc = Assists::new_resolved(&ctx); | 94 | let mut acc = Assists::new(&ctx, true); |
90 | handler(&mut acc, &ctx); | 95 | handler(&mut acc, &ctx); |
91 | let mut res = acc.finish_resolved(); | 96 | let mut res = acc.finish(); |
92 | 97 | ||
93 | let assist = match assist_label { | 98 | let assist = match assist_label { |
94 | Some(label) => res.into_iter().find(|resolved| resolved.assist.label == label), | 99 | Some(label) => res.into_iter().find(|resolved| resolved.label == label), |
95 | None => res.pop(), | 100 | None => res.pop(), |
96 | }; | 101 | }; |
97 | 102 | ||
98 | match (assist, expected) { | 103 | match (assist, expected) { |
99 | (Some(assist), ExpectedResult::After(after)) => { | 104 | (Some(assist), ExpectedResult::After(after)) => { |
100 | let mut source_change = assist.source_change; | 105 | let mut source_change = assist.source_change.unwrap(); |
101 | assert!(!source_change.source_file_edits.is_empty()); | 106 | assert!(!source_change.source_file_edits.is_empty()); |
102 | let skip_header = source_change.source_file_edits.len() == 1; | 107 | let skip_header = source_change.source_file_edits.len() == 1 |
108 | && source_change.file_system_edits.len() == 0; | ||
103 | source_change.source_file_edits.sort_by_key(|it| it.file_id); | 109 | source_change.source_file_edits.sort_by_key(|it| it.file_id); |
104 | 110 | ||
105 | let mut buf = String::new(); | 111 | let mut buf = String::new(); |
@@ -115,10 +121,25 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
115 | buf.push_str(&text); | 121 | buf.push_str(&text); |
116 | } | 122 | } |
117 | 123 | ||
124 | for file_system_edit in source_change.file_system_edits.clone() { | ||
125 | match file_system_edit { | ||
126 | FileSystemEdit::CreateFile { dst, initial_contents } => { | ||
127 | let sr = db.file_source_root(dst.anchor); | ||
128 | let sr = db.source_root(sr); | ||
129 | let mut base = sr.path_for_file(&dst.anchor).unwrap().clone(); | ||
130 | base.pop(); | ||
131 | let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]); | ||
132 | format_to!(buf, "//- {}\n", created_file_path); | ||
133 | buf.push_str(&initial_contents); | ||
134 | } | ||
135 | _ => (), | ||
136 | } | ||
137 | } | ||
138 | |||
118 | assert_eq_text!(after, &buf); | 139 | assert_eq_text!(after, &buf); |
119 | } | 140 | } |
120 | (Some(assist), ExpectedResult::Target(target)) => { | 141 | (Some(assist), ExpectedResult::Target(target)) => { |
121 | let range = assist.assist.target; | 142 | let range = assist.target; |
122 | assert_eq_text!(&text_without_caret[range], target); | 143 | assert_eq_text!(&text_without_caret[range], target); |
123 | } | 144 | } |
124 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 145 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
@@ -135,14 +156,11 @@ fn assist_order_field_struct() { | |||
135 | let (before_cursor_pos, before) = extract_offset(before); | 156 | let (before_cursor_pos, before) = extract_offset(before); |
136 | let (db, file_id) = with_single_file(&before); | 157 | let (db, file_id) = with_single_file(&before); |
137 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; | 158 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; |
138 | let assists = Assist::resolved(&db, &AssistConfig::default(), frange); | 159 | let assists = Assist::get(&db, &AssistConfig::default(), false, frange); |
139 | let mut assists = assists.iter(); | 160 | let mut assists = assists.iter(); |
140 | 161 | ||
141 | assert_eq!( | 162 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); |
142 | assists.next().expect("expected assist").assist.label, | 163 | assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); |
143 | "Change visibility to pub(crate)" | ||
144 | ); | ||
145 | assert_eq!(assists.next().expect("expected assist").assist.label, "Add `#[derive]`"); | ||
146 | } | 164 | } |
147 | 165 | ||
148 | #[test] | 166 | #[test] |
@@ -158,11 +176,11 @@ fn assist_order_if_expr() { | |||
158 | let (range, before) = extract_range(before); | 176 | let (range, before) = extract_range(before); |
159 | let (db, file_id) = with_single_file(&before); | 177 | let (db, file_id) = with_single_file(&before); |
160 | let frange = FileRange { file_id, range }; | 178 | let frange = FileRange { file_id, range }; |
161 | let assists = Assist::resolved(&db, &AssistConfig::default(), frange); | 179 | let assists = Assist::get(&db, &AssistConfig::default(), false, frange); |
162 | let mut assists = assists.iter(); | 180 | let mut assists = assists.iter(); |
163 | 181 | ||
164 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | 182 | assert_eq!(assists.next().expect("expected assist").label, "Extract into variable"); |
165 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); | 183 | assert_eq!(assists.next().expect("expected assist").label, "Replace with match"); |
166 | } | 184 | } |
167 | 185 | ||
168 | #[test] | 186 | #[test] |
@@ -183,27 +201,27 @@ fn assist_filter_works() { | |||
183 | let mut cfg = AssistConfig::default(); | 201 | let mut cfg = AssistConfig::default(); |
184 | cfg.allowed = Some(vec![AssistKind::Refactor]); | 202 | cfg.allowed = Some(vec![AssistKind::Refactor]); |
185 | 203 | ||
186 | let assists = Assist::resolved(&db, &cfg, frange); | 204 | let assists = Assist::get(&db, &cfg, false, frange); |
187 | let mut assists = assists.iter(); | 205 | let mut assists = assists.iter(); |
188 | 206 | ||
189 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | 207 | assert_eq!(assists.next().expect("expected assist").label, "Extract into variable"); |
190 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); | 208 | assert_eq!(assists.next().expect("expected assist").label, "Replace with match"); |
191 | } | 209 | } |
192 | 210 | ||
193 | { | 211 | { |
194 | let mut cfg = AssistConfig::default(); | 212 | let mut cfg = AssistConfig::default(); |
195 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 213 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
196 | let assists = Assist::resolved(&db, &cfg, frange); | 214 | let assists = Assist::get(&db, &cfg, false, frange); |
197 | assert_eq!(assists.len(), 1); | 215 | assert_eq!(assists.len(), 1); |
198 | 216 | ||
199 | let mut assists = assists.iter(); | 217 | let mut assists = assists.iter(); |
200 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | 218 | assert_eq!(assists.next().expect("expected assist").label, "Extract into variable"); |
201 | } | 219 | } |
202 | 220 | ||
203 | { | 221 | { |
204 | let mut cfg = AssistConfig::default(); | 222 | let mut cfg = AssistConfig::default(); |
205 | cfg.allowed = Some(vec![AssistKind::QuickFix]); | 223 | cfg.allowed = Some(vec![AssistKind::QuickFix]); |
206 | let assists = Assist::resolved(&db, &cfg, frange); | 224 | let assists = Assist::get(&db, &cfg, false, frange); |
207 | assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out"); | 225 | assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out"); |
208 | } | 226 | } |
209 | } | 227 | } |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index cc7c4a343..d3dfe24e7 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -42,26 +42,26 @@ fn doctest_add_impl_default_members() { | |||
42 | "add_impl_default_members", | 42 | "add_impl_default_members", |
43 | r#####" | 43 | r#####" |
44 | trait Trait { | 44 | trait Trait { |
45 | Type X; | 45 | type X; |
46 | fn foo(&self); | 46 | fn foo(&self); |
47 | fn bar(&self) {} | 47 | fn bar(&self) {} |
48 | } | 48 | } |
49 | 49 | ||
50 | impl Trait for () { | 50 | impl Trait for () { |
51 | Type X = (); | 51 | type X = (); |
52 | fn foo(&self) {}<|> | 52 | fn foo(&self) {}<|> |
53 | 53 | ||
54 | } | 54 | } |
55 | "#####, | 55 | "#####, |
56 | r#####" | 56 | r#####" |
57 | trait Trait { | 57 | trait Trait { |
58 | Type X; | 58 | type X; |
59 | fn foo(&self); | 59 | fn foo(&self); |
60 | fn bar(&self) {} | 60 | fn bar(&self) {} |
61 | } | 61 | } |
62 | 62 | ||
63 | impl Trait for () { | 63 | impl Trait for () { |
64 | Type X = (); | 64 | type X = (); |
65 | fn foo(&self) {} | 65 | fn foo(&self) {} |
66 | 66 | ||
67 | $0fn bar(&self) {} | 67 | $0fn bar(&self) {} |
@@ -76,7 +76,7 @@ fn doctest_add_impl_missing_members() { | |||
76 | "add_impl_missing_members", | 76 | "add_impl_missing_members", |
77 | r#####" | 77 | r#####" |
78 | trait Trait<T> { | 78 | trait Trait<T> { |
79 | Type X; | 79 | type X; |
80 | fn foo(&self) -> T; | 80 | fn foo(&self) -> T; |
81 | fn bar(&self) {} | 81 | fn bar(&self) {} |
82 | } | 82 | } |
@@ -87,14 +87,16 @@ impl Trait<u32> for () {<|> | |||
87 | "#####, | 87 | "#####, |
88 | r#####" | 88 | r#####" |
89 | trait Trait<T> { | 89 | trait Trait<T> { |
90 | Type X; | 90 | type X; |
91 | fn foo(&self) -> T; | 91 | fn foo(&self) -> T; |
92 | fn bar(&self) {} | 92 | fn bar(&self) {} |
93 | } | 93 | } |
94 | 94 | ||
95 | impl Trait<u32> for () { | 95 | impl Trait<u32> for () { |
96 | $0type X; | ||
97 | |||
96 | fn foo(&self) -> u32 { | 98 | fn foo(&self) -> u32 { |
97 | ${0:todo!()} | 99 | todo!() |
98 | } | 100 | } |
99 | } | 101 | } |
100 | "#####, | 102 | "#####, |
@@ -236,6 +238,21 @@ fn qux(bar: Bar, baz: Baz) {} | |||
236 | } | 238 | } |
237 | 239 | ||
238 | #[test] | 240 | #[test] |
241 | fn doctest_extract_module_to_file() { | ||
242 | check_doc_test( | ||
243 | "extract_module_to_file", | ||
244 | r#####" | ||
245 | mod foo {<|> | ||
246 | fn t() {} | ||
247 | } | ||
248 | "#####, | ||
249 | r#####" | ||
250 | mod foo; | ||
251 | "#####, | ||
252 | ) | ||
253 | } | ||
254 | |||
255 | #[test] | ||
239 | fn doctest_extract_struct_from_enum_variant() { | 256 | fn doctest_extract_struct_from_enum_variant() { |
240 | check_doc_test( | 257 | check_doc_test( |
241 | "extract_struct_from_enum_variant", | 258 | "extract_struct_from_enum_variant", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index f2cacf7c8..d41084b59 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -232,7 +232,13 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
232 | }; | 232 | }; |
233 | Some(make::expr_method_call(receiver, method, arg_list)) | 233 | Some(make::expr_method_call(receiver, method, arg_list)) |
234 | } | 234 | } |
235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), | 235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => { |
236 | if let ast::Expr::ParenExpr(parexpr) = pe.expr()? { | ||
237 | parexpr.expr() | ||
238 | } else { | ||
239 | pe.expr() | ||
240 | } | ||
241 | } | ||
236 | // FIXME: | 242 | // FIXME: |
237 | // ast::Expr::Literal(true | false ) | 243 | // ast::Expr::Literal(true | false ) |
238 | _ => None, | 244 | _ => None, |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 1ef6b5f48..d9fe13485 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -19,9 +19,14 @@ use hir::{ModPath, ScopeDef, Type}; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | item::Builder, | 20 | item::Builder, |
21 | render::{ | 21 | render::{ |
22 | const_::render_const, enum_variant::render_variant, function::render_fn, | 22 | const_::render_const, |
23 | macro_::render_macro, render_field, render_resolution, render_tuple_field, | 23 | enum_variant::render_variant, |
24 | type_alias::render_type_alias, RenderContext, | 24 | function::render_fn, |
25 | macro_::render_macro, | ||
26 | pattern::{render_struct_pat, render_variant_pat}, | ||
27 | render_field, render_resolution, render_tuple_field, | ||
28 | type_alias::render_type_alias, | ||
29 | RenderContext, | ||
25 | }, | 30 | }, |
26 | CompletionContext, CompletionItem, | 31 | CompletionContext, CompletionItem, |
27 | }; | 32 | }; |
@@ -105,6 +110,28 @@ impl Completions { | |||
105 | self.add(item) | 110 | self.add(item) |
106 | } | 111 | } |
107 | 112 | ||
113 | pub(crate) fn add_variant_pat( | ||
114 | &mut self, | ||
115 | ctx: &CompletionContext, | ||
116 | variant: hir::Variant, | ||
117 | local_name: Option<hir::Name>, | ||
118 | ) { | ||
119 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name) { | ||
120 | self.add(item); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub(crate) fn add_struct_pat( | ||
125 | &mut self, | ||
126 | ctx: &CompletionContext, | ||
127 | strukt: hir::Struct, | ||
128 | local_name: Option<hir::Name>, | ||
129 | ) { | ||
130 | if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { | ||
131 | self.add(item); | ||
132 | } | ||
133 | } | ||
134 | |||
108 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 135 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
109 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { | 136 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { |
110 | self.add(item); | 137 | self.add(item); |
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index 4d56731ec..eee31098d 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | use crate::{CompletionContext, Completions}; | 3 | use crate::{CompletionContext, Completions}; |
4 | 4 | ||
5 | /// Completes constats and paths in patterns. | 5 | /// Completes constants and paths in patterns. |
6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { |
7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) { | 7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_pat_binding) { |
8 | return; | 8 | return; |
9 | } | 9 | } |
10 | if ctx.record_pat_syntax.is_some() { | 10 | if ctx.record_pat_syntax.is_some() { |
@@ -15,20 +15,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
15 | // suggest variants + auto-imports | 15 | // suggest variants + auto-imports |
16 | ctx.scope.process_all_names(&mut |name, res| { | 16 | ctx.scope.process_all_names(&mut |name, res| { |
17 | let add_resolution = match &res { | 17 | let add_resolution = match &res { |
18 | hir::ScopeDef::ModuleDef(def) => { | 18 | hir::ScopeDef::ModuleDef(def) => match def { |
19 | if ctx.is_irrefutable_let_pat_binding { | 19 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
20 | matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_))) | 20 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); |
21 | } else { | 21 | true |
22 | matches!( | ||
23 | def, | ||
24 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
25 | | hir::ModuleDef::Adt(hir::Adt::Struct(..)) | ||
26 | | hir::ModuleDef::Variant(..) | ||
27 | | hir::ModuleDef::Const(..) | ||
28 | | hir::ModuleDef::Module(..) | ||
29 | ) | ||
30 | } | 22 | } |
31 | } | 23 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { |
24 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); | ||
25 | true | ||
26 | } | ||
27 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
28 | | hir::ModuleDef::Variant(..) | ||
29 | | hir::ModuleDef::Const(..) | ||
30 | | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding, | ||
31 | _ => false, | ||
32 | }, | ||
32 | hir::ScopeDef::MacroDef(_) => true, | 33 | hir::ScopeDef::MacroDef(_) => true, |
33 | _ => false, | 34 | _ => false, |
34 | }; | 35 | }; |
@@ -42,13 +43,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
42 | mod tests { | 43 | mod tests { |
43 | use expect_test::{expect, Expect}; | 44 | use expect_test::{expect, Expect}; |
44 | 45 | ||
45 | use crate::{test_utils::completion_list, CompletionKind}; | 46 | use crate::{ |
47 | test_utils::{check_edit, completion_list}, | ||
48 | CompletionKind, | ||
49 | }; | ||
46 | 50 | ||
47 | fn check(ra_fixture: &str, expect: Expect) { | 51 | fn check(ra_fixture: &str, expect: Expect) { |
48 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 52 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
49 | expect.assert_eq(&actual) | 53 | expect.assert_eq(&actual) |
50 | } | 54 | } |
51 | 55 | ||
56 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
57 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
58 | expect.assert_eq(&actual) | ||
59 | } | ||
60 | |||
52 | #[test] | 61 | #[test] |
53 | fn completes_enum_variants_and_modules() { | 62 | fn completes_enum_variants_and_modules() { |
54 | check( | 63 | check( |
@@ -69,7 +78,7 @@ fn foo() { | |||
69 | en E | 78 | en E |
70 | ct Z | 79 | ct Z |
71 | st Bar | 80 | st Bar |
72 | ev X () | 81 | ev X |
73 | md m | 82 | md m |
74 | "#]], | 83 | "#]], |
75 | ); | 84 | ); |
@@ -114,4 +123,139 @@ fn foo() { | |||
114 | "#]], | 123 | "#]], |
115 | ); | 124 | ); |
116 | } | 125 | } |
126 | |||
127 | #[test] | ||
128 | fn completes_in_param() { | ||
129 | check( | ||
130 | r#" | ||
131 | enum E { X } | ||
132 | |||
133 | static FOO: E = E::X; | ||
134 | struct Bar { f: u32 } | ||
135 | |||
136 | fn foo(<|>) { | ||
137 | } | ||
138 | "#, | ||
139 | expect![[r#" | ||
140 | st Bar | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_pat_in_let() { | ||
147 | check_snippet( | ||
148 | r#" | ||
149 | struct Bar { f: u32 } | ||
150 | |||
151 | fn foo() { | ||
152 | let <|> | ||
153 | } | ||
154 | "#, | ||
155 | expect![[r#" | ||
156 | bn Bar Bar { f$1 }$0 | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn completes_param_pattern() { | ||
163 | check_snippet( | ||
164 | r#" | ||
165 | struct Foo { bar: String, baz: String } | ||
166 | struct Bar(String, String); | ||
167 | struct Baz; | ||
168 | fn outer(<|>) {} | ||
169 | "#, | ||
170 | expect![[r#" | ||
171 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
172 | bn Bar Bar($1, $2): Bar$0 | ||
173 | "#]], | ||
174 | ) | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn completes_let_pattern() { | ||
179 | check_snippet( | ||
180 | r#" | ||
181 | struct Foo { bar: String, baz: String } | ||
182 | struct Bar(String, String); | ||
183 | struct Baz; | ||
184 | fn outer() { | ||
185 | let <|> | ||
186 | } | ||
187 | "#, | ||
188 | expect![[r#" | ||
189 | bn Foo Foo { bar$1, baz$2 }$0 | ||
190 | bn Bar Bar($1, $2)$0 | ||
191 | "#]], | ||
192 | ) | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn completes_refutable_pattern() { | ||
197 | check_snippet( | ||
198 | r#" | ||
199 | struct Foo { bar: i32, baz: i32 } | ||
200 | struct Bar(String, String); | ||
201 | struct Baz; | ||
202 | fn outer() { | ||
203 | match () { | ||
204 | <|> | ||
205 | } | ||
206 | } | ||
207 | "#, | ||
208 | expect![[r#" | ||
209 | bn Foo Foo { bar$1, baz$2 }$0 | ||
210 | bn Bar Bar($1, $2)$0 | ||
211 | "#]], | ||
212 | ) | ||
213 | } | ||
214 | |||
215 | #[test] | ||
216 | fn omits_private_fields_pat() { | ||
217 | check_snippet( | ||
218 | r#" | ||
219 | mod foo { | ||
220 | pub struct Foo { pub bar: i32, baz: i32 } | ||
221 | pub struct Bar(pub String, String); | ||
222 | pub struct Invisible(String, String); | ||
223 | } | ||
224 | use foo::*; | ||
225 | |||
226 | fn outer() { | ||
227 | match () { | ||
228 | <|> | ||
229 | } | ||
230 | } | ||
231 | "#, | ||
232 | expect![[r#" | ||
233 | bn Foo Foo { bar$1, .. }$0 | ||
234 | bn Bar Bar($1, ..)$0 | ||
235 | "#]], | ||
236 | ) | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn only_shows_ident_completion() { | ||
241 | check_edit( | ||
242 | "Foo", | ||
243 | r#" | ||
244 | struct Foo(i32); | ||
245 | fn main() { | ||
246 | match Foo(92) { | ||
247 | <|>(92) => (), | ||
248 | } | ||
249 | } | ||
250 | "#, | ||
251 | r#" | ||
252 | struct Foo(i32); | ||
253 | fn main() { | ||
254 | match Foo(92) { | ||
255 | Foo(92) => (), | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
117 | } | 261 | } |
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs index 1300f00b2..882c4dcbc 100644 --- a/crates/completion/src/completions/qualified_path.rs +++ b/crates/completion/src/completions/qualified_path.rs | |||
@@ -118,6 +118,12 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
118 | _ => return, | 118 | _ => return, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | if let Some(Adt::Enum(e)) = ty.as_adt() { | ||
122 | for variant in e.variants(ctx.db) { | ||
123 | acc.add_enum_variant(ctx, variant, None); | ||
124 | } | ||
125 | } | ||
126 | |||
121 | let traits_in_scope = ctx.scope.traits_in_scope(); | 127 | let traits_in_scope = ctx.scope.traits_in_scope(); |
122 | let mut seen = FxHashSet::default(); | 128 | let mut seen = FxHashSet::default(); |
123 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | 129 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { |
@@ -752,4 +758,27 @@ fn main() { | |||
752 | "#]], | 758 | "#]], |
753 | ); | 759 | ); |
754 | } | 760 | } |
761 | |||
762 | #[test] | ||
763 | fn completes_self_enum() { | ||
764 | check( | ||
765 | r#" | ||
766 | enum Foo { | ||
767 | Bar, | ||
768 | Baz, | ||
769 | } | ||
770 | |||
771 | impl Foo { | ||
772 | fn foo(self) { | ||
773 | Self::<|> | ||
774 | } | ||
775 | } | ||
776 | "#, | ||
777 | expect![[r#" | ||
778 | ev Bar () | ||
779 | ev Baz () | ||
780 | me foo(…) fn foo(self) | ||
781 | "#]], | ||
782 | ); | ||
783 | } | ||
755 | } | 784 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 099ffb4d4..d09849752 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use std::iter; | ||
4 | |||
3 | use either::Either; | 5 | use either::Either; |
4 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; | 6 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; |
5 | use ide_db::helpers::insert_use::ImportScope; | 7 | use ide_db::helpers::insert_use::ImportScope; |
@@ -50,7 +52,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
50 | } | 52 | } |
51 | 53 | ||
52 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 54 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
53 | if let Some(Adt::Enum(enum_data)) = ty.as_adt() { | 55 | if let Some(Adt::Enum(enum_data)) = |
56 | iter::successors(Some(ty.clone()), |ty| ty.remove_ref()).last().and_then(|ty| ty.as_adt()) | ||
57 | { | ||
54 | let variants = enum_data.variants(ctx.db); | 58 | let variants = enum_data.variants(ctx.db); |
55 | 59 | ||
56 | let module = if let Some(module) = ctx.scope.module() { | 60 | let module = if let Some(module) = ctx.scope.module() { |
@@ -701,6 +705,7 @@ fn main() { <|> } | |||
701 | "#]], | 705 | "#]], |
702 | ); | 706 | ); |
703 | } | 707 | } |
708 | |||
704 | #[test] | 709 | #[test] |
705 | fn completes_enum_variant_matcharm() { | 710 | fn completes_enum_variant_matcharm() { |
706 | check( | 711 | check( |
@@ -722,6 +727,26 @@ fn main() { | |||
722 | } | 727 | } |
723 | 728 | ||
724 | #[test] | 729 | #[test] |
730 | fn completes_enum_variant_matcharm_ref() { | ||
731 | check( | ||
732 | r#" | ||
733 | enum Foo { Bar, Baz, Quux } | ||
734 | |||
735 | fn main() { | ||
736 | let foo = Foo::Quux; | ||
737 | match &foo { Qu<|> } | ||
738 | } | ||
739 | "#, | ||
740 | expect![[r#" | ||
741 | ev Foo::Bar () | ||
742 | ev Foo::Baz () | ||
743 | ev Foo::Quux () | ||
744 | en Foo | ||
745 | "#]], | ||
746 | ) | ||
747 | } | ||
748 | |||
749 | #[test] | ||
725 | fn completes_enum_variant_iflet() { | 750 | fn completes_enum_variant_iflet() { |
726 | check( | 751 | check( |
727 | r#" | 752 | r#" |
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs index 5cd11cf77..41de324d8 100644 --- a/crates/completion/src/context.rs +++ b/crates/completion/src/context.rs | |||
@@ -51,7 +51,7 @@ pub(crate) struct CompletionContext<'a> { | |||
51 | /// If a name-binding or reference to a const in a pattern. | 51 | /// If a name-binding or reference to a const in a pattern. |
52 | /// Irrefutable patterns (like let) are excluded. | 52 | /// Irrefutable patterns (like let) are excluded. |
53 | pub(super) is_pat_binding_or_const: bool, | 53 | pub(super) is_pat_binding_or_const: bool, |
54 | pub(super) is_irrefutable_let_pat_binding: bool, | 54 | pub(super) is_irrefutable_pat_binding: bool, |
55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
56 | pub(super) is_trivial_path: bool, | 56 | pub(super) is_trivial_path: bool, |
57 | /// If not a trivial path, the prefix (qualifier). | 57 | /// If not a trivial path, the prefix (qualifier). |
@@ -147,7 +147,7 @@ impl<'a> CompletionContext<'a> { | |||
147 | active_parameter: ActiveParameter::at(db, position), | 147 | active_parameter: ActiveParameter::at(db, position), |
148 | is_param: false, | 148 | is_param: false, |
149 | is_pat_binding_or_const: false, | 149 | is_pat_binding_or_const: false, |
150 | is_irrefutable_let_pat_binding: false, | 150 | is_irrefutable_pat_binding: false, |
151 | is_trivial_path: false, | 151 | is_trivial_path: false, |
152 | path_qual: None, | 152 | path_qual: None, |
153 | after_if: false, | 153 | after_if: false, |
@@ -327,14 +327,19 @@ impl<'a> CompletionContext<'a> { | |||
327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { | 327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { |
328 | self.is_pat_binding_or_const = false; | 328 | self.is_pat_binding_or_const = false; |
329 | } | 329 | } |
330 | if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) { | 330 | if let Some(Some(pat)) = bind_pat.syntax().ancestors().find_map(|node| { |
331 | if let Some(pat) = let_stmt.pat() { | 331 | match_ast! { |
332 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) | 332 | match node { |
333 | { | 333 | ast::LetStmt(it) => Some(it.pat()), |
334 | self.is_pat_binding_or_const = false; | 334 | ast::Param(it) => Some(it.pat()), |
335 | self.is_irrefutable_let_pat_binding = true; | 335 | _ => None, |
336 | } | 336 | } |
337 | } | 337 | } |
338 | }) { | ||
339 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) { | ||
340 | self.is_pat_binding_or_const = false; | ||
341 | self.is_irrefutable_pat_binding = true; | ||
342 | } | ||
338 | } | 343 | } |
339 | } | 344 | } |
340 | if is_node::<ast::Param>(name.syntax()) { | 345 | if is_node::<ast::Param>(name.syntax()) { |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1092a4825..1ba7201a1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -5,6 +5,7 @@ pub(crate) mod macro_; | |||
5 | pub(crate) mod function; | 5 | pub(crate) mod function; |
6 | pub(crate) mod enum_variant; | 6 | pub(crate) mod enum_variant; |
7 | pub(crate) mod const_; | 7 | pub(crate) mod const_; |
8 | pub(crate) mod pattern; | ||
8 | pub(crate) mod type_alias; | 9 | pub(crate) mod type_alias; |
9 | 10 | ||
10 | mod builder_ext; | 11 | mod builder_ext; |
@@ -159,6 +160,12 @@ impl<'a> Render<'a> { | |||
159 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); |
160 | return Some(item); | 161 | return Some(item); |
161 | } | 162 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | ||
164 | if self.ctx.completion.is_pat_binding_or_const | ||
165 | | self.ctx.completion.is_irrefutable_pat_binding => | ||
166 | { | ||
167 | CompletionItemKind::EnumVariant | ||
168 | } | ||
162 | ScopeDef::ModuleDef(Variant(var)) => { | 169 | ScopeDef::ModuleDef(Variant(var)) => { |
163 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 170 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); |
164 | return Some(item); | 171 | return Some(item); |
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs index ce8718bd5..d053a988b 100644 --- a/crates/completion/src/render/builder_ext.rs +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -34,7 +34,6 @@ impl Builder { | |||
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | if ctx.is_pattern_call { | 36 | if ctx.is_pattern_call { |
37 | mark::hit!(dont_duplicate_pattern_parens); | ||
38 | return false; | 37 | return false; |
39 | } | 38 | } |
40 | if ctx.is_call { | 39 | if ctx.is_call { |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 7176fd9b3..732e139ec 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -126,50 +126,5 @@ fn main() -> Option<i32> { | |||
126 | } | 126 | } |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | check_edit( | ||
130 | "Some", | ||
131 | r#" | ||
132 | enum Option<T> { Some(T), None } | ||
133 | use Option::*; | ||
134 | fn main(value: Option<i32>) { | ||
135 | match value { | ||
136 | Som<|> | ||
137 | } | ||
138 | } | ||
139 | "#, | ||
140 | r#" | ||
141 | enum Option<T> { Some(T), None } | ||
142 | use Option::*; | ||
143 | fn main(value: Option<i32>) { | ||
144 | match value { | ||
145 | Some($0) | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn dont_duplicate_pattern_parens() { | ||
154 | mark::check!(dont_duplicate_pattern_parens); | ||
155 | check_edit( | ||
156 | "Var", | ||
157 | r#" | ||
158 | enum E { Var(i32) } | ||
159 | fn main() { | ||
160 | match E::Var(92) { | ||
161 | E::<|>(92) => (), | ||
162 | } | ||
163 | } | ||
164 | "#, | ||
165 | r#" | ||
166 | enum E { Var(i32) } | ||
167 | fn main() { | ||
168 | match E::Var(92) { | ||
169 | E::Var(92) => (), | ||
170 | } | ||
171 | } | ||
172 | "#, | ||
173 | ); | ||
174 | } | 129 | } |
175 | } | 130 | } |
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs new file mode 100644 index 000000000..a3b6a3cac --- /dev/null +++ b/crates/completion/src/render/pattern.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | //! Renderer for patterns. | ||
2 | |||
3 | use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; | ||
4 | use itertools::Itertools; | ||
5 | |||
6 | use crate::{ | ||
7 | config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem, | ||
8 | CompletionItemKind, | ||
9 | }; | ||
10 | |||
11 | fn visible_fields( | ||
12 | ctx: &RenderContext<'_>, | ||
13 | fields: &[hir::Field], | ||
14 | item: impl HasAttrs, | ||
15 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
16 | let module = ctx.completion.scope.module()?; | ||
17 | let n_fields = fields.len(); | ||
18 | let fields = fields | ||
19 | .into_iter() | ||
20 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
21 | .copied() | ||
22 | .collect::<Vec<_>>(); | ||
23 | |||
24 | let fields_omitted = | ||
25 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
26 | Some((fields, fields_omitted)) | ||
27 | } | ||
28 | |||
29 | pub(crate) fn render_struct_pat( | ||
30 | ctx: RenderContext<'_>, | ||
31 | strukt: hir::Struct, | ||
32 | local_name: Option<Name>, | ||
33 | ) -> Option<CompletionItem> { | ||
34 | let _p = profile::span("render_struct_pat"); | ||
35 | |||
36 | let fields = strukt.fields(ctx.db()); | ||
37 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?; | ||
38 | |||
39 | if visible_fields.is_empty() { | ||
40 | // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); | ||
45 | let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
46 | |||
47 | Some(build_completion(ctx, name, pat, strukt)) | ||
48 | } | ||
49 | |||
50 | pub(crate) fn render_variant_pat( | ||
51 | ctx: RenderContext<'_>, | ||
52 | variant: hir::Variant, | ||
53 | local_name: Option<Name>, | ||
54 | ) -> Option<CompletionItem> { | ||
55 | let _p = profile::span("render_variant_pat"); | ||
56 | |||
57 | let fields = variant.fields(ctx.db()); | ||
58 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; | ||
59 | |||
60 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(); | ||
61 | let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
62 | |||
63 | Some(build_completion(ctx, name, pat, variant)) | ||
64 | } | ||
65 | |||
66 | fn build_completion( | ||
67 | ctx: RenderContext<'_>, | ||
68 | name: String, | ||
69 | pat: String, | ||
70 | item: impl HasAttrs + Copy, | ||
71 | ) -> CompletionItem { | ||
72 | let completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | ||
73 | .kind(CompletionItemKind::Binding) | ||
74 | .set_documentation(ctx.docs(item)) | ||
75 | .set_deprecated(ctx.is_deprecated(item)) | ||
76 | .detail(&pat); | ||
77 | let completion = if let Some(snippet_cap) = ctx.snippet_cap() { | ||
78 | completion.insert_snippet(snippet_cap, pat) | ||
79 | } else { | ||
80 | completion.insert_text(pat) | ||
81 | }; | ||
82 | completion.build() | ||
83 | } | ||
84 | |||
85 | fn render_pat( | ||
86 | ctx: &RenderContext<'_>, | ||
87 | name: &str, | ||
88 | kind: StructKind, | ||
89 | fields: &[hir::Field], | ||
90 | fields_omitted: bool, | ||
91 | ) -> Option<String> { | ||
92 | let mut pat = match kind { | ||
93 | StructKind::Tuple if ctx.snippet_cap().is_some() => { | ||
94 | render_tuple_as_pat(&fields, &name, fields_omitted) | ||
95 | } | ||
96 | StructKind::Record => { | ||
97 | render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) | ||
98 | } | ||
99 | _ => return None, | ||
100 | }; | ||
101 | |||
102 | if ctx.completion.is_param { | ||
103 | pat.push(':'); | ||
104 | pat.push(' '); | ||
105 | pat.push_str(&name); | ||
106 | } | ||
107 | if ctx.snippet_cap().is_some() { | ||
108 | pat.push_str("$0"); | ||
109 | } | ||
110 | Some(pat) | ||
111 | } | ||
112 | |||
113 | fn render_record_as_pat( | ||
114 | db: &dyn HirDatabase, | ||
115 | snippet_cap: Option<SnippetCap>, | ||
116 | fields: &[hir::Field], | ||
117 | name: &str, | ||
118 | fields_omitted: bool, | ||
119 | ) -> String { | ||
120 | let fields = fields.iter(); | ||
121 | if snippet_cap.is_some() { | ||
122 | format!( | ||
123 | "{name} {{ {}{} }}", | ||
124 | fields | ||
125 | .enumerate() | ||
126 | .map(|(idx, field)| format!("{}${}", field.name(db), idx + 1)) | ||
127 | .format(", "), | ||
128 | if fields_omitted { ", .." } else { "" }, | ||
129 | name = name | ||
130 | ) | ||
131 | } else { | ||
132 | format!( | ||
133 | "{name} {{ {}{} }}", | ||
134 | fields.map(|field| field.name(db)).format(", "), | ||
135 | if fields_omitted { ", .." } else { "" }, | ||
136 | name = name | ||
137 | ) | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String { | ||
142 | format!( | ||
143 | "{name}({}{})", | ||
144 | fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "), | ||
145 | if fields_omitted { ", .." } else { "" }, | ||
146 | name = name | ||
147 | ) | ||
148 | } | ||
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index d6c7e71ea..b7ded3478 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -9,7 +9,7 @@ use hir_def::{ | |||
9 | adt::StructKind, | 9 | adt::StructKind, |
10 | adt::VariantData, | 10 | adt::VariantData, |
11 | builtin_type::BuiltinType, | 11 | builtin_type::BuiltinType, |
12 | expr::{BindingAnnotation, Pat, PatId}, | 12 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
13 | import_map, | 13 | import_map, |
14 | item_tree::ItemTreeNode, | 14 | item_tree::ItemTreeNode, |
15 | lang_item::LangItemTarget, | 15 | lang_item::LangItemTarget, |
@@ -374,8 +374,6 @@ impl Module { | |||
374 | let crate_def_map = db.crate_def_map(self.id.krate); | 374 | let crate_def_map = db.crate_def_map(self.id.krate); |
375 | crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); | 375 | crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); |
376 | for decl in self.declarations(db) { | 376 | for decl in self.declarations(db) { |
377 | decl.diagnostics(db, sink); | ||
378 | |||
379 | match decl { | 377 | match decl { |
380 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 378 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), |
381 | crate::ModuleDef::Module(m) => { | 379 | crate::ModuleDef::Module(m) => { |
@@ -384,7 +382,9 @@ impl Module { | |||
384 | m.diagnostics(db, sink) | 382 | m.diagnostics(db, sink) |
385 | } | 383 | } |
386 | } | 384 | } |
387 | _ => (), | 385 | _ => { |
386 | decl.diagnostics(db, sink); | ||
387 | } | ||
388 | } | 388 | } |
389 | } | 389 | } |
390 | 390 | ||
@@ -511,6 +511,10 @@ impl Struct { | |||
511 | db.struct_data(self.id).repr.clone() | 511 | db.struct_data(self.id).repr.clone() |
512 | } | 512 | } |
513 | 513 | ||
514 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
515 | self.variant_data(db).kind() | ||
516 | } | ||
517 | |||
514 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | 518 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { |
515 | db.struct_data(self.id).variant_data.clone() | 519 | db.struct_data(self.id).variant_data.clone() |
516 | } | 520 | } |
@@ -1202,6 +1206,34 @@ impl Local { | |||
1202 | } | 1206 | } |
1203 | 1207 | ||
1204 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1208 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1209 | pub struct Label { | ||
1210 | pub(crate) parent: DefWithBodyId, | ||
1211 | pub(crate) label_id: LabelId, | ||
1212 | } | ||
1213 | |||
1214 | impl Label { | ||
1215 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1216 | self.parent(db).module(db) | ||
1217 | } | ||
1218 | |||
1219 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1220 | self.parent.into() | ||
1221 | } | ||
1222 | |||
1223 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1224 | let body = db.body(self.parent.into()); | ||
1225 | body[self.label_id].name.clone() | ||
1226 | } | ||
1227 | |||
1228 | pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> { | ||
1229 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1230 | let src = source_map.label_syntax(self.label_id); | ||
1231 | let root = src.file_syntax(db.upcast()); | ||
1232 | src.map(|ast| ast.to_node(&root)) | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1236 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1205 | pub enum GenericParam { | 1237 | pub enum GenericParam { |
1206 | TypeParam(TypeParam), | 1238 | TypeParam(TypeParam), |
1207 | LifetimeParam(LifetimeParam), | 1239 | LifetimeParam(LifetimeParam), |
@@ -1268,7 +1300,6 @@ impl LifetimeParam { | |||
1268 | } | 1300 | } |
1269 | } | 1301 | } |
1270 | 1302 | ||
1271 | // FIXME: rename from `ImplDef` to `Impl` | ||
1272 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1303 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1273 | pub struct Impl { | 1304 | pub struct Impl { |
1274 | pub(crate) id: ImplId, | 1305 | pub(crate) id: ImplId, |
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 8e0c571b8..a0792b9a6 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs | |||
@@ -4,12 +4,15 @@ | |||
4 | //! are splitting the hir. | 4 | //! are splitting the hir. |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::PatId, item_scope::ItemInNs, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, | 7 | expr::{LabelId, PatId}, |
8 | GenericDefId, ModuleDefId, VariantId, | 8 | item_scope::ItemInNs, |
9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId, | ||
10 | VariantId, | ||
9 | }; | 11 | }; |
10 | 12 | ||
11 | use crate::{ | 13 | use crate::{ |
12 | Adt, AssocItem, DefWithBody, Field, GenericDef, Local, MacroDef, ModuleDef, Variant, VariantDef, | 14 | Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, |
15 | VariantDef, | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | macro_rules! from_id { | 18 | macro_rules! from_id { |
@@ -228,6 +231,12 @@ impl From<(DefWithBodyId, PatId)> for Local { | |||
228 | } | 231 | } |
229 | } | 232 | } |
230 | 233 | ||
234 | impl From<(DefWithBodyId, LabelId)> for Label { | ||
235 | fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self { | ||
236 | Label { parent, label_id } | ||
237 | } | ||
238 | } | ||
239 | |||
231 | impl From<MacroDef> for ItemInNs { | 240 | impl From<MacroDef> for ItemInNs { |
232 | fn from(macro_def: MacroDef) -> Self { | 241 | fn from(macro_def: MacroDef) -> Self { |
233 | ItemInNs::Macros(macro_def.into()) | 242 | ItemInNs::Macros(macro_def.into()) |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bdd270c58..7ac9fd507 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -35,8 +35,8 @@ pub use crate::{ | |||
35 | code_model::{ | 35 | code_model::{ |
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, | 36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, |
37 | Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef, | 37 | Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef, |
38 | HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, | 38 | HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, |
39 | Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, | 39 | Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, |
40 | }, | 40 | }, |
41 | has_source::HasSource, | 41 | has_source::HasSource, |
42 | semantics::{PathResolution, Semantics, SemanticsScope}, | 42 | semantics::{PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 25ebf73d8..67cd16e31 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -15,7 +15,7 @@ use itertools::Itertools; | |||
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::{FxHashMap, FxHashSet}; |
16 | use syntax::{ | 16 | use syntax::{ |
17 | algo::find_node_at_offset, | 17 | algo::find_node_at_offset, |
18 | ast::{self, GenericParamsOwner}, | 18 | ast::{self, GenericParamsOwner, LoopBodyOwner}, |
19 | match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize, | 19 | match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize, |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -25,8 +25,8 @@ use crate::{ | |||
25 | diagnostics::Diagnostic, | 25 | diagnostics::Diagnostic, |
26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
28 | AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, LifetimeParam, Local, | 28 | AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam, |
29 | MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 29 | Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, |
30 | VariantDef, | 30 | VariantDef, |
31 | }; | 31 | }; |
32 | 32 | ||
@@ -182,6 +182,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
182 | self.imp.resolve_lifetime_param(lifetime) | 182 | self.imp.resolve_lifetime_param(lifetime) |
183 | } | 183 | } |
184 | 184 | ||
185 | pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> { | ||
186 | self.imp.resolve_label(lifetime) | ||
187 | } | ||
188 | |||
185 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 189 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
186 | self.imp.type_of_expr(expr) | 190 | self.imp.type_of_expr(expr) |
187 | } | 191 | } |
@@ -425,6 +429,28 @@ impl<'db> SemanticsImpl<'db> { | |||
425 | ToDef::to_def(self, src) | 429 | ToDef::to_def(self, src) |
426 | } | 430 | } |
427 | 431 | ||
432 | fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> { | ||
433 | let text = lifetime.text(); | ||
434 | let label = lifetime.syntax().ancestors().find_map(|syn| { | ||
435 | let label = match_ast! { | ||
436 | match syn { | ||
437 | ast::ForExpr(it) => it.label(), | ||
438 | ast::WhileExpr(it) => it.label(), | ||
439 | ast::LoopExpr(it) => it.label(), | ||
440 | ast::EffectExpr(it) => it.label(), | ||
441 | _ => None, | ||
442 | } | ||
443 | }; | ||
444 | label.filter(|l| { | ||
445 | l.lifetime() | ||
446 | .and_then(|lt| lt.lifetime_ident_token()) | ||
447 | .map_or(false, |lt| lt.text() == text) | ||
448 | }) | ||
449 | })?; | ||
450 | let src = self.find_file(label.syntax().clone()).with_value(label); | ||
451 | ToDef::to_def(self, src) | ||
452 | } | ||
453 | |||
428 | fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 454 | fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
429 | self.analyze(expr.syntax()).type_of_expr(self.db, expr) | 455 | self.analyze(expr.syntax()).type_of_expr(self.db, expr) |
430 | } | 456 | } |
@@ -720,6 +746,7 @@ to_def_impls![ | |||
720 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 746 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), |
721 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), | 747 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), |
722 | (crate::Local, ast::IdentPat, bind_pat_to_def), | 748 | (crate::Local, ast::IdentPat, bind_pat_to_def), |
749 | (crate::Label, ast::Label, label_to_def), | ||
723 | ]; | 750 | ]; |
724 | 751 | ||
725 | fn find_root(node: &SyntaxNode) -> SyntaxNode { | 752 | fn find_root(node: &SyntaxNode) -> SyntaxNode { |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 3efca5baa..424e6e8a9 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -4,7 +4,7 @@ use base_db::FileId; | |||
4 | use hir_def::{ | 4 | use hir_def::{ |
5 | child_by_source::ChildBySource, | 5 | child_by_source::ChildBySource, |
6 | dyn_map::DynMap, | 6 | dyn_map::DynMap, |
7 | expr::PatId, | 7 | expr::{LabelId, PatId}, |
8 | keys::{self, Key}, | 8 | keys::{self, Key}, |
9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, | 9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, |
10 | LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 10 | LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, |
@@ -108,12 +108,21 @@ impl SourceToDefCtx<'_, '_> { | |||
108 | &mut self, | 108 | &mut self, |
109 | src: InFile<ast::IdentPat>, | 109 | src: InFile<ast::IdentPat>, |
110 | ) -> Option<(DefWithBodyId, PatId)> { | 110 | ) -> Option<(DefWithBodyId, PatId)> { |
111 | let container = self.find_pat_container(src.as_ref().map(|it| it.syntax()))?; | 111 | let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?; |
112 | let (_body, source_map) = self.db.body_with_source_map(container); | 112 | let (_body, source_map) = self.db.body_with_source_map(container); |
113 | let src = src.map(ast::Pat::from); | 113 | let src = src.map(ast::Pat::from); |
114 | let pat_id = source_map.node_pat(src.as_ref())?; | 114 | let pat_id = source_map.node_pat(src.as_ref())?; |
115 | Some((container, pat_id)) | 115 | Some((container, pat_id)) |
116 | } | 116 | } |
117 | pub(super) fn label_to_def( | ||
118 | &mut self, | ||
119 | src: InFile<ast::Label>, | ||
120 | ) -> Option<(DefWithBodyId, LabelId)> { | ||
121 | let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?; | ||
122 | let (_body, source_map) = self.db.body_with_source_map(container); | ||
123 | let label_id = source_map.node_label(src.as_ref())?; | ||
124 | Some((container, label_id)) | ||
125 | } | ||
117 | 126 | ||
118 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( | 127 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( |
119 | &mut self, | 128 | &mut self, |
@@ -237,7 +246,7 @@ impl SourceToDefCtx<'_, '_> { | |||
237 | None | 246 | None |
238 | } | 247 | } |
239 | 248 | ||
240 | fn find_pat_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> { | 249 | fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> { |
241 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 250 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
242 | let res: DefWithBodyId = match_ast! { | 251 | let res: DefWithBodyId = match_ast! { |
243 | match (container.value) { | 252 | match (container.value) { |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 998b82601..d07004b9d 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -26,7 +26,7 @@ pub(crate) use lower::LowerCtx; | |||
26 | use crate::{ | 26 | use crate::{ |
27 | attr::{Attrs, RawAttrs}, | 27 | attr::{Attrs, RawAttrs}, |
28 | db::DefDatabase, | 28 | db::DefDatabase, |
29 | expr::{Expr, ExprId, Pat, PatId}, | 29 | expr::{Expr, ExprId, Label, LabelId, Pat, PatId}, |
30 | item_scope::BuiltinShadowMode, | 30 | item_scope::BuiltinShadowMode, |
31 | item_scope::ItemScope, | 31 | item_scope::ItemScope, |
32 | nameres::CrateDefMap, | 32 | nameres::CrateDefMap, |
@@ -226,6 +226,7 @@ pub(crate) struct Mark { | |||
226 | pub struct Body { | 226 | pub struct Body { |
227 | pub exprs: Arena<Expr>, | 227 | pub exprs: Arena<Expr>, |
228 | pub pats: Arena<Pat>, | 228 | pub pats: Arena<Pat>, |
229 | pub labels: Arena<Label>, | ||
229 | /// The patterns for the function's parameters. While the parameter types are | 230 | /// The patterns for the function's parameters. While the parameter types are |
230 | /// part of the function signature, the patterns are not (they don't change | 231 | /// part of the function signature, the patterns are not (they don't change |
231 | /// the external type of the function). | 232 | /// the external type of the function). |
@@ -244,6 +245,8 @@ pub type ExprSource = InFile<ExprPtr>; | |||
244 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 245 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; |
245 | pub type PatSource = InFile<PatPtr>; | 246 | pub type PatSource = InFile<PatPtr>; |
246 | 247 | ||
248 | pub type LabelPtr = AstPtr<ast::Label>; | ||
249 | pub type LabelSource = InFile<LabelPtr>; | ||
247 | /// An item body together with the mapping from syntax nodes to HIR expression | 250 | /// An item body together with the mapping from syntax nodes to HIR expression |
248 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | 251 | /// IDs. This is needed to go from e.g. a position in a file to the HIR |
249 | /// expression containing it; but for type inference etc., we want to operate on | 252 | /// expression containing it; but for type inference etc., we want to operate on |
@@ -261,6 +264,8 @@ pub struct BodySourceMap { | |||
261 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | 264 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, |
262 | pat_map: FxHashMap<PatSource, PatId>, | 265 | pat_map: FxHashMap<PatSource, PatId>, |
263 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | 266 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, |
267 | label_map: FxHashMap<LabelSource, LabelId>, | ||
268 | label_map_back: ArenaMap<LabelId, LabelSource>, | ||
264 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>, | 269 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>, |
265 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | 270 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, |
266 | 271 | ||
@@ -334,6 +339,14 @@ impl Index<PatId> for Body { | |||
334 | } | 339 | } |
335 | } | 340 | } |
336 | 341 | ||
342 | impl Index<LabelId> for Body { | ||
343 | type Output = Label; | ||
344 | |||
345 | fn index(&self, label: LabelId) -> &Label { | ||
346 | &self.labels[label] | ||
347 | } | ||
348 | } | ||
349 | |||
337 | impl BodySourceMap { | 350 | impl BodySourceMap { |
338 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | 351 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { |
339 | self.expr_map_back[expr].clone() | 352 | self.expr_map_back[expr].clone() |
@@ -363,6 +376,15 @@ impl BodySourceMap { | |||
363 | self.pat_map.get(&src).cloned() | 376 | self.pat_map.get(&src).cloned() |
364 | } | 377 | } |
365 | 378 | ||
379 | pub fn label_syntax(&self, label: LabelId) -> LabelSource { | ||
380 | self.label_map_back[label].clone() | ||
381 | } | ||
382 | |||
383 | pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> { | ||
384 | let src = node.map(|it| AstPtr::new(it)); | ||
385 | self.label_map.get(&src).cloned() | ||
386 | } | ||
387 | |||
366 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> { | 388 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> { |
367 | self.field_map[&(expr, field)].clone() | 389 | self.field_map[&(expr, field)].clone() |
368 | } | 390 | } |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 0f404be1b..17c72779b 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -22,13 +22,14 @@ use test_utils::mark; | |||
22 | 22 | ||
23 | use crate::{ | 23 | use crate::{ |
24 | adt::StructKind, | 24 | adt::StructKind, |
25 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, | 25 | body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, |
26 | builtin_type::{BuiltinFloat, BuiltinInt}, | 26 | builtin_type::{BuiltinFloat, BuiltinInt}, |
27 | db::DefDatabase, | 27 | db::DefDatabase, |
28 | diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}, | 28 | diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}, |
29 | expr::{ | 29 | expr::{ |
30 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, | 30 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label, |
31 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 31 | LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, |
32 | Statement, | ||
32 | }, | 33 | }, |
33 | item_scope::BuiltinShadowMode, | 34 | item_scope::BuiltinShadowMode, |
34 | item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, | 35 | item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, |
@@ -72,6 +73,7 @@ pub(super) fn lower( | |||
72 | body: Body { | 73 | body: Body { |
73 | exprs: Arena::default(), | 74 | exprs: Arena::default(), |
74 | pats: Arena::default(), | 75 | pats: Arena::default(), |
76 | labels: Arena::default(), | ||
75 | params: Vec::new(), | 77 | params: Vec::new(), |
76 | body_expr: dummy_expr_id(), | 78 | body_expr: dummy_expr_id(), |
77 | item_scope: Default::default(), | 79 | item_scope: Default::default(), |
@@ -175,6 +177,18 @@ impl ExprCollector<'_> { | |||
175 | id | 177 | id |
176 | } | 178 | } |
177 | 179 | ||
180 | fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId { | ||
181 | let src = self.expander.to_source(ptr); | ||
182 | let id = self.make_label(label, src.clone()); | ||
183 | self.source_map.label_map.insert(src, id); | ||
184 | id | ||
185 | } | ||
186 | fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId { | ||
187 | let id = self.body.labels.alloc(label); | ||
188 | self.source_map.label_map_back.insert(id, src); | ||
189 | id | ||
190 | } | ||
191 | |||
178 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | 192 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { |
179 | let syntax_ptr = AstPtr::new(&expr); | 193 | let syntax_ptr = AstPtr::new(&expr); |
180 | if self.check_cfg(&expr).is_none() { | 194 | if self.check_cfg(&expr).is_none() { |
@@ -228,37 +242,40 @@ impl ExprCollector<'_> { | |||
228 | self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) | 242 | self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) |
229 | } | 243 | } |
230 | // FIXME: we need to record these effects somewhere... | 244 | // FIXME: we need to record these effects somewhere... |
231 | ast::Effect::Label(label) => match e.block_expr() { | 245 | ast::Effect::Label(label) => { |
232 | Some(block) => { | 246 | let label = self.collect_label(label); |
233 | let res = self.collect_block(block); | 247 | match e.block_expr() { |
234 | match &mut self.body.exprs[res] { | 248 | Some(block) => { |
235 | Expr::Block { label: block_label, .. } => { | 249 | let res = self.collect_block(block); |
236 | *block_label = label.lifetime().map(|t| Name::new_lifetime(&t)) | 250 | match &mut self.body.exprs[res] { |
251 | Expr::Block { label: block_label, .. } => { | ||
252 | *block_label = Some(label); | ||
253 | } | ||
254 | _ => unreachable!(), | ||
237 | } | 255 | } |
238 | _ => unreachable!(), | 256 | res |
239 | } | 257 | } |
240 | res | 258 | None => self.missing_expr(), |
241 | } | 259 | } |
242 | None => self.missing_expr(), | 260 | } |
243 | }, | ||
244 | // FIXME: we need to record these effects somewhere... | 261 | // FIXME: we need to record these effects somewhere... |
245 | ast::Effect::Async(_) => { | 262 | ast::Effect::Async(_) => { |
246 | let body = self.collect_block_opt(e.block_expr()); | 263 | let body = self.collect_block_opt(e.block_expr()); |
247 | self.alloc_expr(Expr::Async { body }, syntax_ptr) | 264 | self.alloc_expr(Expr::Async { body }, syntax_ptr) |
248 | } | 265 | } |
266 | ast::Effect::Const(_) => { | ||
267 | let body = self.collect_block_opt(e.block_expr()); | ||
268 | self.alloc_expr(Expr::Const { body }, syntax_ptr) | ||
269 | } | ||
249 | }, | 270 | }, |
250 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 271 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
251 | ast::Expr::LoopExpr(e) => { | 272 | ast::Expr::LoopExpr(e) => { |
273 | let label = e.label().map(|label| self.collect_label(label)); | ||
252 | let body = self.collect_block_opt(e.loop_body()); | 274 | let body = self.collect_block_opt(e.loop_body()); |
253 | self.alloc_expr( | 275 | self.alloc_expr(Expr::Loop { body, label }, syntax_ptr) |
254 | Expr::Loop { | ||
255 | body, | ||
256 | label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)), | ||
257 | }, | ||
258 | syntax_ptr, | ||
259 | ) | ||
260 | } | 276 | } |
261 | ast::Expr::WhileExpr(e) => { | 277 | ast::Expr::WhileExpr(e) => { |
278 | let label = e.label().map(|label| self.collect_label(label)); | ||
262 | let body = self.collect_block_opt(e.loop_body()); | 279 | let body = self.collect_block_opt(e.loop_body()); |
263 | 280 | ||
264 | let condition = match e.condition() { | 281 | let condition = match e.condition() { |
@@ -279,42 +296,20 @@ impl ExprCollector<'_> { | |||
279 | ]; | 296 | ]; |
280 | let match_expr = | 297 | let match_expr = |
281 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | 298 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); |
282 | return self.alloc_expr( | 299 | return self |
283 | Expr::Loop { | 300 | .alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr); |
284 | body: match_expr, | ||
285 | label: e | ||
286 | .label() | ||
287 | .and_then(|l| l.lifetime()) | ||
288 | .map(|l| Name::new_lifetime(&l)), | ||
289 | }, | ||
290 | syntax_ptr, | ||
291 | ); | ||
292 | } | 301 | } |
293 | }, | 302 | }, |
294 | }; | 303 | }; |
295 | 304 | ||
296 | self.alloc_expr( | 305 | self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr) |
297 | Expr::While { | ||
298 | condition, | ||
299 | body, | ||
300 | label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)), | ||
301 | }, | ||
302 | syntax_ptr, | ||
303 | ) | ||
304 | } | 306 | } |
305 | ast::Expr::ForExpr(e) => { | 307 | ast::Expr::ForExpr(e) => { |
308 | let label = e.label().map(|label| self.collect_label(label)); | ||
306 | let iterable = self.collect_expr_opt(e.iterable()); | 309 | let iterable = self.collect_expr_opt(e.iterable()); |
307 | let pat = self.collect_pat_opt(e.pat()); | 310 | let pat = self.collect_pat_opt(e.pat()); |
308 | let body = self.collect_block_opt(e.loop_body()); | 311 | let body = self.collect_block_opt(e.loop_body()); |
309 | self.alloc_expr( | 312 | self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr) |
310 | Expr::For { | ||
311 | iterable, | ||
312 | pat, | ||
313 | body, | ||
314 | label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)), | ||
315 | }, | ||
316 | syntax_ptr, | ||
317 | ) | ||
318 | } | 313 | } |
319 | ast::Expr::CallExpr(e) => { | 314 | ast::Expr::CallExpr(e) => { |
320 | let callee = self.collect_expr_opt(e.expr()); | 315 | let callee = self.collect_expr_opt(e.expr()); |
@@ -814,6 +809,13 @@ impl ExprCollector<'_> { | |||
814 | } | 809 | } |
815 | } | 810 | } |
816 | 811 | ||
812 | fn collect_label(&mut self, ast_label: ast::Label) -> LabelId { | ||
813 | let label = Label { | ||
814 | name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime), | ||
815 | }; | ||
816 | self.alloc_label(label, AstPtr::new(&ast_label)) | ||
817 | } | ||
818 | |||
817 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { | 819 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { |
818 | let pattern = match &pat { | 820 | let pattern = match &pat { |
819 | ast::Pat::IdentPat(bp) => { | 821 | ast::Pat::IdentPat(bp) => { |
@@ -932,6 +934,14 @@ impl ExprCollector<'_> { | |||
932 | let inner = self.collect_pat_opt(boxpat.pat()); | 934 | let inner = self.collect_pat_opt(boxpat.pat()); |
933 | Pat::Box { inner } | 935 | Pat::Box { inner } |
934 | } | 936 | } |
937 | ast::Pat::ConstBlockPat(const_block_pat) => { | ||
938 | if let Some(expr) = const_block_pat.block_expr() { | ||
939 | let expr_id = self.collect_block(expr); | ||
940 | Pat::ConstBlock(expr_id) | ||
941 | } else { | ||
942 | Pat::Missing | ||
943 | } | ||
944 | } | ||
935 | // FIXME: implement | 945 | // FIXME: implement |
936 | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 946 | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, |
937 | }; | 947 | }; |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index e5d740a36..6a481769d 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -30,6 +30,12 @@ pub(crate) fn dummy_expr_id() -> ExprId { | |||
30 | pub type PatId = Idx<Pat>; | 30 | pub type PatId = Idx<Pat>; |
31 | 31 | ||
32 | #[derive(Debug, Clone, Eq, PartialEq)] | 32 | #[derive(Debug, Clone, Eq, PartialEq)] |
33 | pub struct Label { | ||
34 | pub name: Name, | ||
35 | } | ||
36 | pub type LabelId = Idx<Label>; | ||
37 | |||
38 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
33 | pub enum Literal { | 39 | pub enum Literal { |
34 | String(String), | 40 | String(String), |
35 | ByteString(Vec<u8>), | 41 | ByteString(Vec<u8>), |
@@ -52,22 +58,22 @@ pub enum Expr { | |||
52 | Block { | 58 | Block { |
53 | statements: Vec<Statement>, | 59 | statements: Vec<Statement>, |
54 | tail: Option<ExprId>, | 60 | tail: Option<ExprId>, |
55 | label: Option<Name>, | 61 | label: Option<LabelId>, |
56 | }, | 62 | }, |
57 | Loop { | 63 | Loop { |
58 | body: ExprId, | 64 | body: ExprId, |
59 | label: Option<Name>, | 65 | label: Option<LabelId>, |
60 | }, | 66 | }, |
61 | While { | 67 | While { |
62 | condition: ExprId, | 68 | condition: ExprId, |
63 | body: ExprId, | 69 | body: ExprId, |
64 | label: Option<Name>, | 70 | label: Option<LabelId>, |
65 | }, | 71 | }, |
66 | For { | 72 | For { |
67 | iterable: ExprId, | 73 | iterable: ExprId, |
68 | pat: PatId, | 74 | pat: PatId, |
69 | body: ExprId, | 75 | body: ExprId, |
70 | label: Option<Name>, | 76 | label: Option<LabelId>, |
71 | }, | 77 | }, |
72 | Call { | 78 | Call { |
73 | callee: ExprId, | 79 | callee: ExprId, |
@@ -114,6 +120,9 @@ pub enum Expr { | |||
114 | Async { | 120 | Async { |
115 | body: ExprId, | 121 | body: ExprId, |
116 | }, | 122 | }, |
123 | Const { | ||
124 | body: ExprId, | ||
125 | }, | ||
117 | Cast { | 126 | Cast { |
118 | expr: ExprId, | 127 | expr: ExprId, |
119 | type_ref: TypeRef, | 128 | type_ref: TypeRef, |
@@ -253,7 +262,10 @@ impl Expr { | |||
253 | f(*expr); | 262 | f(*expr); |
254 | } | 263 | } |
255 | } | 264 | } |
256 | Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body), | 265 | Expr::TryBlock { body } |
266 | | Expr::Unsafe { body } | ||
267 | | Expr::Async { body } | ||
268 | | Expr::Const { body } => f(*body), | ||
257 | Expr::Loop { body, .. } => f(*body), | 269 | Expr::Loop { body, .. } => f(*body), |
258 | Expr::While { condition, body, .. } => { | 270 | Expr::While { condition, body, .. } => { |
259 | f(*condition); | 271 | f(*condition); |
@@ -399,12 +411,18 @@ pub enum Pat { | |||
399 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | 411 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, |
400 | Ref { pat: PatId, mutability: Mutability }, | 412 | Ref { pat: PatId, mutability: Mutability }, |
401 | Box { inner: PatId }, | 413 | Box { inner: PatId }, |
414 | ConstBlock(ExprId), | ||
402 | } | 415 | } |
403 | 416 | ||
404 | impl Pat { | 417 | impl Pat { |
405 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | 418 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { |
406 | match self { | 419 | match self { |
407 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | 420 | Pat::Range { .. } |
421 | | Pat::Lit(..) | ||
422 | | Pat::Path(..) | ||
423 | | Pat::ConstBlock(..) | ||
424 | | Pat::Wild | ||
425 | | Pat::Missing => {} | ||
408 | Pat::Bind { subpat, .. } => { | 426 | Pat::Bind { subpat, .. } => { |
409 | subpat.iter().copied().for_each(f); | 427 | subpat.iter().copied().for_each(f); |
410 | } | 428 | } |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 41134d23b..bb8fca009 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -62,6 +62,7 @@ pub struct GenericParams { | |||
62 | pub enum WherePredicate { | 62 | pub enum WherePredicate { |
63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, |
64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, |
65 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | ||
65 | } | 66 | } |
66 | 67 | ||
67 | #[derive(Clone, PartialEq, Eq, Debug)] | 68 | #[derive(Clone, PartialEq, Eq, Debug)] |
@@ -69,7 +70,6 @@ pub enum WherePredicateTypeTarget { | |||
69 | TypeRef(TypeRef), | 70 | TypeRef(TypeRef), |
70 | /// For desugared where predicates that can directly refer to a type param. | 71 | /// For desugared where predicates that can directly refer to a type param. |
71 | TypeParam(LocalTypeParamId), | 72 | TypeParam(LocalTypeParamId), |
72 | // FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef) | ||
73 | } | 73 | } |
74 | 74 | ||
75 | #[derive(Default)] | 75 | #[derive(Default)] |
@@ -234,7 +234,7 @@ impl GenericParams { | |||
234 | for bound in | 234 | for bound in |
235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
236 | { | 236 | { |
237 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 237 | self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
@@ -279,8 +279,25 @@ impl GenericParams { | |||
279 | } else { | 279 | } else { |
280 | continue; | 280 | continue; |
281 | }; | 281 | }; |
282 | |||
283 | let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| { | ||
284 | // Higher-Ranked Trait Bounds | ||
285 | param_list | ||
286 | .lifetime_params() | ||
287 | .map(|lifetime_param| { | ||
288 | lifetime_param | ||
289 | .lifetime() | ||
290 | .map_or_else(Name::missing, |lt| Name::new_lifetime(<)) | ||
291 | }) | ||
292 | .collect() | ||
293 | }); | ||
282 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 294 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
283 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 295 | self.add_where_predicate_from_bound( |
296 | lower_ctx, | ||
297 | bound, | ||
298 | lifetimes.as_ref(), | ||
299 | target.clone(), | ||
300 | ); | ||
284 | } | 301 | } |
285 | } | 302 | } |
286 | } | 303 | } |
@@ -289,6 +306,7 @@ impl GenericParams { | |||
289 | &mut self, | 306 | &mut self, |
290 | lower_ctx: &LowerCtx, | 307 | lower_ctx: &LowerCtx, |
291 | bound: ast::TypeBound, | 308 | bound: ast::TypeBound, |
309 | hrtb_lifetimes: Option<&Box<[Name]>>, | ||
292 | target: Either<TypeRef, LifetimeRef>, | 310 | target: Either<TypeRef, LifetimeRef>, |
293 | ) { | 311 | ) { |
294 | if bound.question_mark_token().is_some() { | 312 | if bound.question_mark_token().is_some() { |
@@ -297,9 +315,16 @@ impl GenericParams { | |||
297 | } | 315 | } |
298 | let bound = TypeBound::from_ast(lower_ctx, bound); | 316 | let bound = TypeBound::from_ast(lower_ctx, bound); |
299 | let predicate = match (target, bound) { | 317 | let predicate = match (target, bound) { |
300 | (Either::Left(type_ref), bound) => WherePredicate::TypeBound { | 318 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { |
301 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 319 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
302 | bound, | 320 | lifetimes: hrtb_lifetimes.clone(), |
321 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
322 | bound, | ||
323 | }, | ||
324 | None => WherePredicate::TypeBound { | ||
325 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
326 | bound, | ||
327 | }, | ||
303 | }, | 328 | }, |
304 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { | 329 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { |
305 | WherePredicate::Lifetime { target: lifetime, bound } | 330 | WherePredicate::Lifetime { target: lifetime, bound } |
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index b4ccd4488..af3262439 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -79,7 +79,7 @@ impl ModDir { | |||
79 | for candidate in candidate_files.iter() { | 79 | for candidate in candidate_files.iter() { |
80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; | 80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; |
81 | if let Some(file_id) = db.resolve_path(path) { | 81 | if let Some(file_id) = db.resolve_path(path) { |
82 | let is_mod_rs = candidate.ends_with("mod.rs"); | 82 | let is_mod_rs = candidate.ends_with("/mod.rs"); |
83 | 83 | ||
84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { | 84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { |
85 | (DirPath::empty(), false) | 85 | (DirPath::empty(), false) |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index dddbbcdac..6382521fb 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -563,6 +563,7 @@ mod tests { | |||
563 | 563 | ||
564 | let args = macro_call.token_tree().unwrap(); | 564 | let args = macro_call.token_tree().unwrap(); |
565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; | 565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; |
566 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)); | ||
566 | 567 | ||
567 | let arg_id = db.intern_eager_expansion({ | 568 | let arg_id = db.intern_eager_expansion({ |
568 | EagerCallLoc { | 569 | EagerCallLoc { |
@@ -570,7 +571,7 @@ mod tests { | |||
570 | fragment: FragmentKind::Expr, | 571 | fragment: FragmentKind::Expr, |
571 | subtree: Arc::new(parsed_args.clone()), | 572 | subtree: Arc::new(parsed_args.clone()), |
572 | krate, | 573 | krate, |
573 | file_id: file_id.into(), | 574 | call: call_id, |
574 | } | 575 | } |
575 | }); | 576 | }); |
576 | 577 | ||
@@ -580,7 +581,7 @@ mod tests { | |||
580 | fragment, | 581 | fragment, |
581 | subtree: Arc::new(subtree), | 582 | subtree: Arc::new(subtree), |
582 | krate, | 583 | krate, |
583 | file_id: file_id.into(), | 584 | call: call_id, |
584 | }; | 585 | }; |
585 | 586 | ||
586 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); | 587 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 4477d867f..077de3727 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -5,7 +5,7 @@ use std::sync::Arc; | |||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, | 11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, |
@@ -129,11 +129,11 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
130 | match id.kind { | 130 | match id.kind { |
131 | MacroDefKind::Declarative => { | 131 | MacroDefKind::Declarative => { |
132 | let macro_call = match id.ast_id?.to_node(db) { | 132 | let macro_rules = match id.ast_id?.to_node(db) { |
133 | syntax::ast::Macro::MacroRules(mac) => mac, | 133 | syntax::ast::Macro::MacroRules(mac) => mac, |
134 | syntax::ast::Macro::MacroDef(_) => return None, | 134 | syntax::ast::Macro::MacroDef(_) => return None, |
135 | }; | 135 | }; |
136 | let arg = macro_call.token_tree()?; | 136 | let arg = macro_rules.token_tree()?; |
137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); |
139 | None | 139 | None |
@@ -141,7 +141,8 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, | |||
141 | let rules = match MacroRules::parse(&tt) { | 141 | let rules = match MacroRules::parse(&tt) { |
142 | Ok(it) => it, | 142 | Ok(it) => it, |
143 | Err(err) => { | 143 | Err(err) => { |
144 | log::warn!("fail on macro_def parse: error: {:#?} {:#?}", err, tt); | 144 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); |
145 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | ||
145 | return None; | 146 | return None; |
146 | } | 147 | } |
147 | }; | 148 | }; |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 0229a836e..6354b090d 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -110,6 +110,9 @@ pub fn expand_eager_macro( | |||
110 | || err("malformed macro invocation"), | 110 | || err("malformed macro invocation"), |
111 | )?; | 111 | )?; |
112 | 112 | ||
113 | let ast_map = db.ast_id_map(macro_call.file_id); | ||
114 | let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); | ||
115 | |||
113 | // Note: | 116 | // Note: |
114 | // When `lazy_expand` is called, its *parent* file must be already exists. | 117 | // When `lazy_expand` is called, its *parent* file must be already exists. |
115 | // Here we store an eager macro id for the argument expanded subtree here | 118 | // Here we store an eager macro id for the argument expanded subtree here |
@@ -120,7 +123,7 @@ pub fn expand_eager_macro( | |||
120 | fragment: FragmentKind::Expr, | 123 | fragment: FragmentKind::Expr, |
121 | subtree: Arc::new(parsed_args.clone()), | 124 | subtree: Arc::new(parsed_args.clone()), |
122 | krate, | 125 | krate, |
123 | file_id: macro_call.file_id, | 126 | call: call_id, |
124 | } | 127 | } |
125 | }); | 128 | }); |
126 | let arg_file_id: MacroCallId = arg_id.into(); | 129 | let arg_file_id: MacroCallId = arg_id.into(); |
@@ -141,13 +144,8 @@ pub fn expand_eager_macro( | |||
141 | let res = eager.expand(db, arg_id, &subtree); | 144 | let res = eager.expand(db, arg_id, &subtree); |
142 | 145 | ||
143 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; | 146 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; |
144 | let eager = EagerCallLoc { | 147 | let eager = |
145 | def, | 148 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), krate, call: call_id }; |
146 | fragment, | ||
147 | subtree: Arc::new(subtree), | ||
148 | krate, | ||
149 | file_id: macro_call.file_id, | ||
150 | }; | ||
151 | 149 | ||
152 | Ok(db.intern_eager_expansion(eager)) | 150 | Ok(db.intern_eager_expansion(eager)) |
153 | } else { | 151 | } else { |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index d486186e5..3fa1b1d77 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -83,7 +83,7 @@ impl HirFileId { | |||
83 | } | 83 | } |
84 | MacroCallId::EagerMacro(id) => { | 84 | MacroCallId::EagerMacro(id) => { |
85 | let loc = db.lookup_intern_eager_expansion(id); | 85 | let loc = db.lookup_intern_eager_expansion(id); |
86 | loc.file_id | 86 | loc.call.file_id |
87 | } | 87 | } |
88 | }; | 88 | }; |
89 | file_id.original_file(db) | 89 | file_id.original_file(db) |
@@ -103,7 +103,7 @@ impl HirFileId { | |||
103 | } | 103 | } |
104 | MacroCallId::EagerMacro(id) => { | 104 | MacroCallId::EagerMacro(id) => { |
105 | let loc = db.lookup_intern_eager_expansion(id); | 105 | let loc = db.lookup_intern_eager_expansion(id); |
106 | loc.file_id | 106 | loc.call.file_id |
107 | } | 107 | } |
108 | }; | 108 | }; |
109 | } | 109 | } |
@@ -114,17 +114,16 @@ impl HirFileId { | |||
114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { | 114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { |
115 | match self.0 { | 115 | match self.0 { |
116 | HirFileIdRepr::FileId(_) => None, | 116 | HirFileIdRepr::FileId(_) => None, |
117 | HirFileIdRepr::MacroFile(macro_file) => { | 117 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { |
118 | let lazy_id = match macro_file.macro_call_id { | 118 | MacroCallId::LazyMacro(lazy_id) => { |
119 | MacroCallId::LazyMacro(id) => id, | 119 | let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); |
120 | MacroCallId::EagerMacro(_id) => { | 120 | Some(loc.kind.node(db)) |
121 | // FIXME: handle call node for eager macro | 121 | } |
122 | return None; | 122 | MacroCallId::EagerMacro(id) => { |
123 | } | 123 | let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id); |
124 | }; | 124 | Some(loc.call.with_value(loc.call.to_node(db).syntax().clone())) |
125 | let loc = db.lookup_intern_macro(lazy_id); | 125 | } |
126 | Some(loc.kind.node(db)) | 126 | }, |
127 | } | ||
128 | } | 127 | } |
129 | } | 128 | } |
130 | 129 | ||
@@ -304,7 +303,7 @@ pub struct EagerCallLoc { | |||
304 | pub(crate) fragment: FragmentKind, | 303 | pub(crate) fragment: FragmentKind, |
305 | pub(crate) subtree: Arc<tt::Subtree>, | 304 | pub(crate) subtree: Arc<tt::Subtree>, |
306 | pub(crate) krate: CrateId, | 305 | pub(crate) krate: CrateId, |
307 | pub(crate) file_id: HirFileId, | 306 | pub(crate) call: AstId<ast::MacroCall>, |
308 | } | 307 | } |
309 | 308 | ||
310 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro | 309 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 289e812fe..965c1780a 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -17,9 +17,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.43", default-features = false } | 20 | chalk-solve = { version = "0.45", default-features = false } |
21 | chalk-ir = "0.43" | 21 | chalk-ir = "0.45" |
22 | chalk-recursive = "0.43" | 22 | chalk-recursive = "0.45" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | hir_def = { path = "../hir_def", version = "0.0.0" } | 25 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 2cdce2cef..70a3f3075 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -143,7 +143,7 @@ impl<'a> InferenceContext<'a> { | |||
143 | self.breakables.push(BreakableContext { | 143 | self.breakables.push(BreakableContext { |
144 | may_break: false, | 144 | may_break: false, |
145 | break_ty: break_ty.clone(), | 145 | break_ty: break_ty.clone(), |
146 | label: label.clone(), | 146 | label: label.map(|label| self.body[label].name.clone()), |
147 | }); | 147 | }); |
148 | let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty)); | 148 | let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty)); |
149 | let ctxt = self.breakables.pop().expect("breakable stack broken"); | 149 | let ctxt = self.breakables.pop().expect("breakable stack broken"); |
@@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> { | |||
155 | } | 155 | } |
156 | None => self.infer_block(statements, *tail, expected), | 156 | None => self.infer_block(statements, *tail, expected), |
157 | }, | 157 | }, |
158 | Expr::Unsafe { body } => self.infer_expr(*body, expected), | 158 | Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), |
159 | Expr::TryBlock { body } => { | 159 | Expr::TryBlock { body } => { |
160 | let _inner = self.infer_expr(*body, expected); | 160 | let _inner = self.infer_expr(*body, expected); |
161 | // FIXME should be std::result::Result<{inner}, _> | 161 | // FIXME should be std::result::Result<{inner}, _> |
@@ -172,7 +172,7 @@ impl<'a> InferenceContext<'a> { | |||
172 | self.breakables.push(BreakableContext { | 172 | self.breakables.push(BreakableContext { |
173 | may_break: false, | 173 | may_break: false, |
174 | break_ty: self.table.new_type_var(), | 174 | break_ty: self.table.new_type_var(), |
175 | label: label.clone(), | 175 | label: label.map(|label| self.body[label].name.clone()), |
176 | }); | 176 | }); |
177 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 177 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
178 | 178 | ||
@@ -191,7 +191,7 @@ impl<'a> InferenceContext<'a> { | |||
191 | self.breakables.push(BreakableContext { | 191 | self.breakables.push(BreakableContext { |
192 | may_break: false, | 192 | may_break: false, |
193 | break_ty: Ty::Unknown, | 193 | break_ty: Ty::Unknown, |
194 | label: label.clone(), | 194 | label: label.map(|label| self.body[label].name.clone()), |
195 | }); | 195 | }); |
196 | // while let is desugared to a match loop, so this is always simple while | 196 | // while let is desugared to a match loop, so this is always simple while |
197 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 197 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
@@ -207,7 +207,7 @@ impl<'a> InferenceContext<'a> { | |||
207 | self.breakables.push(BreakableContext { | 207 | self.breakables.push(BreakableContext { |
208 | may_break: false, | 208 | may_break: false, |
209 | break_ty: Ty::Unknown, | 209 | break_ty: Ty::Unknown, |
210 | label: label.clone(), | 210 | label: label.map(|label| self.body[label].name.clone()), |
211 | }); | 211 | }); |
212 | let pat_ty = | 212 | let pat_ty = |
213 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 213 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index b70ec55eb..d974f805b 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -243,6 +243,9 @@ impl<'a> InferenceContext<'a> { | |||
243 | } | 243 | } |
244 | None => Ty::Unknown, | 244 | None => Ty::Unknown, |
245 | }, | 245 | }, |
246 | Pat::ConstBlock(expr) => { | ||
247 | self.infer_expr(*expr, &Expectation::has_type(expected.clone())) | ||
248 | } | ||
246 | Pat::Missing => Ty::Unknown, | 249 | Pat::Missing => Ty::Unknown, |
247 | }; | 250 | }; |
248 | // use a new type variable if we got Ty::Unknown here | 251 | // use a new type variable if we got Ty::Unknown here |
@@ -264,8 +267,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | |||
264 | | Pat::Range { .. } | 267 | | Pat::Range { .. } |
265 | | Pat::Slice { .. } => true, | 268 | | Pat::Slice { .. } => true, |
266 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), | 269 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), |
267 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | 270 | // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. |
268 | Pat::Path(..) => true, | 271 | Pat::Path(..) => true, |
272 | Pat::ConstBlock(..) => true, | ||
269 | Pat::Lit(expr) => match body[*expr] { | 273 | Pat::Lit(expr) => match body[*expr] { |
270 | Expr::Literal(Literal::String(..)) => false, | 274 | Expr::Literal(Literal::String(..)) => false, |
271 | _ => true, | 275 | _ => true, |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8392cb770..8da56cd11 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -675,7 +675,8 @@ impl GenericPredicate { | |||
675 | where_predicate: &'a WherePredicate, | 675 | where_predicate: &'a WherePredicate, |
676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | 676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
677 | match where_predicate { | 677 | match where_predicate { |
678 | WherePredicate::TypeBound { target, bound } => { | 678 | WherePredicate::ForLifetime { target, bound, .. } |
679 | | WherePredicate::TypeBound { target, bound } => { | ||
679 | let self_ty = match target { | 680 | let self_ty = match target { |
680 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), | 681 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), |
681 | WherePredicateTypeTarget::TypeParam(param_id) => { | 682 | WherePredicateTypeTarget::TypeParam(param_id) => { |
@@ -888,14 +889,13 @@ pub(crate) fn generic_predicates_for_param_query( | |||
888 | .where_predicates_in_scope() | 889 | .where_predicates_in_scope() |
889 | // we have to filter out all other predicates *first*, before attempting to lower them | 890 | // we have to filter out all other predicates *first*, before attempting to lower them |
890 | .filter(|pred| match pred { | 891 | .filter(|pred| match pred { |
891 | WherePredicate::TypeBound { | 892 | WherePredicate::ForLifetime { target, .. } |
892 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 893 | | WherePredicate::TypeBound { target, .. } => match target { |
893 | .. | 894 | WherePredicateTypeTarget::TypeRef(type_ref) => { |
894 | } => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id), | 895 | Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) |
895 | WherePredicate::TypeBound { | 896 | } |
896 | target: WherePredicateTypeTarget::TypeParam(local_id), | 897 | WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id, |
897 | .. | 898 | }, |
898 | } => *local_id == param_id.local_id, | ||
899 | WherePredicate::Lifetime { .. } => false, | 899 | WherePredicate::Lifetime { .. } => false, |
900 | }) | 900 | }) |
901 | .flat_map(|pred| { | 901 | .flat_map(|pred| { |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 5a5f48fd0..2053d8f56 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -774,3 +774,33 @@ fn foo(tuple: Tuple) { | |||
774 | "#]], | 774 | "#]], |
775 | ); | 775 | ); |
776 | } | 776 | } |
777 | |||
778 | #[test] | ||
779 | fn const_block_pattern() { | ||
780 | check_infer( | ||
781 | r#" | ||
782 | struct Foo(usize); | ||
783 | fn foo(foo: Foo) { | ||
784 | match foo { | ||
785 | const { Foo(15 + 32) } => {}, | ||
786 | _ => {} | ||
787 | } | ||
788 | }"#, | ||
789 | expect![[r#" | ||
790 | 26..29 'foo': Foo | ||
791 | 36..115 '{ ... } }': () | ||
792 | 42..113 'match ... }': () | ||
793 | 48..51 'foo': Foo | ||
794 | 62..84 'const ... 32) }': Foo | ||
795 | 68..84 '{ Foo(... 32) }': Foo | ||
796 | 70..73 'Foo': Foo(usize) -> Foo | ||
797 | 70..82 'Foo(15 + 32)': Foo | ||
798 | 74..76 '15': usize | ||
799 | 74..81 '15 + 32': usize | ||
800 | 79..81 '32': usize | ||
801 | 88..90 '{}': () | ||
802 | 100..101 '_': Foo | ||
803 | 105..107 '{}': () | ||
804 | "#]], | ||
805 | ); | ||
806 | } | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a569223b4..a61282d5a 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -1894,6 +1894,7 @@ fn effects_smoke_test() { | |||
1894 | let x = unsafe { 92 }; | 1894 | let x = unsafe { 92 }; |
1895 | let y = async { async { () }.await }; | 1895 | let y = async { async { () }.await }; |
1896 | let z = try { () }; | 1896 | let z = try { () }; |
1897 | let w = const { 92 }; | ||
1897 | let t = 'a: { 92 }; | 1898 | let t = 'a: { 92 }; |
1898 | } | 1899 | } |
1899 | 1900 | ||
@@ -1905,7 +1906,7 @@ fn effects_smoke_test() { | |||
1905 | } | 1906 | } |
1906 | "#, | 1907 | "#, |
1907 | expect![[r#" | 1908 | expect![[r#" |
1908 | 16..136 '{ ...2 }; }': () | 1909 | 16..162 '{ ...2 }; }': () |
1909 | 26..27 'x': i32 | 1910 | 26..27 'x': i32 |
1910 | 30..43 'unsafe { 92 }': i32 | 1911 | 30..43 'unsafe { 92 }': i32 |
1911 | 37..43 '{ 92 }': i32 | 1912 | 37..43 '{ 92 }': i32 |
@@ -1921,9 +1922,13 @@ fn effects_smoke_test() { | |||
1921 | 99..109 'try { () }': {unknown} | 1922 | 99..109 'try { () }': {unknown} |
1922 | 103..109 '{ () }': () | 1923 | 103..109 '{ () }': () |
1923 | 105..107 '()': () | 1924 | 105..107 '()': () |
1924 | 119..120 't': i32 | 1925 | 119..120 'w': i32 |
1925 | 127..133 '{ 92 }': i32 | 1926 | 123..135 'const { 92 }': i32 |
1926 | 129..131 '92': i32 | 1927 | 129..135 '{ 92 }': i32 |
1928 | 131..133 '92': i32 | ||
1929 | 145..146 't': i32 | ||
1930 | 153..159 '{ 92 }': i32 | ||
1931 | 155..157 '92': i32 | ||
1927 | "#]], | 1932 | "#]], |
1928 | ) | 1933 | ) |
1929 | } | 1934 | } |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index 69eae6f79..2196af677 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -56,8 +56,13 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
56 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { | 56 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { |
57 | self.db.struct_datum(self.krate, struct_id) | 57 | self.db.struct_datum(self.krate, struct_id) |
58 | } | 58 | } |
59 | fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr { | 59 | fn adt_repr(&self, _struct_id: AdtId) -> Arc<rust_ir::AdtRepr<Interner>> { |
60 | rust_ir::AdtRepr { repr_c: false, repr_packed: false } | 60 | // FIXME: keep track of these |
61 | Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None }) | ||
62 | } | ||
63 | fn discriminant_type(&self, _ty: chalk_ir::Ty<Interner>) -> chalk_ir::Ty<Interner> { | ||
64 | // FIXME: keep track of this | ||
65 | chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(&Interner) | ||
61 | } | 66 | } |
62 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | 67 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { |
63 | self.db.impl_datum(self.krate, impl_id) | 68 | self.db.impl_datum(self.krate, impl_id) |
@@ -457,6 +462,7 @@ fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> { | |||
457 | "fn" => WellKnownTrait::Fn, | 462 | "fn" => WellKnownTrait::Fn, |
458 | "unsize" => WellKnownTrait::Unsize, | 463 | "unsize" => WellKnownTrait::Unsize, |
459 | "coerce_unsized" => WellKnownTrait::CoerceUnsized, | 464 | "coerce_unsized" => WellKnownTrait::CoerceUnsized, |
465 | "discriminant_kind" => WellKnownTrait::DiscriminantKind, | ||
460 | _ => return None, | 466 | _ => return None, |
461 | }) | 467 | }) |
462 | } | 468 | } |
@@ -473,6 +479,7 @@ fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | |||
473 | WellKnownTrait::Unsize => "unsize", | 479 | WellKnownTrait::Unsize => "unsize", |
474 | WellKnownTrait::Unpin => "unpin", | 480 | WellKnownTrait::Unpin => "unpin", |
475 | WellKnownTrait::CoerceUnsized => "coerce_unsized", | 481 | WellKnownTrait::CoerceUnsized => "coerce_unsized", |
482 | WellKnownTrait::DiscriminantKind => "discriminant_kind", | ||
476 | } | 483 | } |
477 | } | 484 | } |
478 | 485 | ||
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index af880c065..65b79df0d 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs | |||
@@ -5,7 +5,9 @@ use std::sync::Arc; | |||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | adt::VariantData, | 6 | adt::VariantData, |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget}, | 8 | generics::{ |
9 | GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, | ||
10 | }, | ||
9 | path::Path, | 11 | path::Path, |
10 | resolver::{HasResolver, TypeNs}, | 12 | resolver::{HasResolver, TypeNs}, |
11 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
@@ -27,7 +29,8 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
27 | .where_predicates | 29 | .where_predicates |
28 | .iter() | 30 | .iter() |
29 | .filter_map(|pred| match pred { | 31 | .filter_map(|pred| match pred { |
30 | hir_def::generics::WherePredicate::TypeBound { target, bound } => match target { | 32 | WherePredicate::ForLifetime { target, bound, .. } |
33 | | WherePredicate::TypeBound { target, bound } => match target { | ||
31 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) | 34 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) |
32 | if p == &Path::from(name![Self]) => | 35 | if p == &Path::from(name![Self]) => |
33 | { | 36 | { |
@@ -38,7 +41,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
38 | } | 41 | } |
39 | _ => None, | 42 | _ => None, |
40 | }, | 43 | }, |
41 | hir_def::generics::WherePredicate::Lifetime { .. } => None, | 44 | WherePredicate::Lifetime { .. } => None, |
42 | }) | 45 | }) |
43 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { | 46 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { |
44 | Some(TypeNs::TraitId(t)) => Some(t), | 47 | Some(TypeNs::TraitId(t)) => Some(t), |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 049f808dc..038273750 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -248,35 +248,7 @@ mod tests { | |||
248 | /// * a diagnostic is produced | 248 | /// * a diagnostic is produced |
249 | /// * this diagnostic fix trigger range touches the input cursor position | 249 | /// * this diagnostic fix trigger range touches the input cursor position |
250 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | 250 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied |
251 | pub(super) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | 251 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { |
252 | let after = trim_indent(ra_fixture_after); | ||
253 | |||
254 | let (analysis, file_position) = fixture::position(ra_fixture_before); | ||
255 | let diagnostic = analysis | ||
256 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) | ||
257 | .unwrap() | ||
258 | .pop() | ||
259 | .unwrap(); | ||
260 | let mut fix = diagnostic.fix.unwrap(); | ||
261 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; | ||
262 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | ||
263 | let actual = { | ||
264 | let mut actual = target_file_contents.to_string(); | ||
265 | edit.apply(&mut actual); | ||
266 | actual | ||
267 | }; | ||
268 | |||
269 | assert_eq_text!(&after, &actual); | ||
270 | assert!( | ||
271 | fix.fix_trigger_range.contains_inclusive(file_position.offset), | ||
272 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
273 | fix.fix_trigger_range, | ||
274 | file_position.offset | ||
275 | ); | ||
276 | } | ||
277 | |||
278 | /// Similar to `check_fix`, but applies all the available fixes. | ||
279 | fn check_fixes(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
280 | let after = trim_indent(ra_fixture_after); | 252 | let after = trim_indent(ra_fixture_after); |
281 | 253 | ||
282 | let (analysis, file_position) = fixture::position(ra_fixture_before); | 254 | let (analysis, file_position) = fixture::position(ra_fixture_before); |
@@ -286,10 +258,12 @@ mod tests { | |||
286 | .pop() | 258 | .pop() |
287 | .unwrap(); | 259 | .unwrap(); |
288 | let fix = diagnostic.fix.unwrap(); | 260 | let fix = diagnostic.fix.unwrap(); |
289 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | ||
290 | let actual = { | 261 | let actual = { |
291 | let mut actual = target_file_contents.to_string(); | 262 | let file_id = fix.source_change.source_file_edits.first().unwrap().file_id; |
263 | let mut actual = analysis.file_text(file_id).unwrap().to_string(); | ||
264 | |||
292 | // Go from the last one to the first one, so that ranges won't be affected by previous edits. | 265 | // Go from the last one to the first one, so that ranges won't be affected by previous edits. |
266 | // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/4901#issuecomment-644675309 | ||
293 | for edit in fix.source_change.source_file_edits.iter().rev() { | 267 | for edit in fix.source_change.source_file_edits.iter().rev() { |
294 | edit.edit.apply(&mut actual); | 268 | edit.edit.apply(&mut actual); |
295 | } | 269 | } |
@@ -305,29 +279,6 @@ mod tests { | |||
305 | ); | 279 | ); |
306 | } | 280 | } |
307 | 281 | ||
308 | /// Checks that a diagnostic applies to the file containing the `<|>` cursor marker | ||
309 | /// which has a fix that can apply to other files. | ||
310 | fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
311 | let ra_fixture_after = &trim_indent(ra_fixture_after); | ||
312 | let (analysis, file_pos) = fixture::position(ra_fixture_before); | ||
313 | let current_file_id = file_pos.file_id; | ||
314 | let diagnostic = analysis | ||
315 | .diagnostics(&DiagnosticsConfig::default(), current_file_id) | ||
316 | .unwrap() | ||
317 | .pop() | ||
318 | .unwrap(); | ||
319 | let mut fix = diagnostic.fix.unwrap(); | ||
320 | let edit = fix.source_change.source_file_edits.pop().unwrap(); | ||
321 | let changed_file_id = edit.file_id; | ||
322 | let before = analysis.file_text(changed_file_id).unwrap(); | ||
323 | let actual = { | ||
324 | let mut actual = before.to_string(); | ||
325 | edit.edit.apply(&mut actual); | ||
326 | actual | ||
327 | }; | ||
328 | assert_eq_text!(ra_fixture_after, &actual); | ||
329 | } | ||
330 | |||
331 | /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics | 282 | /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics |
332 | /// apply to the file containing the cursor. | 283 | /// apply to the file containing the cursor. |
333 | pub(crate) fn check_no_diagnostics(ra_fixture: &str) { | 284 | pub(crate) fn check_no_diagnostics(ra_fixture: &str) { |
@@ -619,6 +570,7 @@ fn test_fn() { | |||
619 | ), | 570 | ), |
620 | path: "foo.rs", | 571 | path: "foo.rs", |
621 | }, | 572 | }, |
573 | initial_contents: "", | ||
622 | }, | 574 | }, |
623 | ], | 575 | ], |
624 | is_snippet: false, | 576 | is_snippet: false, |
@@ -763,25 +715,25 @@ struct Foo { | |||
763 | 715 | ||
764 | #[test] | 716 | #[test] |
765 | fn test_add_field_in_other_file_from_usage() { | 717 | fn test_add_field_in_other_file_from_usage() { |
766 | check_apply_diagnostic_fix_in_other_file( | 718 | check_fix( |
767 | r" | 719 | r#" |
768 | //- /main.rs | 720 | //- /main.rs |
769 | mod foo; | 721 | mod foo; |
770 | 722 | ||
771 | fn main() { | 723 | fn main() { |
772 | <|>foo::Foo { bar: 3, baz: false}; | 724 | foo::Foo { bar: 3, <|>baz: false}; |
773 | } | 725 | } |
774 | //- /foo.rs | 726 | //- /foo.rs |
775 | struct Foo { | 727 | struct Foo { |
776 | bar: i32 | 728 | bar: i32 |
777 | } | 729 | } |
778 | ", | 730 | "#, |
779 | r" | 731 | r#" |
780 | struct Foo { | 732 | struct Foo { |
781 | bar: i32, | 733 | bar: i32, |
782 | pub(crate) baz: bool | 734 | pub(crate) baz: bool |
783 | } | 735 | } |
784 | ", | 736 | "#, |
785 | ) | 737 | ) |
786 | } | 738 | } |
787 | 739 | ||
@@ -801,7 +753,7 @@ struct Foo { | |||
801 | 753 | ||
802 | #[test] | 754 | #[test] |
803 | fn test_rename_incorrect_case() { | 755 | fn test_rename_incorrect_case() { |
804 | check_fixes( | 756 | check_fix( |
805 | r#" | 757 | r#" |
806 | pub struct test_struct<|> { one: i32 } | 758 | pub struct test_struct<|> { one: i32 } |
807 | 759 | ||
@@ -818,7 +770,7 @@ pub fn some_fn(val: TestStruct) -> TestStruct { | |||
818 | "#, | 770 | "#, |
819 | ); | 771 | ); |
820 | 772 | ||
821 | check_fixes( | 773 | check_fix( |
822 | r#" | 774 | r#" |
823 | pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { | 775 | pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { |
824 | NonSnakeCase | 776 | NonSnakeCase |
@@ -831,7 +783,7 @@ pub fn some_fn(non_snake_case: u8) -> u8 { | |||
831 | "#, | 783 | "#, |
832 | ); | 784 | ); |
833 | 785 | ||
834 | check_fixes( | 786 | check_fix( |
835 | r#" | 787 | r#" |
836 | pub fn SomeFn<|>(val: u8) -> u8 { | 788 | pub fn SomeFn<|>(val: u8) -> u8 { |
837 | if val != 0 { SomeFn(val - 1) } else { val } | 789 | if val != 0 { SomeFn(val - 1) } else { val } |
@@ -844,7 +796,7 @@ pub fn some_fn(val: u8) -> u8 { | |||
844 | "#, | 796 | "#, |
845 | ); | 797 | ); |
846 | 798 | ||
847 | check_fixes( | 799 | check_fix( |
848 | r#" | 800 | r#" |
849 | fn some_fn() { | 801 | fn some_fn() { |
850 | let whatAWeird_Formatting<|> = 10; | 802 | let whatAWeird_Formatting<|> = 10; |
@@ -873,7 +825,7 @@ fn foo() { | |||
873 | 825 | ||
874 | #[test] | 826 | #[test] |
875 | fn test_rename_incorrect_case_struct_method() { | 827 | fn test_rename_incorrect_case_struct_method() { |
876 | check_fixes( | 828 | check_fix( |
877 | r#" | 829 | r#" |
878 | pub struct TestStruct; | 830 | pub struct TestStruct; |
879 | 831 | ||
@@ -894,4 +846,17 @@ impl TestStruct { | |||
894 | "#, | 846 | "#, |
895 | ); | 847 | ); |
896 | } | 848 | } |
849 | |||
850 | #[test] | ||
851 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | ||
852 | let input = r#"fn FOO<|>() {}"#; | ||
853 | let expected = r#"fn foo() {}"#; | ||
854 | |||
855 | let (analysis, file_position) = fixture::position(input); | ||
856 | let diagnostics = | ||
857 | analysis.diagnostics(&DiagnosticsConfig::default(), file_position.file_id).unwrap(); | ||
858 | assert_eq!(diagnostics.len(), 1); | ||
859 | |||
860 | check_fix(input, expected); | ||
861 | } | ||
897 | } | 862 | } |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index e8b896623..d79f5c170 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -40,6 +40,7 @@ impl DiagnosticWithFix for UnresolvedModule { | |||
40 | anchor: self.file.original_file(sema.db), | 40 | anchor: self.file.original_file(sema.db), |
41 | path: self.candidate.clone(), | 41 | path: self.candidate.clone(), |
42 | }, | 42 | }, |
43 | initial_contents: "".to_string(), | ||
43 | } | 44 | } |
44 | .into(), | 45 | .into(), |
45 | unresolved_module.syntax().text_range(), | 46 | unresolved_module.syntax().text_range(), |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index cd8ec54fa..6431e7d6d 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -5,7 +5,7 @@ use std::fmt; | |||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource}; | 6 | use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource}; |
7 | use ide_db::{ | 7 | use ide_db::{ |
8 | base_db::{FileId, SourceDatabase}, | 8 | base_db::{FileId, FileRange, SourceDatabase}, |
9 | symbol_index::FileSymbolKind, | 9 | symbol_index::FileSymbolKind, |
10 | }; | 10 | }; |
11 | use ide_db::{defs::Definition, RootDatabase}; | 11 | use ide_db::{defs::Definition, RootDatabase}; |
@@ -28,6 +28,7 @@ pub enum SymbolKind { | |||
28 | ValueParam, | 28 | ValueParam, |
29 | SelfParam, | 29 | SelfParam, |
30 | Local, | 30 | Local, |
31 | Label, | ||
31 | Function, | 32 | Function, |
32 | Const, | 33 | Const, |
33 | Static, | 34 | Static, |
@@ -223,6 +224,7 @@ impl TryToNav for Definition { | |||
223 | Definition::Local(it) => Some(it.to_nav(db)), | 224 | Definition::Local(it) => Some(it.to_nav(db)), |
224 | Definition::TypeParam(it) => Some(it.to_nav(db)), | 225 | Definition::TypeParam(it) => Some(it.to_nav(db)), |
225 | Definition::LifetimeParam(it) => Some(it.to_nav(db)), | 226 | Definition::LifetimeParam(it) => Some(it.to_nav(db)), |
227 | Definition::Label(it) => Some(it.to_nav(db)), | ||
226 | } | 228 | } |
227 | } | 229 | } |
228 | } | 230 | } |
@@ -421,6 +423,27 @@ impl ToNav for hir::Local { | |||
421 | } | 423 | } |
422 | } | 424 | } |
423 | 425 | ||
426 | impl ToNav for hir::Label { | ||
427 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
428 | let src = self.source(db); | ||
429 | let node = src.value.syntax(); | ||
430 | let FileRange { file_id, range } = src.with_value(node).original_file_range(db); | ||
431 | let focus_range = | ||
432 | src.value.lifetime().and_then(|lt| lt.lifetime_ident_token()).map(|lt| lt.text_range()); | ||
433 | let name = self.name(db).to_string().into(); | ||
434 | NavigationTarget { | ||
435 | file_id, | ||
436 | name, | ||
437 | kind: Some(SymbolKind::Label), | ||
438 | full_range: range, | ||
439 | focus_range, | ||
440 | container_name: None, | ||
441 | description: None, | ||
442 | docs: None, | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
424 | impl ToNav for hir::TypeParam { | 447 | impl ToNav for hir::TypeParam { |
425 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 448 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
426 | let src = self.source(db); | 449 | let src = self.source(db); |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index b61ea0b3e..e10516f43 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -193,7 +193,8 @@ fn rewrite_intra_doc_link( | |||
193 | Definition::SelfType(_) | 193 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 194 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 195 | | Definition::TypeParam(_) |
196 | | Definition::LifetimeParam(_) => return None, | 196 | | Definition::LifetimeParam(_) |
197 | | Definition::Label(_) => return None, | ||
197 | }?; | 198 | }?; |
198 | let krate = resolved.module(db)?.krate(); | 199 | let krate = resolved.module(db)?.krate(); |
199 | let canonical_path = resolved.canonical_path(db)?; | 200 | let canonical_path = resolved.canonical_path(db)?; |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 7a12e9965..912144f8b 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -750,6 +750,31 @@ fn test() { | |||
750 | } | 750 | } |
751 | 751 | ||
752 | #[test] | 752 | #[test] |
753 | fn goto_through_included_file() { | ||
754 | check( | ||
755 | r#" | ||
756 | //- /main.rs | ||
757 | #[rustc_builtin_macro] | ||
758 | macro_rules! include {} | ||
759 | |||
760 | include!("foo.rs"); | ||
761 | //^^^^^^^^^^^^^^^^^^^ | ||
762 | |||
763 | fn f() { | ||
764 | foo<|>(); | ||
765 | } | ||
766 | |||
767 | mod confuse_index { | ||
768 | pub fn foo() {} | ||
769 | } | ||
770 | |||
771 | //- /foo.rs | ||
772 | fn foo() {} | ||
773 | "#, | ||
774 | ); | ||
775 | } | ||
776 | |||
777 | #[test] | ||
753 | fn goto_for_type_param() { | 778 | fn goto_for_type_param() { |
754 | check( | 779 | check( |
755 | r#" | 780 | r#" |
@@ -1077,4 +1102,47 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1077 | }"#, | 1102 | }"#, |
1078 | ) | 1103 | ) |
1079 | } | 1104 | } |
1105 | |||
1106 | #[test] | ||
1107 | #[ignore] // requires the HIR to somehow track these hrtb lifetimes | ||
1108 | fn goto_lifetime_hrtb() { | ||
1109 | check( | ||
1110 | r#"trait Foo<T> {} | ||
1111 | fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} | ||
1112 | //^^ | ||
1113 | "#, | ||
1114 | ); | ||
1115 | check( | ||
1116 | r#"trait Foo<T> {} | ||
1117 | fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | ||
1118 | //^^ | ||
1119 | "#, | ||
1120 | ); | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1124 | #[ignore] // requires ForTypes to be implemented | ||
1125 | fn goto_lifetime_hrtb_for_type() { | ||
1126 | check( | ||
1127 | r#"trait Foo<T> {} | ||
1128 | fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} | ||
1129 | //^^ | ||
1130 | "#, | ||
1131 | ); | ||
1132 | } | ||
1133 | |||
1134 | #[test] | ||
1135 | fn goto_label() { | ||
1136 | check( | ||
1137 | r#" | ||
1138 | fn foo<'foo>(_: &'foo ()) { | ||
1139 | 'foo: { | ||
1140 | //^^^^ | ||
1141 | 'bar: loop { | ||
1142 | break 'foo<|>; | ||
1143 | } | ||
1144 | } | ||
1145 | }"#, | ||
1146 | ) | ||
1147 | } | ||
1080 | } | 1148 | } |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 52f993cc9..73245fbe7 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -370,7 +370,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 370 | Adt::Enum(it) => from_def_source(db, it, mod_path), |
371 | }) | 371 | }) |
372 | } | 372 | } |
373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) => { | 373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { |
374 | // FIXME: Hover for generic param | 374 | // FIXME: Hover for generic param |
375 | None | 375 | None |
376 | } | 376 | } |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index dbad9a84f..41eb139d1 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -79,7 +79,7 @@ pub use crate::{ | |||
79 | HighlightedRange, | 79 | HighlightedRange, |
80 | }, | 80 | }, |
81 | }; | 81 | }; |
82 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist}; | 82 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; |
83 | pub use completion::{ | 83 | pub use completion::{ |
84 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability, | 84 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability, |
85 | CompletionScore, ImportEdit, InsertTextFormat, | 85 | CompletionScore, ImportEdit, InsertTextFormat, |
@@ -490,23 +490,17 @@ impl Analysis { | |||
490 | .unwrap_or_default()) | 490 | .unwrap_or_default()) |
491 | } | 491 | } |
492 | 492 | ||
493 | /// Computes resolved assists with source changes for the given position. | 493 | /// Computes assists (aka code actions aka intentions) for the given |
494 | pub fn resolved_assists( | 494 | /// position. If `resolve == false`, computes enough info to show the |
495 | &self, | 495 | /// lightbulb list in the editor, but doesn't compute actual edits, to |
496 | config: &AssistConfig, | 496 | /// improve performance. |
497 | frange: FileRange, | 497 | pub fn assists( |
498 | ) -> Cancelable<Vec<ResolvedAssist>> { | ||
499 | self.with_db(|db| assists::Assist::resolved(db, config, frange)) | ||
500 | } | ||
501 | |||
502 | /// Computes unresolved assists (aka code actions aka intentions) for the given | ||
503 | /// position. | ||
504 | pub fn unresolved_assists( | ||
505 | &self, | 498 | &self, |
506 | config: &AssistConfig, | 499 | config: &AssistConfig, |
500 | resolve: bool, | ||
507 | frange: FileRange, | 501 | frange: FileRange, |
508 | ) -> Cancelable<Vec<Assist>> { | 502 | ) -> Cancelable<Vec<Assist>> { |
509 | self.with_db(|db| Assist::unresolved(db, config, frange)) | 503 | self.with_db(|db| Assist::get(db, config, resolve, frange)) |
510 | } | 504 | } |
511 | 505 | ||
512 | /// Computes the set of diagnostics for the given file. | 506 | /// Computes the set of diagnostics for the given file. |
@@ -535,6 +529,14 @@ impl Analysis { | |||
535 | self.with_db(|db| references::rename::prepare_rename(db, position)) | 529 | self.with_db(|db| references::rename::prepare_rename(db, position)) |
536 | } | 530 | } |
537 | 531 | ||
532 | pub fn will_rename_file( | ||
533 | &self, | ||
534 | file_id: FileId, | ||
535 | new_name_stem: &str, | ||
536 | ) -> Cancelable<Option<SourceChange>> { | ||
537 | self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem)) | ||
538 | } | ||
539 | |||
538 | pub fn structural_search_replace( | 540 | pub fn structural_search_replace( |
539 | &self, | 541 | &self, |
540 | query: &str, | 542 | query: &str, |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 18ea19305..21b2d7ca1 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -130,7 +130,7 @@ pub(crate) fn find_all_refs( | |||
130 | kind = ReferenceKind::FieldShorthandForLocal; | 130 | kind = ReferenceKind::FieldShorthandForLocal; |
131 | } | 131 | } |
132 | } | 132 | } |
133 | } else if let Definition::LifetimeParam(_) = def { | 133 | } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { |
134 | kind = ReferenceKind::Lifetime; | 134 | kind = ReferenceKind::Lifetime; |
135 | }; | 135 | }; |
136 | 136 | ||
@@ -147,20 +147,20 @@ fn find_name( | |||
147 | ) -> Option<RangeInfo<Definition>> { | 147 | ) -> Option<RangeInfo<Definition>> { |
148 | if let Some(name) = opt_name { | 148 | if let Some(name) = opt_name { |
149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); | 149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); |
150 | let range = name.syntax().text_range(); | 150 | let FileRange { range, .. } = sema.original_range(name.syntax()); |
151 | return Some(RangeInfo::new(range, def)); | 151 | return Some(RangeInfo::new(range, def)); |
152 | } | 152 | } |
153 | 153 | ||
154 | let (text_range, def) = if let Some(lifetime) = | 154 | let (FileRange { range, .. }, def) = if let Some(lifetime) = |
155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) | 155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) |
156 | { | 156 | { |
157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) | 157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) |
158 | .map(|class| NameRefClass::referenced(class, sema.db)) | 158 | .map(|class| NameRefClass::referenced(class, sema.db)) |
159 | { | 159 | { |
160 | (lifetime.syntax().text_range(), def) | 160 | (sema.original_range(lifetime.syntax()), def) |
161 | } else { | 161 | } else { |
162 | ( | 162 | ( |
163 | lifetime.syntax().text_range(), | 163 | sema.original_range(lifetime.syntax()), |
164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), | 164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), |
165 | ) | 165 | ) |
166 | } | 166 | } |
@@ -168,11 +168,11 @@ fn find_name( | |||
168 | let name_ref = | 168 | let name_ref = |
169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; | 169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; |
170 | ( | 170 | ( |
171 | name_ref.syntax().text_range(), | 171 | sema.original_range(name_ref.syntax()), |
172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | 172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), |
173 | ) | 173 | ) |
174 | }; | 174 | }; |
175 | Some(RangeInfo::new(text_range, def)) | 175 | Some(RangeInfo::new(range, def)) |
176 | } | 176 | } |
177 | 177 | ||
178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { | 178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { |
@@ -1086,4 +1086,62 @@ impl<'a> Foo<'a> for &'a () { | |||
1086 | "#]], | 1086 | "#]], |
1087 | ); | 1087 | ); |
1088 | } | 1088 | } |
1089 | |||
1090 | #[test] | ||
1091 | fn test_map_range_to_original() { | ||
1092 | check( | ||
1093 | r#" | ||
1094 | macro_rules! foo {($i:ident) => {$i} } | ||
1095 | fn main() { | ||
1096 | let a<|> = "test"; | ||
1097 | foo!(a); | ||
1098 | } | ||
1099 | "#, | ||
1100 | expect![[r#" | ||
1101 | a Local FileId(0) 59..60 Other | ||
1102 | |||
1103 | FileId(0) 80..81 Other Read | ||
1104 | "#]], | ||
1105 | ); | ||
1106 | } | ||
1107 | |||
1108 | #[test] | ||
1109 | fn test_map_range_to_original_ref() { | ||
1110 | check( | ||
1111 | r#" | ||
1112 | macro_rules! foo {($i:ident) => {$i} } | ||
1113 | fn main() { | ||
1114 | let a = "test"; | ||
1115 | foo!(a<|>); | ||
1116 | } | ||
1117 | "#, | ||
1118 | expect![[r#" | ||
1119 | a Local FileId(0) 59..60 Other | ||
1120 | |||
1121 | FileId(0) 80..81 Other Read | ||
1122 | "#]], | ||
1123 | ); | ||
1124 | } | ||
1125 | |||
1126 | #[test] | ||
1127 | fn test_find_labels() { | ||
1128 | check( | ||
1129 | r#" | ||
1130 | fn foo<'a>() -> &'a () { | ||
1131 | 'a: loop { | ||
1132 | 'b: loop { | ||
1133 | continue 'a<|>; | ||
1134 | } | ||
1135 | break 'a; | ||
1136 | } | ||
1137 | } | ||
1138 | "#, | ||
1139 | expect![[r#" | ||
1140 | 'a Label FileId(0) 29..32 29..31 Lifetime | ||
1141 | |||
1142 | FileId(0) 80..82 Lifetime | ||
1143 | FileId(0) 108..110 Lifetime | ||
1144 | "#]], | ||
1145 | ); | ||
1146 | } | ||
1089 | } | 1147 | } |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index cd721b7eb..854bf194e 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -6,7 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
9 | use ide_db::base_db::{AnchoredPathBuf, FileRange, SourceDatabaseExt}; | 9 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; |
10 | use ide_db::{ | 10 | use ide_db::{ |
11 | defs::{Definition, NameClass, NameRefClass}, | 11 | defs::{Definition, NameClass, NameRefClass}, |
12 | RootDatabase, | 12 | RootDatabase, |
@@ -110,6 +110,23 @@ pub(crate) fn rename_with_semantics( | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | pub(crate) fn will_rename_file( | ||
114 | db: &RootDatabase, | ||
115 | file_id: FileId, | ||
116 | new_name_stem: &str, | ||
117 | ) -> Option<SourceChange> { | ||
118 | let sema = Semantics::new(db); | ||
119 | let module = sema.to_module_def(file_id)?; | ||
120 | |||
121 | let decl = module.declaration_source(db)?; | ||
122 | let range = decl.value.name()?.syntax().text_range(); | ||
123 | |||
124 | let position = FilePosition { file_id: decl.file_id.original_file(db), offset: range.start() }; | ||
125 | let mut change = rename_mod(&sema, position, module, new_name_stem).ok()?.info; | ||
126 | change.file_system_edits.clear(); | ||
127 | Some(change) | ||
128 | } | ||
129 | |||
113 | fn find_module_at_offset( | 130 | fn find_module_at_offset( |
114 | sema: &Semantics<RootDatabase>, | 131 | sema: &Semantics<RootDatabase>, |
115 | position: FilePosition, | 132 | position: FilePosition, |
@@ -1523,4 +1540,29 @@ fn main() { | |||
1523 | }"#, | 1540 | }"#, |
1524 | ); | 1541 | ); |
1525 | } | 1542 | } |
1543 | |||
1544 | #[test] | ||
1545 | fn test_rename_label() { | ||
1546 | check( | ||
1547 | "'foo", | ||
1548 | r#" | ||
1549 | fn foo<'a>() -> &'a () { | ||
1550 | 'a: { | ||
1551 | 'b: loop { | ||
1552 | break 'a<|>; | ||
1553 | } | ||
1554 | } | ||
1555 | } | ||
1556 | "#, | ||
1557 | r#" | ||
1558 | fn foo<'a>() -> &'a () { | ||
1559 | 'foo: { | ||
1560 | 'b: loop { | ||
1561 | break 'foo; | ||
1562 | } | ||
1563 | } | ||
1564 | } | ||
1565 | "#, | ||
1566 | ) | ||
1567 | } | ||
1526 | } | 1568 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 2f2b99130..891183266 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -193,7 +193,7 @@ fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Op | |||
193 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { | 193 | if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { |
194 | if let Some(adt) = imp.target_ty(sema.db).as_adt() { | 194 | if let Some(adt) = imp.target_ty(sema.db).as_adt() { |
195 | let name = adt.name(sema.db).to_string(); | 195 | let name = adt.name(sema.db).to_string(); |
196 | let idx = path.rfind(':').unwrap_or(0); | 196 | let idx = path.rfind(':').map_or(0, |idx| idx + 1); |
197 | let (prefix, suffix) = path.split_at(idx); | 197 | let (prefix, suffix) = path.split_at(idx); |
198 | return format!("{}{}::{}", prefix, name, suffix); | 198 | return format!("{}{}::{}", prefix, name, suffix); |
199 | } | 199 | } |
@@ -931,4 +931,42 @@ mod test_mod { | |||
931 | "#]], | 931 | "#]], |
932 | ); | 932 | ); |
933 | } | 933 | } |
934 | |||
935 | #[test] | ||
936 | fn test_doc_runnables_impl_mod() { | ||
937 | check( | ||
938 | r#" | ||
939 | //- /lib.rs | ||
940 | mod foo; | ||
941 | //- /foo.rs | ||
942 | struct Foo;<|> | ||
943 | impl Foo { | ||
944 | /// ``` | ||
945 | /// let x = 5; | ||
946 | /// ``` | ||
947 | fn foo() {} | ||
948 | } | ||
949 | "#, | ||
950 | &[&DOCTEST], | ||
951 | expect![[r#" | ||
952 | [ | ||
953 | Runnable { | ||
954 | nav: NavigationTarget { | ||
955 | file_id: FileId( | ||
956 | 1, | ||
957 | ), | ||
958 | full_range: 27..81, | ||
959 | name: "foo", | ||
960 | }, | ||
961 | kind: DocTest { | ||
962 | test_id: Path( | ||
963 | "foo::Foo::foo", | ||
964 | ), | ||
965 | }, | ||
966 | cfg: None, | ||
967 | }, | ||
968 | ] | ||
969 | "#]], | ||
970 | ); | ||
971 | } | ||
934 | } | 972 | } |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 00c717c7c..5ad96581b 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -560,10 +560,20 @@ fn highlight_element( | |||
560 | CHAR => HighlightTag::CharLiteral.into(), | 560 | CHAR => HighlightTag::CharLiteral.into(), |
561 | QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow, | 561 | QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow, |
562 | LIFETIME => { | 562 | LIFETIME => { |
563 | let h = Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)); | 563 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); |
564 | match element.parent().map(|it| it.kind()) { | 564 | |
565 | Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition, | 565 | match NameClass::classify_lifetime(sema, &lifetime) { |
566 | _ => h, | 566 | Some(NameClass::Definition(def)) => { |
567 | highlight_def(db, def) | HighlightModifier::Definition | ||
568 | } | ||
569 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | ||
570 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | ||
571 | _ => Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)), | ||
572 | }, | ||
573 | _ => { | ||
574 | Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)) | ||
575 | | HighlightModifier::Definition | ||
576 | } | ||
567 | } | 577 | } |
568 | } | 578 | } |
569 | p if p.is_punct() => match p { | 579 | p if p.is_punct() => match p { |
@@ -825,6 +835,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
825 | return h; | 835 | return h; |
826 | } | 836 | } |
827 | Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam), | 837 | Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam), |
838 | Definition::Label(_) => HighlightTag::Symbol(SymbolKind::Label), | ||
828 | } | 839 | } |
829 | .into() | 840 | .into() |
830 | } | 841 | } |
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index abcc5cccc..99ba3a59d 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -64,6 +64,7 @@ body { margin: 0; } | |||
64 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 64 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
65 | 65 | ||
66 | .lifetime { color: #DFAF8F; font-style: italic; } | 66 | .lifetime { color: #DFAF8F; font-style: italic; } |
67 | .label { color: #DFAF8F; font-style: italic; } | ||
67 | .comment { color: #7F9F7F; } | 68 | .comment { color: #7F9F7F; } |
68 | .documentation { color: #629755; } | 69 | .documentation { color: #629755; } |
69 | .injected { opacity: 0.65 ; } | 70 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 974f54fa0..2a6cc0cab 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -80,6 +80,7 @@ impl HighlightTag { | |||
80 | SymbolKind::LifetimeParam => "lifetime", | 80 | SymbolKind::LifetimeParam => "lifetime", |
81 | SymbolKind::Macro => "macro", | 81 | SymbolKind::Macro => "macro", |
82 | SymbolKind::Local => "variable", | 82 | SymbolKind::Local => "variable", |
83 | SymbolKind::Label => "label", | ||
83 | SymbolKind::ValueParam => "value_param", | 84 | SymbolKind::ValueParam => "value_param", |
84 | SymbolKind::SelfParam => "self_keyword", | 85 | SymbolKind::SelfParam => "self_keyword", |
85 | SymbolKind::Impl => "self_type", | 86 | SymbolKind::Impl => "self_type", |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index db6f32d33..506ebe60e 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 4e511baa9..4dd7413ba 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index 800d894c7..ed452586a 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 7f18ad297..92e7dc3e4 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index c843b5085..31dad5d42 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index d26f48516..e3a0aa317 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 588e86a34..72ff9dd40 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
@@ -194,6 +195,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
194 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> | 195 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> |
195 | 196 | ||
196 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> | 197 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> |
198 | |||
199 | <span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span> | ||
200 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span> | ||
201 | <span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span> | ||
202 | <span class="punctuation">}</span> | ||
197 | <span class="punctuation">}</span> | 203 | <span class="punctuation">}</span> |
198 | 204 | ||
199 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 205 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index c7589605f..8b3dfa69f 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -4,6 +4,7 @@ body { margin: 0; } | |||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | 5 | ||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | 6 | .lifetime { color: #DFAF8F; font-style: italic; } |
7 | .label { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
8 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
9 | .injected { opacity: 0.65 ; } | 10 | .injected { opacity: 0.65 ; } |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index f53d2c3ba..e0df0d2b5 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -168,6 +168,11 @@ fn main() { | |||
168 | let baz = -baz; | 168 | let baz = -baz; |
169 | 169 | ||
170 | let _ = !true; | 170 | let _ = !true; |
171 | |||
172 | 'foo: loop { | ||
173 | break 'foo; | ||
174 | continue 'foo; | ||
175 | } | ||
171 | } | 176 | } |
172 | 177 | ||
173 | enum Option<T> { | 178 | enum Option<T> { |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 9d7dce1d4..d33a6cb86 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | db::HirDatabase, Crate, Field, HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module, | 9 | db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, |
10 | ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, | 10 | Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode}, | 13 | ast::{self, AstNode}, |
@@ -26,7 +26,7 @@ pub enum Definition { | |||
26 | Local(Local), | 26 | Local(Local), |
27 | TypeParam(TypeParam), | 27 | TypeParam(TypeParam), |
28 | LifetimeParam(LifetimeParam), | 28 | LifetimeParam(LifetimeParam), |
29 | // FIXME: Label | 29 | Label(Label), |
30 | } | 30 | } |
31 | 31 | ||
32 | impl Definition { | 32 | impl Definition { |
@@ -39,6 +39,7 @@ impl Definition { | |||
39 | Definition::Local(it) => Some(it.module(db)), | 39 | Definition::Local(it) => Some(it.module(db)), |
40 | Definition::TypeParam(it) => Some(it.module(db)), | 40 | Definition::TypeParam(it) => Some(it.module(db)), |
41 | Definition::LifetimeParam(it) => Some(it.module(db)), | 41 | Definition::LifetimeParam(it) => Some(it.module(db)), |
42 | Definition::Label(it) => Some(it.module(db)), | ||
42 | } | 43 | } |
43 | } | 44 | } |
44 | 45 | ||
@@ -51,6 +52,7 @@ impl Definition { | |||
51 | Definition::Local(_) => None, | 52 | Definition::Local(_) => None, |
52 | Definition::TypeParam(_) => None, | 53 | Definition::TypeParam(_) => None, |
53 | Definition::LifetimeParam(_) => None, | 54 | Definition::LifetimeParam(_) => None, |
55 | Definition::Label(_) => None, | ||
54 | } | 56 | } |
55 | } | 57 | } |
56 | 58 | ||
@@ -77,6 +79,7 @@ impl Definition { | |||
77 | Definition::Local(it) => it.name(db)?, | 79 | Definition::Local(it) => it.name(db)?, |
78 | Definition::TypeParam(it) => it.name(db), | 80 | Definition::TypeParam(it) => it.name(db), |
79 | Definition::LifetimeParam(it) => it.name(db), | 81 | Definition::LifetimeParam(it) => it.name(db), |
82 | Definition::Label(it) => it.name(db), | ||
80 | }; | 83 | }; |
81 | Some(name) | 84 | Some(name) |
82 | } | 85 | } |
@@ -248,7 +251,10 @@ impl NameClass { | |||
248 | let def = sema.to_def(&it)?; | 251 | let def = sema.to_def(&it)?; |
249 | Some(NameClass::Definition(Definition::LifetimeParam(def))) | 252 | Some(NameClass::Definition(Definition::LifetimeParam(def))) |
250 | }, | 253 | }, |
251 | ast::Label(_it) => None, | 254 | ast::Label(it) => { |
255 | let def = sema.to_def(&it)?; | ||
256 | Some(NameClass::Definition(Definition::Label(def))) | ||
257 | }, | ||
252 | _ => None, | 258 | _ => None, |
253 | } | 259 | } |
254 | } | 260 | } |
@@ -370,6 +376,9 @@ impl NameRefClass { | |||
370 | let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string()); | 376 | let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string()); |
371 | let parent = lifetime.syntax().parent()?; | 377 | let parent = lifetime.syntax().parent()?; |
372 | match parent.kind() { | 378 | match parent.kind() { |
379 | SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => { | ||
380 | sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition) | ||
381 | } | ||
373 | SyntaxKind::LIFETIME_ARG | 382 | SyntaxKind::LIFETIME_ARG |
374 | | SyntaxKind::SELF_PARAM | 383 | | SyntaxKind::SELF_PARAM |
375 | | SyntaxKind::TYPE_BOUND | 384 | | SyntaxKind::TYPE_BOUND |
@@ -387,7 +396,6 @@ impl NameRefClass { | |||
387 | .map(Definition::LifetimeParam) | 396 | .map(Definition::LifetimeParam) |
388 | .map(NameRefClass::Definition) | 397 | .map(NameRefClass::Definition) |
389 | } | 398 | } |
390 | SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => None, | ||
391 | _ => None, | 399 | _ => None, |
392 | } | 400 | } |
393 | } | 401 | } |
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index e87d98dad..10c0abdac 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs | |||
@@ -44,7 +44,7 @@ impl From<Vec<SourceFileEdit>> for SourceChange { | |||
44 | 44 | ||
45 | #[derive(Debug, Clone)] | 45 | #[derive(Debug, Clone)] |
46 | pub enum FileSystemEdit { | 46 | pub enum FileSystemEdit { |
47 | CreateFile { dst: AnchoredPathBuf }, | 47 | CreateFile { dst: AnchoredPathBuf, initial_contents: String }, |
48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, | 48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, |
49 | } | 49 | } |
50 | 50 | ||
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index f10e7a9b6..451fa1456 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1004,6 +1004,18 @@ fn test_underscore() { | |||
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | #[test] | 1006 | #[test] |
1007 | fn test_vertical_bar_with_pat() { | ||
1008 | parse_macro( | ||
1009 | r#" | ||
1010 | macro_rules! foo { | ||
1011 | (| $pat:pat | ) => { 0 } | ||
1012 | } | ||
1013 | "#, | ||
1014 | ) | ||
1015 | .assert_expand_items(r#"foo! { | x | }"#, r#"0"#); | ||
1016 | } | ||
1017 | |||
1018 | #[test] | ||
1007 | fn test_lifetime() { | 1019 | fn test_lifetime() { |
1008 | parse_macro( | 1020 | parse_macro( |
1009 | r#" | 1021 | r#" |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 1a078f6b4..f08c8bab7 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -55,7 +55,7 @@ pub(crate) mod fragments { | |||
55 | use super::*; | 55 | use super::*; |
56 | 56 | ||
57 | pub(crate) use super::{ | 57 | pub(crate) use super::{ |
58 | expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_, | 58 | expressions::block_expr, paths::type_path as path, patterns::pattern_single, types::type_, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | pub(crate) fn expr(p: &mut Parser) { | 61 | pub(crate) fn expr(p: &mut Parser) { |
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index 18b63feb7..c7a3556a7 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs | |||
@@ -46,6 +46,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = | |||
46 | T![continue], | 46 | T![continue], |
47 | T![async], | 47 | T![async], |
48 | T![try], | 48 | T![try], |
49 | T![const], | ||
49 | T![loop], | 50 | T![loop], |
50 | T![for], | 51 | T![for], |
51 | LIFETIME_IDENT, | 52 | LIFETIME_IDENT, |
@@ -115,6 +116,14 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar | |||
115 | block_expr(p); | 116 | block_expr(p); |
116 | m.complete(p, EFFECT_EXPR) | 117 | m.complete(p, EFFECT_EXPR) |
117 | } | 118 | } |
119 | // test const_block | ||
120 | // fn f() { const { } } | ||
121 | T![const] if la == T!['{'] => { | ||
122 | let m = p.start(); | ||
123 | p.bump(T![const]); | ||
124 | block_expr(p); | ||
125 | m.complete(p, EFFECT_EXPR) | ||
126 | } | ||
118 | T!['{'] => { | 127 | T!['{'] => { |
119 | // test for_range_from | 128 | // test for_range_from |
120 | // fn foo() { | 129 | // fn foo() { |
@@ -156,11 +165,13 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { | |||
156 | let mut saw_expr = false; | 165 | let mut saw_expr = false; |
157 | while !p.at(EOF) && !p.at(T![')']) { | 166 | while !p.at(EOF) && !p.at(T![')']) { |
158 | saw_expr = true; | 167 | saw_expr = true; |
159 | if !p.at_ts(EXPR_FIRST) { | 168 | |
160 | p.error("expected expression"); | 169 | // test tuple_attrs |
170 | // const A: (i64, i64) = (1, #[cfg(test)] 2); | ||
171 | if !expr_with_attrs(p) { | ||
161 | break; | 172 | break; |
162 | } | 173 | } |
163 | expr(p); | 174 | |
164 | if !p.at(T![')']) { | 175 | if !p.at(T![')']) { |
165 | saw_comma = true; | 176 | saw_comma = true; |
166 | p.expect(T![,]); | 177 | p.expect(T![,]); |
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 8999829b4..cf4168d32 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs | |||
@@ -96,7 +96,10 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { | |||
96 | let mut has_mods = false; | 96 | let mut has_mods = false; |
97 | 97 | ||
98 | // modifiers | 98 | // modifiers |
99 | has_mods |= p.eat(T![const]); | 99 | if p.at(T![const]) && p.nth(1) != T!['{'] { |
100 | p.eat(T![const]); | ||
101 | has_mods = true; | ||
102 | } | ||
100 | 103 | ||
101 | // test_err async_without_semicolon | 104 | // test_err async_without_semicolon |
102 | // fn foo() { let _ = async {} } | 105 | // fn foo() { let _ = async {} } |
@@ -167,7 +170,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { | |||
167 | m.complete(p, TRAIT); | 170 | m.complete(p, TRAIT); |
168 | } | 171 | } |
169 | 172 | ||
170 | T![const] => { | 173 | T![const] if p.nth(1) != T!['{'] => { |
171 | consts::konst(p, m); | 174 | consts::konst(p, m); |
172 | } | 175 | } |
173 | 176 | ||
@@ -386,10 +389,15 @@ fn macro_rules(p: &mut Parser, m: Marker) { | |||
386 | } | 389 | } |
387 | 390 | ||
388 | match p.current() { | 391 | match p.current() { |
389 | T!['{'] => { | 392 | // test macro_rules_non_brace |
393 | // macro_rules! m ( ($i:ident) => {} ); | ||
394 | // macro_rules! m [ ($i:ident) => {} ]; | ||
395 | T!['['] | T!['('] => { | ||
390 | token_tree(p); | 396 | token_tree(p); |
397 | p.expect(T![;]); | ||
391 | } | 398 | } |
392 | _ => p.error("expected `{`"), | 399 | T!['{'] => token_tree(p), |
400 | _ => p.error("expected `{`, `[`, `(`"), | ||
393 | } | 401 | } |
394 | m.complete(p, MACRO_RULES); | 402 | m.complete(p, MACRO_RULES); |
395 | } | 403 | } |
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs index 3ee4e4fca..2d006a1d5 100644 --- a/crates/parser/src/grammar/params.rs +++ b/crates/parser/src/grammar/params.rs | |||
@@ -47,20 +47,23 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
47 | if let FnDef = flavor { | 47 | if let FnDef = flavor { |
48 | // test self_param_outer_attr | 48 | // test self_param_outer_attr |
49 | // fn f(#[must_use] self) {} | 49 | // fn f(#[must_use] self) {} |
50 | let m = p.start(); | ||
50 | attributes::outer_attrs(p); | 51 | attributes::outer_attrs(p); |
51 | opt_self_param(p); | 52 | opt_self_param(p, m); |
52 | } | 53 | } |
53 | 54 | ||
54 | while !p.at(EOF) && !p.at(ket) { | 55 | while !p.at(EOF) && !p.at(ket) { |
55 | // test param_outer_arg | 56 | // test param_outer_arg |
56 | // fn f(#[attr1] pat: Type) {} | 57 | // fn f(#[attr1] pat: Type) {} |
58 | let m = p.start(); | ||
57 | attributes::outer_attrs(p); | 59 | attributes::outer_attrs(p); |
58 | 60 | ||
59 | if !p.at_ts(PARAM_FIRST) { | 61 | if !p.at_ts(PARAM_FIRST) { |
60 | p.error("expected value parameter"); | 62 | p.error("expected value parameter"); |
63 | m.abandon(p); | ||
61 | break; | 64 | break; |
62 | } | 65 | } |
63 | let param = param(p, flavor); | 66 | let param = param(p, m, flavor); |
64 | if !p.at(ket) { | 67 | if !p.at(ket) { |
65 | p.expect(T![,]); | 68 | p.expect(T![,]); |
66 | } | 69 | } |
@@ -77,9 +80,8 @@ const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | |||
77 | 80 | ||
78 | struct Variadic(bool); | 81 | struct Variadic(bool); |
79 | 82 | ||
80 | fn param(p: &mut Parser, flavor: Flavor) -> Variadic { | 83 | fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic { |
81 | let mut res = Variadic(false); | 84 | let mut res = Variadic(false); |
82 | let m = p.start(); | ||
83 | match flavor { | 85 | match flavor { |
84 | // test param_list_vararg | 86 | // test param_list_vararg |
85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | 87 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } |
@@ -151,10 +153,8 @@ fn variadic_param(p: &mut Parser) -> bool { | |||
151 | // fn d(&'a mut self, x: i32) {} | 153 | // fn d(&'a mut self, x: i32) {} |
152 | // fn e(mut self) {} | 154 | // fn e(mut self) {} |
153 | // } | 155 | // } |
154 | fn opt_self_param(p: &mut Parser) { | 156 | fn opt_self_param(p: &mut Parser, m: Marker) { |
155 | let m; | ||
156 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { | 157 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { |
157 | m = p.start(); | ||
158 | p.eat(T![mut]); | 158 | p.eat(T![mut]); |
159 | p.eat(T![self]); | 159 | p.eat(T![self]); |
160 | // test arb_self_types | 160 | // test arb_self_types |
@@ -174,9 +174,8 @@ fn opt_self_param(p: &mut Parser) { | |||
174 | (T![&], T![mut], T![self], _) => 3, | 174 | (T![&], T![mut], T![self], _) => 3, |
175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, | 175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, |
176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, | 176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, |
177 | _ => return, | 177 | _ => return m.abandon(p), |
178 | }; | 178 | }; |
179 | m = p.start(); | ||
180 | p.bump_any(); | 179 | p.bump_any(); |
181 | if p.at(LIFETIME_IDENT) { | 180 | if p.at(LIFETIME_IDENT) { |
182 | lifetime(p); | 181 | lifetime(p); |
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 7e7f73dee..b53d5749f 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs | |||
@@ -89,6 +89,7 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | |||
89 | let m = match p.nth(0) { | 89 | let m = match p.nth(0) { |
90 | T![box] => box_pat(p), | 90 | T![box] => box_pat(p), |
91 | T![ref] | T![mut] => ident_pat(p, true), | 91 | T![ref] | T![mut] => ident_pat(p, true), |
92 | T![const] => const_block_pat(p), | ||
92 | IDENT => match p.nth(1) { | 93 | IDENT => match p.nth(1) { |
93 | // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro | 94 | // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro |
94 | // (T![x]). | 95 | // (T![x]). |
@@ -386,3 +387,16 @@ fn box_pat(p: &mut Parser) -> CompletedMarker { | |||
386 | pattern_single(p); | 387 | pattern_single(p); |
387 | m.complete(p, BOX_PAT) | 388 | m.complete(p, BOX_PAT) |
388 | } | 389 | } |
390 | |||
391 | // test const_block_pat | ||
392 | // fn main() { | ||
393 | // let const { 15 } = (); | ||
394 | // let const { foo(); bar() } = (); | ||
395 | // } | ||
396 | fn const_block_pat(p: &mut Parser) -> CompletedMarker { | ||
397 | assert!(p.at(T![const])); | ||
398 | let m = p.start(); | ||
399 | p.bump(T![const]); | ||
400 | expressions::block_expr(p); | ||
401 | m.complete(p, CONST_BLOCK_PAT) | ||
402 | } | ||
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 9c3f7c28a..4aeccd193 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs | |||
@@ -113,7 +113,7 @@ fn type_bound(p: &mut Parser) -> bool { | |||
113 | p.eat(T![?]); | 113 | p.eat(T![?]); |
114 | match p.current() { | 114 | match p.current() { |
115 | LIFETIME_IDENT => lifetime(p), | 115 | LIFETIME_IDENT => lifetime(p), |
116 | T![for] => types::for_type(p), | 116 | T![for] => types::for_type(p, false), |
117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), | 117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), |
118 | _ => { | 118 | _ => { |
119 | m.abandon(p); | 119 | m.abandon(p); |
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 36a15eace..94cbf7d85 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs | |||
@@ -44,7 +44,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { | |||
44 | T![&] => ref_type(p), | 44 | T![&] => ref_type(p), |
45 | T![_] => infer_type(p), | 45 | T![_] => infer_type(p), |
46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), | 46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), |
47 | T![for] => for_type(p), | 47 | T![for] => for_type(p, allow_bounds), |
48 | T![impl] => impl_trait_type(p), | 48 | T![impl] => impl_trait_type(p), |
49 | T![dyn] => dyn_trait_type(p), | 49 | T![dyn] => dyn_trait_type(p), |
50 | // Some path types are not allowed to have bounds (no plus) | 50 | // Some path types are not allowed to have bounds (no plus) |
@@ -227,7 +227,7 @@ pub(super) fn for_binder(p: &mut Parser) { | |||
227 | // type A = for<'a> fn() -> (); | 227 | // type A = for<'a> fn() -> (); |
228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); | 228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); |
229 | // type Obj = for<'a> PartialEq<&'a i32>; | 229 | // type Obj = for<'a> PartialEq<&'a i32>; |
230 | pub(super) fn for_type(p: &mut Parser) { | 230 | pub(super) fn for_type(p: &mut Parser, allow_bounds: bool) { |
231 | assert!(p.at(T![for])); | 231 | assert!(p.at(T![for])); |
232 | let m = p.start(); | 232 | let m = p.start(); |
233 | for_binder(p); | 233 | for_binder(p); |
@@ -240,7 +240,13 @@ pub(super) fn for_type(p: &mut Parser) { | |||
240 | } | 240 | } |
241 | } | 241 | } |
242 | type_no_bounds(p); | 242 | type_no_bounds(p); |
243 | m.complete(p, FOR_TYPE); | 243 | let completed = m.complete(p, FOR_TYPE); |
244 | |||
245 | // test no_dyn_trait_leading_for | ||
246 | // type A = for<'a> Test<'a> + Send; | ||
247 | if allow_bounds { | ||
248 | opt_type_bounds_as_dyn_trait_type(p, completed); | ||
249 | } | ||
244 | } | 250 | } |
245 | 251 | ||
246 | // test impl_trait_type | 252 | // test impl_trait_type |
@@ -290,7 +296,7 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { | |||
290 | let path = m.complete(p, kind); | 296 | let path = m.complete(p, kind); |
291 | 297 | ||
292 | if allow_bounds { | 298 | if allow_bounds { |
293 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 299 | opt_type_bounds_as_dyn_trait_type(p, path); |
294 | } | 300 | } |
295 | } | 301 | } |
296 | 302 | ||
@@ -304,19 +310,23 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { | |||
304 | // fn foo() -> Box<dyn T + 'f> {} | 310 | // fn foo() -> Box<dyn T + 'f> {} |
305 | let path = m.complete(p, PATH_TYPE); | 311 | let path = m.complete(p, PATH_TYPE); |
306 | if allow_bounds { | 312 | if allow_bounds { |
307 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 313 | opt_type_bounds_as_dyn_trait_type(p, path); |
308 | } | 314 | } |
309 | } | 315 | } |
310 | 316 | ||
311 | /// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE | 317 | /// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE |
312 | /// with a TYPE_BOUND_LIST | 318 | /// with a TYPE_BOUND_LIST |
313 | fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { | 319 | fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { |
320 | assert!(matches!( | ||
321 | type_marker.kind(), | ||
322 | SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL | ||
323 | )); | ||
314 | if !p.at(T![+]) { | 324 | if !p.at(T![+]) { |
315 | return; | 325 | return; |
316 | } | 326 | } |
317 | 327 | ||
318 | // First create a TYPE_BOUND from the completed PATH_TYPE | 328 | // First create a TYPE_BOUND from the completed PATH_TYPE |
319 | let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); | 329 | let m = type_marker.precede(p).complete(p, TYPE_BOUND); |
320 | 330 | ||
321 | // Next setup a marker for the TYPE_BOUND_LIST | 331 | // Next setup a marker for the TYPE_BOUND_LIST |
322 | let m = m.precede(p); | 332 | let m = m.precede(p); |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index ab8e4c70e..811e740f9 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs | |||
@@ -112,7 +112,7 @@ pub fn parse_fragment( | |||
112 | FragmentKind::Path => grammar::fragments::path, | 112 | FragmentKind::Path => grammar::fragments::path, |
113 | FragmentKind::Expr => grammar::fragments::expr, | 113 | FragmentKind::Expr => grammar::fragments::expr, |
114 | FragmentKind::Type => grammar::fragments::type_, | 114 | FragmentKind::Type => grammar::fragments::type_, |
115 | FragmentKind::Pattern => grammar::fragments::pattern, | 115 | FragmentKind::Pattern => grammar::fragments::pattern_single, |
116 | FragmentKind::Item => grammar::fragments::item, | 116 | FragmentKind::Item => grammar::fragments::item, |
117 | FragmentKind::Block => grammar::fragments::block_expr, | 117 | FragmentKind::Block => grammar::fragments::block_expr, |
118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, | 118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, |
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 980aa5979..f69e71bdb 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs | |||
@@ -170,6 +170,7 @@ pub enum SyntaxKind { | |||
170 | RANGE_PAT, | 170 | RANGE_PAT, |
171 | LITERAL_PAT, | 171 | LITERAL_PAT, |
172 | MACRO_PAT, | 172 | MACRO_PAT, |
173 | CONST_BLOCK_PAT, | ||
173 | TUPLE_EXPR, | 174 | TUPLE_EXPR, |
174 | ARRAY_EXPR, | 175 | ARRAY_EXPR, |
175 | PAREN_EXPR, | 176 | PAREN_EXPR, |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index 1bfa6c3fc..df9a55c10 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } | 13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } |
14 | libloading = "0.6.0" | 14 | libloading = "0.6.0" |
15 | memmap = "0.7" | 15 | memmap = "0.7" |
16 | 16 | ||
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0b4d3f4eb..53e70eaf7 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -28,6 +28,7 @@ oorandom = "11.1.2" | |||
28 | rustc-hash = "1.1.0" | 28 | rustc-hash = "1.1.0" |
29 | serde = { version = "1.0.106", features = ["derive"] } | 29 | serde = { version = "1.0.106", features = ["derive"] } |
30 | serde_json = { version = "1.0.48", features = ["preserve_order"] } | 30 | serde_json = { version = "1.0.48", features = ["preserve_order"] } |
31 | serde_path_to_error = "0.1" | ||
31 | threadpool = "1.7.1" | 32 | threadpool = "1.7.1" |
32 | rayon = "1.5" | 33 | rayon = "1.5" |
33 | mimalloc = { version = "0.1.19", default-features = false, optional = true } | 34 | mimalloc = { version = "0.1.19", default-features = false, optional = true } |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index de5eb93b5..80e46bf7f 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -5,12 +5,14 @@ use ide::CompletionResolveCapability; | |||
5 | use lsp_types::{ | 5 | use lsp_types::{ |
6 | CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, | 6 | CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, |
7 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, | 7 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, |
8 | DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability, | 8 | DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationPattern, |
9 | ImplementationProviderCapability, OneOf, RenameOptions, SaveOptions, | 9 | FileOperationPatternKind, FileOperationRegistrationOptions, FoldingRangeProviderCapability, |
10 | HoverProviderCapability, ImplementationProviderCapability, OneOf, RenameOptions, SaveOptions, | ||
10 | SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend, | 11 | SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend, |
11 | SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, | 12 | SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, |
12 | TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, | 13 | TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, |
13 | WorkDoneProgressOptions, | 14 | WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities, |
15 | WorkspaceServerCapabilities, | ||
14 | }; | 16 | }; |
15 | use rustc_hash::FxHashSet; | 17 | use rustc_hash::FxHashSet; |
16 | use serde_json::json; | 18 | use serde_json::json; |
@@ -68,7 +70,26 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
68 | document_link_provider: None, | 70 | document_link_provider: None, |
69 | color_provider: None, | 71 | color_provider: None, |
70 | execute_command_provider: None, | 72 | execute_command_provider: None, |
71 | workspace: None, | 73 | workspace: Some(WorkspaceServerCapabilities { |
74 | workspace_folders: None, | ||
75 | file_operations: Some(WorkspaceFileOperationsServerCapabilities { | ||
76 | did_create: None, | ||
77 | will_create: None, | ||
78 | did_rename: None, | ||
79 | will_rename: Some(FileOperationRegistrationOptions { | ||
80 | filters: vec![FileOperationFilter { | ||
81 | scheme: Some(String::from("file")), | ||
82 | pattern: FileOperationPattern { | ||
83 | glob: String::from("**/*.rs"), | ||
84 | matches: Some(FileOperationPatternKind::File), | ||
85 | options: None, | ||
86 | }, | ||
87 | }], | ||
88 | }), | ||
89 | did_delete: None, | ||
90 | will_delete: None, | ||
91 | }), | ||
92 | }), | ||
72 | call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), | 93 | call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), |
73 | semantic_tokens_provider: Some( | 94 | semantic_tokens_provider: Some( |
74 | SemanticTokensOptions { | 95 | SemanticTokensOptions { |
diff --git a/crates/rust-analyzer/src/cli/progress_report.rs b/crates/rust-analyzer/src/cli/progress_report.rs index bdbe565e6..5a2dc39d5 100644 --- a/crates/rust-analyzer/src/cli/progress_report.rs +++ b/crates/rust-analyzer/src/cli/progress_report.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! A simple progress bar | 1 | //! A simple progress bar |
2 | //! | 2 | //! |
3 | //! A single thread non-optimized progress bar | 3 | //! A single thread non-optimized progress bar |
4 | use std::io::Write; | 4 | use std::io::{self, Write}; |
5 | 5 | ||
6 | /// A Simple ASCII Progress Bar | 6 | /// A Simple ASCII Progress Bar |
7 | pub(crate) struct ProgressReport { | 7 | pub(crate) struct ProgressReport { |
@@ -97,8 +97,8 @@ impl ProgressReport { | |||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | let _ = std::io::stdout().write(output.as_bytes()); | 100 | let _ = io::stdout().write(output.as_bytes()); |
101 | let _ = std::io::stdout().flush(); | 101 | let _ = io::stdout().flush(); |
102 | self.text = text.to_string(); | 102 | self.text = text.to_string(); |
103 | } | 103 | } |
104 | 104 | ||
@@ -115,6 +115,8 @@ impl ProgressReport { | |||
115 | let spaces = " ".repeat(self.text.len()); | 115 | let spaces = " ".repeat(self.text.len()); |
116 | let backspaces = "\x08".repeat(self.text.len()); | 116 | let backspaces = "\x08".repeat(self.text.len()); |
117 | print!("{}{}{}", backspaces, spaces, backspaces); | 117 | print!("{}{}{}", backspaces, spaces, backspaces); |
118 | let _ = io::stdout().flush(); | ||
119 | |||
118 | self.text = String::new(); | 120 | self.text = String::new(); |
119 | } | 121 | } |
120 | } | 122 | } |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1f4b5c24c..1db5b4e7d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -33,7 +33,7 @@ config_data! { | |||
33 | callInfo_full: bool = "true", | 33 | callInfo_full: bool = "true", |
34 | 34 | ||
35 | /// Automatically refresh project info via `cargo metadata` on | 35 | /// Automatically refresh project info via `cargo metadata` on |
36 | /// Cargo.toml changes. | 36 | /// `Cargo.toml` changes. |
37 | cargo_autoreload: bool = "true", | 37 | cargo_autoreload: bool = "true", |
38 | /// Activate all available features. | 38 | /// Activate all available features. |
39 | cargo_allFeatures: bool = "false", | 39 | cargo_allFeatures: bool = "false", |
@@ -52,7 +52,7 @@ config_data! { | |||
52 | /// Run specified `cargo check` command for diagnostics on save. | 52 | /// Run specified `cargo check` command for diagnostics on save. |
53 | checkOnSave_enable: bool = "true", | 53 | checkOnSave_enable: bool = "true", |
54 | /// Check with all features (will be passed as `--all-features`). | 54 | /// Check with all features (will be passed as `--all-features`). |
55 | /// Defaults to `rust-analyzer.cargo.allFeatures`. | 55 | /// Defaults to `#rust-analyzer.cargo.allFeatures#`. |
56 | checkOnSave_allFeatures: Option<bool> = "null", | 56 | checkOnSave_allFeatures: Option<bool> = "null", |
57 | /// Check all targets and tests (will be passed as `--all-targets`). | 57 | /// Check all targets and tests (will be passed as `--all-targets`). |
58 | checkOnSave_allTargets: bool = "true", | 58 | checkOnSave_allTargets: bool = "true", |
@@ -61,12 +61,12 @@ config_data! { | |||
61 | /// Do not activate the `default` feature. | 61 | /// Do not activate the `default` feature. |
62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", | 62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", |
63 | /// Check for a specific target. Defaults to | 63 | /// Check for a specific target. Defaults to |
64 | /// `rust-analyzer.cargo.target`. | 64 | /// `#rust-analyzer.cargo.target#`. |
65 | checkOnSave_target: Option<String> = "null", | 65 | checkOnSave_target: Option<String> = "null", |
66 | /// Extra arguments for `cargo check`. | 66 | /// Extra arguments for `cargo check`. |
67 | checkOnSave_extraArgs: Vec<String> = "[]", | 67 | checkOnSave_extraArgs: Vec<String> = "[]", |
68 | /// List of features to activate. Defaults to | 68 | /// List of features to activate. Defaults to |
69 | /// `rust-analyzer.cargo.features`. | 69 | /// `#rust-analyzer.cargo.features#`. |
70 | checkOnSave_features: Option<Vec<String>> = "null", | 70 | checkOnSave_features: Option<Vec<String>> = "null", |
71 | /// Advanced option, fully override the command rust-analyzer uses for | 71 | /// Advanced option, fully override the command rust-analyzer uses for |
72 | /// checking. The command should include `--message-format=json` or | 72 | /// checking. The command should include `--message-format=json` or |
@@ -80,7 +80,7 @@ config_data! { | |||
80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | 80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. |
81 | completion_postfix_enable: bool = "true", | 81 | completion_postfix_enable: bool = "true", |
82 | /// Toggles the additional completions that automatically add imports when completed. | 82 | /// Toggles the additional completions that automatically add imports when completed. |
83 | /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | 83 | /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. |
84 | completion_autoimport_enable: bool = "true", | 84 | completion_autoimport_enable: bool = "true", |
85 | 85 | ||
86 | /// Whether to show native rust-analyzer diagnostics. | 86 | /// Whether to show native rust-analyzer diagnostics. |
@@ -90,13 +90,13 @@ config_data! { | |||
90 | diagnostics_enableExperimental: bool = "true", | 90 | diagnostics_enableExperimental: bool = "true", |
91 | /// List of rust-analyzer diagnostics to disable. | 91 | /// List of rust-analyzer diagnostics to disable. |
92 | diagnostics_disabled: FxHashSet<String> = "[]", | 92 | diagnostics_disabled: FxHashSet<String> = "[]", |
93 | /// List of warnings that should be displayed with info severity.\nThe | 93 | /// List of warnings that should be displayed with info severity.\n\nThe |
94 | /// warnings will be indicated by a blue squiggly underline in code and | 94 | /// warnings will be indicated by a blue squiggly underline in code and |
95 | /// a blue icon in the problems panel. | 95 | /// a blue icon in the `Problems Panel`. |
96 | diagnostics_warningsAsHint: Vec<String> = "[]", | 96 | diagnostics_warningsAsHint: Vec<String> = "[]", |
97 | /// List of warnings that should be displayed with hint severity.\nThe | 97 | /// List of warnings that should be displayed with hint severity.\n\nThe |
98 | /// warnings will be indicated by faded text or three dots in code and | 98 | /// warnings will be indicated by faded text or three dots in code and |
99 | /// will not show up in the problems panel. | 99 | /// will not show up in the `Problems Panel`. |
100 | diagnostics_warningsAsInfo: Vec<String> = "[]", | 100 | diagnostics_warningsAsInfo: Vec<String> = "[]", |
101 | 101 | ||
102 | /// Controls file watching implementation. | 102 | /// Controls file watching implementation. |
@@ -121,7 +121,7 @@ config_data! { | |||
121 | 121 | ||
122 | /// Whether to show inlay type hints for method chains. | 122 | /// Whether to show inlay type hints for method chains. |
123 | inlayHints_chainingHints: bool = "true", | 123 | inlayHints_chainingHints: bool = "true", |
124 | /// Maximum length for inlay hints. | 124 | /// Maximum length for inlay hints. Default is unlimited. |
125 | inlayHints_maxLength: Option<usize> = "null", | 125 | inlayHints_maxLength: Option<usize> = "null", |
126 | /// Whether to show function parameter name inlay hints at the call | 126 | /// Whether to show function parameter name inlay hints at the call |
127 | /// site. | 127 | /// site. |
@@ -145,27 +145,27 @@ config_data! { | |||
145 | lens_methodReferences: bool = "false", | 145 | lens_methodReferences: bool = "false", |
146 | 146 | ||
147 | /// Disable project auto-discovery in favor of explicitly specified set | 147 | /// Disable project auto-discovery in favor of explicitly specified set |
148 | /// of projects. \nElements must be paths pointing to Cargo.toml, | 148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, |
149 | /// rust-project.json, or JSON objects in rust-project.json format. | 149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
151 | /// Number of syntax trees rust-analyzer keeps in memory. | 151 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
152 | lruCapacity: Option<usize> = "null", | 152 | lruCapacity: Option<usize> = "null", |
153 | /// Whether to show `can't find Cargo.toml` error message. | 153 | /// Whether to show `can't find Cargo.toml` error message. |
154 | notifications_cargoTomlNotFound: bool = "true", | 154 | notifications_cargoTomlNotFound: bool = "true", |
155 | /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be | 155 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be |
156 | /// enabled. | 156 | /// enabled. |
157 | procMacro_enable: bool = "false", | 157 | procMacro_enable: bool = "false", |
158 | 158 | ||
159 | /// Command to be executed instead of 'cargo' for runnables. | 159 | /// Command to be executed instead of 'cargo' for runnables. |
160 | runnables_overrideCargo: Option<String> = "null", | 160 | runnables_overrideCargo: Option<String> = "null", |
161 | /// Additional arguments to be passed to cargo for runnables such as | 161 | /// Additional arguments to be passed to cargo for runnables such as |
162 | /// tests or binaries.\nFor example, it may be '--release'. | 162 | /// tests or binaries.\nFor example, it may be `--release`. |
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | 163 | runnables_cargoExtraArgs: Vec<String> = "[]", |
164 | 164 | ||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 165 | /// Path to the rust compiler sources, for usage in rustc_private projects. |
166 | rustcSource : Option<String> = "null", | 166 | rustcSource : Option<String> = "null", |
167 | 167 | ||
168 | /// Additional arguments to rustfmt. | 168 | /// Additional arguments to `rustfmt`. |
169 | rustfmt_extraArgs: Vec<String> = "[]", | 169 | rustfmt_extraArgs: Vec<String> = "[]", |
170 | /// Advanced option, fully override the command rust-analyzer uses for | 170 | /// Advanced option, fully override the command rust-analyzer uses for |
171 | /// formatting. | 171 | /// formatting. |
@@ -349,12 +349,12 @@ impl Config { | |||
349 | res | 349 | res |
350 | } | 350 | } |
351 | pub fn update(&mut self, json: serde_json::Value) { | 351 | pub fn update(&mut self, json: serde_json::Value) { |
352 | log::info!("Config::update({:#})", json); | 352 | log::info!("updating config from JSON: {:#}", json); |
353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
354 | return; | 354 | return; |
355 | } | 355 | } |
356 | self.do_update(json); | 356 | self.do_update(json); |
357 | log::info!("Config::update() = {:#?}", self); | 357 | log::info!("updated config: {:#?}", self); |
358 | } | 358 | } |
359 | fn do_update(&mut self, json: serde_json::Value) { | 359 | fn do_update(&mut self, json: serde_json::Value) { |
360 | let data = ConfigData::from_json(json); | 360 | let data = ConfigData::from_json(json); |
@@ -758,7 +758,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
758 | ], | 758 | ], |
759 | "enumDescriptions": [ | 759 | "enumDescriptions": [ |
760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", |
762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." |
763 | ], | 763 | ], |
764 | }, | 764 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index f16f97131..540759198 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -319,6 +319,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
319 | message: "original diagnostic".to_string(), | 319 | message: "original diagnostic".to_string(), |
320 | }; | 320 | }; |
321 | for info in &related_information { | 321 | for info in &related_information { |
322 | // Filter out empty/non-existent messages, as they greatly confuse VS Code. | ||
323 | if info.message.is_empty() { | ||
324 | continue; | ||
325 | } | ||
322 | diagnostics.push(MappedRustDiagnostic { | 326 | diagnostics.push(MappedRustDiagnostic { |
323 | url: info.location.uri.clone(), | 327 | url: info.location.uri.clone(), |
324 | fixes: fixes.clone(), // share fixes to make them easier to apply | 328 | fixes: fixes.clone(), // share fixes to make them easier to apply |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 66f8bee99..374fb5302 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -5,11 +5,13 @@ | |||
5 | use std::{ | 5 | use std::{ |
6 | io::Write as _, | 6 | io::Write as _, |
7 | process::{self, Stdio}, | 7 | process::{self, Stdio}, |
8 | sync::Arc, | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | use ide::{ | 11 | use ide::{ |
11 | CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, | 12 | AssistConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, |
12 | NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SymbolKind, TextEdit, | 13 | HoverGotoTypeData, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, |
14 | SearchScope, SourceChange, SymbolKind, TextEdit, | ||
13 | }; | 15 | }; |
14 | use itertools::Itertools; | 16 | use itertools::Itertools; |
15 | use lsp_server::ErrorCode; | 17 | use lsp_server::ErrorCode; |
@@ -400,6 +402,45 @@ pub(crate) fn handle_workspace_symbol( | |||
400 | } | 402 | } |
401 | } | 403 | } |
402 | 404 | ||
405 | pub(crate) fn handle_will_rename_files( | ||
406 | snap: GlobalStateSnapshot, | ||
407 | params: lsp_types::RenameFilesParams, | ||
408 | ) -> Result<Option<lsp_types::WorkspaceEdit>> { | ||
409 | let _p = profile::span("handle_will_rename_files"); | ||
410 | |||
411 | let source_changes: Vec<SourceChange> = params | ||
412 | .files | ||
413 | .into_iter() | ||
414 | .filter_map(|file_rename| { | ||
415 | let from = Url::parse(&file_rename.old_uri).ok()?; | ||
416 | let to = Url::parse(&file_rename.new_uri).ok()?; | ||
417 | |||
418 | let from_path = from.to_file_path().ok()?; | ||
419 | let to_path = to.to_file_path().ok()?; | ||
420 | |||
421 | // Limit to single-level moves for now. | ||
422 | match (from_path.parent(), to_path.parent()) { | ||
423 | (Some(p1), Some(p2)) if p1 == p2 => { | ||
424 | let new_name = to_path.file_stem()?; | ||
425 | let new_name = new_name.to_str()?; | ||
426 | Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())) | ||
427 | } | ||
428 | _ => None, | ||
429 | } | ||
430 | }) | ||
431 | .filter_map(|(file_id, new_name)| { | ||
432 | snap.analysis.will_rename_file(file_id, &new_name).ok()? | ||
433 | }) | ||
434 | .collect(); | ||
435 | |||
436 | // Drop file system edits since we're just renaming things on the same level | ||
437 | let edits = source_changes.into_iter().map(|it| it.source_file_edits).flatten().collect(); | ||
438 | let source_change = SourceChange::from_edits(edits, Vec::new()); | ||
439 | |||
440 | let workspace_edit = to_proto::workspace_edit(&snap, source_change)?; | ||
441 | Ok(Some(workspace_edit)) | ||
442 | } | ||
443 | |||
403 | pub(crate) fn handle_goto_definition( | 444 | pub(crate) fn handle_goto_definition( |
404 | snap: GlobalStateSnapshot, | 445 | snap: GlobalStateSnapshot, |
405 | params: lsp_types::GotoDefinitionParams, | 446 | params: lsp_types::GotoDefinitionParams, |
@@ -865,58 +906,8 @@ pub(crate) fn handle_formatting( | |||
865 | } | 906 | } |
866 | } | 907 | } |
867 | 908 | ||
868 | fn handle_fixes( | ||
869 | snap: &GlobalStateSnapshot, | ||
870 | params: &lsp_types::CodeActionParams, | ||
871 | res: &mut Vec<lsp_ext::CodeAction>, | ||
872 | ) -> Result<()> { | ||
873 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; | ||
874 | let line_index = snap.analysis.file_line_index(file_id)?; | ||
875 | let range = from_proto::text_range(&line_index, params.range); | ||
876 | |||
877 | match ¶ms.context.only { | ||
878 | Some(v) => { | ||
879 | if !v.iter().any(|it| { | ||
880 | it == &lsp_types::CodeActionKind::EMPTY | ||
881 | || it == &lsp_types::CodeActionKind::QUICKFIX | ||
882 | }) { | ||
883 | return Ok(()); | ||
884 | } | ||
885 | } | ||
886 | None => {} | ||
887 | }; | ||
888 | |||
889 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, file_id)?; | ||
890 | |||
891 | for fix in diagnostics | ||
892 | .into_iter() | ||
893 | .filter_map(|d| d.fix) | ||
894 | .filter(|fix| fix.fix_trigger_range.intersect(range).is_some()) | ||
895 | { | ||
896 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; | ||
897 | let action = lsp_ext::CodeAction { | ||
898 | title: fix.label.to_string(), | ||
899 | group: None, | ||
900 | kind: Some(CodeActionKind::QUICKFIX), | ||
901 | edit: Some(edit), | ||
902 | is_preferred: Some(false), | ||
903 | data: None, | ||
904 | }; | ||
905 | res.push(action); | ||
906 | } | ||
907 | |||
908 | for fix in snap.check_fixes.get(&file_id).into_iter().flatten() { | ||
909 | let fix_range = from_proto::text_range(&line_index, fix.range); | ||
910 | if fix_range.intersect(range).is_none() { | ||
911 | continue; | ||
912 | } | ||
913 | res.push(fix.action.clone()); | ||
914 | } | ||
915 | Ok(()) | ||
916 | } | ||
917 | |||
918 | pub(crate) fn handle_code_action( | 909 | pub(crate) fn handle_code_action( |
919 | mut snap: GlobalStateSnapshot, | 910 | snap: GlobalStateSnapshot, |
920 | params: lsp_types::CodeActionParams, | 911 | params: lsp_types::CodeActionParams, |
921 | ) -> Result<Option<Vec<lsp_ext::CodeAction>>> { | 912 | ) -> Result<Option<Vec<lsp_ext::CodeAction>>> { |
922 | let _p = profile::span("handle_code_action"); | 913 | let _p = profile::span("handle_code_action"); |
@@ -932,24 +923,35 @@ pub(crate) fn handle_code_action( | |||
932 | let range = from_proto::text_range(&line_index, params.range); | 923 | let range = from_proto::text_range(&line_index, params.range); |
933 | let frange = FileRange { file_id, range }; | 924 | let frange = FileRange { file_id, range }; |
934 | 925 | ||
935 | snap.config.assist.allowed = params | 926 | let assists_config = AssistConfig { |
936 | .clone() | 927 | allowed: params |
937 | .context | 928 | .clone() |
938 | .only | 929 | .context |
939 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); | 930 | .only |
931 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()), | ||
932 | ..snap.config.assist | ||
933 | }; | ||
940 | 934 | ||
941 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 935 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
942 | 936 | ||
943 | handle_fixes(&snap, ¶ms, &mut res)?; | 937 | let include_quick_fixes = match ¶ms.context.only { |
938 | Some(v) => v.iter().any(|it| { | ||
939 | it == &lsp_types::CodeActionKind::EMPTY || it == &lsp_types::CodeActionKind::QUICKFIX | ||
940 | }), | ||
941 | None => true, | ||
942 | }; | ||
943 | if include_quick_fixes { | ||
944 | add_quick_fixes(&snap, frange, &line_index, &mut res)?; | ||
945 | } | ||
944 | 946 | ||
945 | if snap.config.client_caps.code_action_resolve { | 947 | if snap.config.client_caps.code_action_resolve { |
946 | for (index, assist) in | 948 | for (index, assist) in |
947 | snap.analysis.unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() | 949 | snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate() |
948 | { | 950 | { |
949 | res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?); | 951 | res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?); |
950 | } | 952 | } |
951 | } else { | 953 | } else { |
952 | for assist in snap.analysis.resolved_assists(&snap.config.assist, frange)?.into_iter() { | 954 | for assist in snap.analysis.assists(&assists_config, true, frange)?.into_iter() { |
953 | res.push(to_proto::resolved_code_action(&snap, assist)?); | 955 | res.push(to_proto::resolved_code_action(&snap, assist)?); |
954 | } | 956 | } |
955 | } | 957 | } |
@@ -957,6 +959,40 @@ pub(crate) fn handle_code_action( | |||
957 | Ok(Some(res)) | 959 | Ok(Some(res)) |
958 | } | 960 | } |
959 | 961 | ||
962 | fn add_quick_fixes( | ||
963 | snap: &GlobalStateSnapshot, | ||
964 | frange: FileRange, | ||
965 | line_index: &Arc<LineIndex>, | ||
966 | acc: &mut Vec<lsp_ext::CodeAction>, | ||
967 | ) -> Result<()> { | ||
968 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, frange.file_id)?; | ||
969 | |||
970 | for fix in diagnostics | ||
971 | .into_iter() | ||
972 | .filter_map(|d| d.fix) | ||
973 | .filter(|fix| fix.fix_trigger_range.intersect(frange.range).is_some()) | ||
974 | { | ||
975 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; | ||
976 | let action = lsp_ext::CodeAction { | ||
977 | title: fix.label.to_string(), | ||
978 | group: None, | ||
979 | kind: Some(CodeActionKind::QUICKFIX), | ||
980 | edit: Some(edit), | ||
981 | is_preferred: Some(false), | ||
982 | data: None, | ||
983 | }; | ||
984 | acc.push(action); | ||
985 | } | ||
986 | |||
987 | for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { | ||
988 | let fix_range = from_proto::text_range(&line_index, fix.range); | ||
989 | if fix_range.intersect(frange.range).is_some() { | ||
990 | acc.push(fix.action.clone()); | ||
991 | } | ||
992 | } | ||
993 | Ok(()) | ||
994 | } | ||
995 | |||
960 | pub(crate) fn handle_code_action_resolve( | 996 | pub(crate) fn handle_code_action_resolve( |
961 | mut snap: GlobalStateSnapshot, | 997 | mut snap: GlobalStateSnapshot, |
962 | mut code_action: lsp_ext::CodeAction, | 998 | mut code_action: lsp_ext::CodeAction, |
@@ -978,11 +1014,11 @@ pub(crate) fn handle_code_action_resolve( | |||
978 | .only | 1014 | .only |
979 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); | 1015 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
980 | 1016 | ||
981 | let assists = snap.analysis.resolved_assists(&snap.config.assist, frange)?; | 1017 | let assists = snap.analysis.assists(&snap.config.assist, true, frange)?; |
982 | let (id, index) = split_once(¶ms.id, ':').unwrap(); | 1018 | let (id, index) = split_once(¶ms.id, ':').unwrap(); |
983 | let index = index.parse::<usize>().unwrap(); | 1019 | let index = index.parse::<usize>().unwrap(); |
984 | let assist = &assists[index]; | 1020 | let assist = &assists[index]; |
985 | assert!(assist.assist.id.0 == id); | 1021 | assert!(assist.id.0 == id); |
986 | let edit = to_proto::resolved_code_action(&snap, assist.clone())?.edit; | 1022 | let edit = to_proto::resolved_code_action(&snap, assist.clone())?.edit; |
987 | code_action.edit = edit; | 1023 | code_action.edit = edit; |
988 | Ok(code_action) | 1024 | Ok(code_action) |
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 79fe30e53..d538ad69a 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -46,7 +46,7 @@ pub type Error = Box<dyn std::error::Error + Send + Sync>; | |||
46 | pub type Result<T, E = Error> = std::result::Result<T, E>; | 46 | pub type Result<T, E = Error> = std::result::Result<T, E>; |
47 | 47 | ||
48 | pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { | 48 | pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { |
49 | let res = T::deserialize(&json) | 49 | let res = serde_path_to_error::deserialize(&json) |
50 | .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; | 50 | .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; |
51 | Ok(res) | 51 | Ok(res) |
52 | } | 52 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ec3d5e060..5d55dc96e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -485,6 +485,7 @@ impl GlobalState { | |||
485 | .on::<lsp_types::request::SemanticTokensRangeRequest>( | 485 | .on::<lsp_types::request::SemanticTokensRangeRequest>( |
486 | handlers::handle_semantic_tokens_range, | 486 | handlers::handle_semantic_tokens_range, |
487 | ) | 487 | ) |
488 | .on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files) | ||
488 | .on::<lsp_ext::Ssr>(handlers::handle_ssr) | 489 | .on::<lsp_ext::Ssr>(handlers::handle_ssr) |
489 | .finish(); | 490 | .finish(); |
490 | Ok(()) | 491 | Ok(()) |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 1daad1c98..c2f6a655d 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -45,6 +45,7 @@ define_semantic_token_types![ | |||
45 | (FORMAT_SPECIFIER, "formatSpecifier"), | 45 | (FORMAT_SPECIFIER, "formatSpecifier"), |
46 | (GENERIC, "generic"), | 46 | (GENERIC, "generic"), |
47 | (LIFETIME, "lifetime"), | 47 | (LIFETIME, "lifetime"), |
48 | (LABEL, "label"), | ||
48 | (PUNCTUATION, "punctuation"), | 49 | (PUNCTUATION, "punctuation"), |
49 | (SELF_KEYWORD, "selfKeyword"), | 50 | (SELF_KEYWORD, "selfKeyword"), |
50 | (TYPE_ALIAS, "typeAlias"), | 51 | (TYPE_ALIAS, "typeAlias"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e0561b5a7..1a38e79f0 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -8,8 +8,8 @@ use ide::{ | |||
8 | Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, | 8 | Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, |
9 | FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, | 9 | FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, |
10 | HighlightedRange, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, | 10 | HighlightedRange, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, |
11 | NavigationTarget, ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, | 11 | NavigationTarget, ReferenceAccess, Runnable, Severity, SourceChange, SourceFileEdit, |
12 | SourceFileEdit, SymbolKind, TextEdit, TextRange, TextSize, | 12 | SymbolKind, TextEdit, TextRange, TextSize, |
13 | }; | 13 | }; |
14 | use itertools::Itertools; | 14 | use itertools::Itertools; |
15 | 15 | ||
@@ -46,7 +46,8 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { | |||
46 | SymbolKind::Local | 46 | SymbolKind::Local |
47 | | SymbolKind::SelfParam | 47 | | SymbolKind::SelfParam |
48 | | SymbolKind::LifetimeParam | 48 | | SymbolKind::LifetimeParam |
49 | | SymbolKind::ValueParam => lsp_types::SymbolKind::Variable, | 49 | | SymbolKind::ValueParam |
50 | | SymbolKind::Label => lsp_types::SymbolKind::Variable, | ||
50 | SymbolKind::Union => lsp_types::SymbolKind::Struct, | 51 | SymbolKind::Union => lsp_types::SymbolKind::Struct, |
51 | } | 52 | } |
52 | } | 53 | } |
@@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers( | |||
378 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, | 379 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, |
379 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, | 380 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, |
380 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, | 381 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, |
382 | SymbolKind::Label => semantic_tokens::LABEL, | ||
381 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, | 383 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, |
382 | SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, | 384 | SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, |
383 | SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, | 385 | SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, |
@@ -634,30 +636,47 @@ pub(crate) fn snippet_text_document_edit( | |||
634 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 636 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
635 | } | 637 | } |
636 | 638 | ||
637 | pub(crate) fn resource_op( | 639 | pub(crate) fn snippet_text_document_ops( |
638 | snap: &GlobalStateSnapshot, | 640 | snap: &GlobalStateSnapshot, |
639 | file_system_edit: FileSystemEdit, | 641 | file_system_edit: FileSystemEdit, |
640 | ) -> lsp_types::ResourceOp { | 642 | ) -> Vec<lsp_ext::SnippetDocumentChangeOperation> { |
643 | let mut ops = Vec::new(); | ||
641 | match file_system_edit { | 644 | match file_system_edit { |
642 | FileSystemEdit::CreateFile { dst } => { | 645 | FileSystemEdit::CreateFile { dst, initial_contents } => { |
643 | let uri = snap.anchored_path(&dst); | 646 | let uri = snap.anchored_path(&dst); |
644 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { | 647 | let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { |
645 | uri, | 648 | uri: uri.clone(), |
646 | options: None, | 649 | options: None, |
647 | annotation_id: None, | 650 | annotation_id: None, |
648 | }) | 651 | }); |
652 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file)); | ||
653 | if !initial_contents.is_empty() { | ||
654 | let text_document = | ||
655 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; | ||
656 | let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); | ||
657 | let text_edit = lsp_ext::SnippetTextEdit { | ||
658 | range, | ||
659 | new_text: initial_contents, | ||
660 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | ||
661 | }; | ||
662 | let edit_file = | ||
663 | lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; | ||
664 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file)); | ||
665 | } | ||
649 | } | 666 | } |
650 | FileSystemEdit::MoveFile { src, dst } => { | 667 | FileSystemEdit::MoveFile { src, dst } => { |
651 | let old_uri = snap.file_id_to_url(src); | 668 | let old_uri = snap.file_id_to_url(src); |
652 | let new_uri = snap.anchored_path(&dst); | 669 | let new_uri = snap.anchored_path(&dst); |
653 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { | 670 | let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile { |
654 | old_uri, | 671 | old_uri, |
655 | new_uri, | 672 | new_uri, |
656 | options: None, | 673 | options: None, |
657 | annotation_id: None, | 674 | annotation_id: None, |
658 | }) | 675 | }); |
676 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) | ||
659 | } | 677 | } |
660 | } | 678 | } |
679 | ops | ||
661 | } | 680 | } |
662 | 681 | ||
663 | pub(crate) fn snippet_workspace_edit( | 682 | pub(crate) fn snippet_workspace_edit( |
@@ -666,8 +685,8 @@ pub(crate) fn snippet_workspace_edit( | |||
666 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { | 685 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { |
667 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); | 686 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); |
668 | for op in source_change.file_system_edits { | 687 | for op in source_change.file_system_edits { |
669 | let op = resource_op(&snap, op); | 688 | let ops = snippet_text_document_ops(snap, op); |
670 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); | 689 | document_changes.extend_from_slice(&ops); |
671 | } | 690 | } |
672 | for edit in source_change.source_file_edits { | 691 | for edit in source_change.source_file_edits { |
673 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; | 692 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; |
@@ -761,6 +780,7 @@ pub(crate) fn unresolved_code_action( | |||
761 | assist: Assist, | 780 | assist: Assist, |
762 | index: usize, | 781 | index: usize, |
763 | ) -> Result<lsp_ext::CodeAction> { | 782 | ) -> Result<lsp_ext::CodeAction> { |
783 | assert!(assist.source_change.is_none()); | ||
764 | let res = lsp_ext::CodeAction { | 784 | let res = lsp_ext::CodeAction { |
765 | title: assist.label.to_string(), | 785 | title: assist.label.to_string(), |
766 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 786 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), |
@@ -777,18 +797,14 @@ pub(crate) fn unresolved_code_action( | |||
777 | 797 | ||
778 | pub(crate) fn resolved_code_action( | 798 | pub(crate) fn resolved_code_action( |
779 | snap: &GlobalStateSnapshot, | 799 | snap: &GlobalStateSnapshot, |
780 | assist: ResolvedAssist, | 800 | assist: Assist, |
781 | ) -> Result<lsp_ext::CodeAction> { | 801 | ) -> Result<lsp_ext::CodeAction> { |
782 | let change = assist.source_change; | 802 | let change = assist.source_change.unwrap(); |
783 | let res = lsp_ext::CodeAction { | 803 | let res = lsp_ext::CodeAction { |
784 | edit: Some(snippet_workspace_edit(snap, change)?), | 804 | edit: Some(snippet_workspace_edit(snap, change)?), |
785 | title: assist.assist.label.to_string(), | 805 | title: assist.label.to_string(), |
786 | group: assist | 806 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), |
787 | .assist | 807 | kind: Some(code_action_kind(assist.id.1)), |
788 | .group | ||
789 | .filter(|_| snap.config.client_caps.code_action_group) | ||
790 | .map(|gr| gr.0), | ||
791 | kind: Some(code_action_kind(assist.assist.id.1)), | ||
792 | is_preferred: None, | 808 | is_preferred: None, |
793 | data: None, | 809 | data: None, |
794 | }; | 810 | }; |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index c6a6f11e1..21015591c 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "691.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index e4a9b945c..636ce166d 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs | |||
@@ -358,6 +358,7 @@ pub enum Effect { | |||
358 | Async(SyntaxToken), | 358 | Async(SyntaxToken), |
359 | Unsafe(SyntaxToken), | 359 | Unsafe(SyntaxToken), |
360 | Try(SyntaxToken), | 360 | Try(SyntaxToken), |
361 | Const(SyntaxToken), | ||
361 | // Very much not an effect, but we stuff it into this node anyway | 362 | // Very much not an effect, but we stuff it into this node anyway |
362 | Label(ast::Label), | 363 | Label(ast::Label), |
363 | } | 364 | } |
@@ -373,6 +374,9 @@ impl ast::EffectExpr { | |||
373 | if let Some(token) = self.try_token() { | 374 | if let Some(token) = self.try_token() { |
374 | return Effect::Try(token); | 375 | return Effect::Try(token); |
375 | } | 376 | } |
377 | if let Some(token) = self.const_token() { | ||
378 | return Effect::Const(token); | ||
379 | } | ||
376 | if let Some(label) = self.label() { | 380 | if let Some(label) = self.label() { |
377 | return Effect::Label(label); | 381 | return Effect::Label(label); |
378 | } | 382 | } |
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 1588ba93e..c5b80bffe 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs | |||
@@ -763,6 +763,7 @@ impl EffectExpr { | |||
763 | pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } | 763 | pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } |
764 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } | 764 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } |
765 | pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } | 765 | pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } |
766 | pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } | ||
766 | pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } | 767 | pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } |
767 | } | 768 | } |
768 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 769 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -1251,6 +1252,14 @@ impl TupleStructPat { | |||
1251 | pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } | 1252 | pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } |
1252 | } | 1253 | } |
1253 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 1254 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
1255 | pub struct ConstBlockPat { | ||
1256 | pub(crate) syntax: SyntaxNode, | ||
1257 | } | ||
1258 | impl ConstBlockPat { | ||
1259 | pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } | ||
1260 | pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } | ||
1261 | } | ||
1262 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
1254 | pub struct RecordPatFieldList { | 1263 | pub struct RecordPatFieldList { |
1255 | pub(crate) syntax: SyntaxNode, | 1264 | pub(crate) syntax: SyntaxNode, |
1256 | } | 1265 | } |
@@ -1369,6 +1378,7 @@ pub enum Pat { | |||
1369 | SlicePat(SlicePat), | 1378 | SlicePat(SlicePat), |
1370 | TuplePat(TuplePat), | 1379 | TuplePat(TuplePat), |
1371 | TupleStructPat(TupleStructPat), | 1380 | TupleStructPat(TupleStructPat), |
1381 | ConstBlockPat(ConstBlockPat), | ||
1372 | } | 1382 | } |
1373 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 1383 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
1374 | pub enum FieldList { | 1384 | pub enum FieldList { |
@@ -2772,6 +2782,17 @@ impl AstNode for TupleStructPat { | |||
2772 | } | 2782 | } |
2773 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 2783 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
2774 | } | 2784 | } |
2785 | impl AstNode for ConstBlockPat { | ||
2786 | fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT } | ||
2787 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
2788 | if Self::can_cast(syntax.kind()) { | ||
2789 | Some(Self { syntax }) | ||
2790 | } else { | ||
2791 | None | ||
2792 | } | ||
2793 | } | ||
2794 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
2795 | } | ||
2775 | impl AstNode for RecordPatFieldList { | 2796 | impl AstNode for RecordPatFieldList { |
2776 | fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST } | 2797 | fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST } |
2777 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 2798 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
@@ -3242,12 +3263,15 @@ impl From<TuplePat> for Pat { | |||
3242 | impl From<TupleStructPat> for Pat { | 3263 | impl From<TupleStructPat> for Pat { |
3243 | fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) } | 3264 | fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) } |
3244 | } | 3265 | } |
3266 | impl From<ConstBlockPat> for Pat { | ||
3267 | fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) } | ||
3268 | } | ||
3245 | impl AstNode for Pat { | 3269 | impl AstNode for Pat { |
3246 | fn can_cast(kind: SyntaxKind) -> bool { | 3270 | fn can_cast(kind: SyntaxKind) -> bool { |
3247 | match kind { | 3271 | match kind { |
3248 | IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT | 3272 | IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT |
3249 | | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT | 3273 | | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT |
3250 | | TUPLE_PAT | TUPLE_STRUCT_PAT => true, | 3274 | | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true, |
3251 | _ => false, | 3275 | _ => false, |
3252 | } | 3276 | } |
3253 | } | 3277 | } |
@@ -3268,6 +3292,7 @@ impl AstNode for Pat { | |||
3268 | SLICE_PAT => Pat::SlicePat(SlicePat { syntax }), | 3292 | SLICE_PAT => Pat::SlicePat(SlicePat { syntax }), |
3269 | TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }), | 3293 | TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }), |
3270 | TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }), | 3294 | TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }), |
3295 | CONST_BLOCK_PAT => Pat::ConstBlockPat(ConstBlockPat { syntax }), | ||
3271 | _ => return None, | 3296 | _ => return None, |
3272 | }; | 3297 | }; |
3273 | Some(res) | 3298 | Some(res) |
@@ -3289,6 +3314,7 @@ impl AstNode for Pat { | |||
3289 | Pat::SlicePat(it) => &it.syntax, | 3314 | Pat::SlicePat(it) => &it.syntax, |
3290 | Pat::TuplePat(it) => &it.syntax, | 3315 | Pat::TuplePat(it) => &it.syntax, |
3291 | Pat::TupleStructPat(it) => &it.syntax, | 3316 | Pat::TupleStructPat(it) => &it.syntax, |
3317 | Pat::ConstBlockPat(it) => &it.syntax, | ||
3292 | } | 3318 | } |
3293 | } | 3319 | } |
3294 | } | 3320 | } |
@@ -4137,6 +4163,11 @@ impl std::fmt::Display for TupleStructPat { | |||
4137 | std::fmt::Display::fmt(self.syntax(), f) | 4163 | std::fmt::Display::fmt(self.syntax(), f) |
4138 | } | 4164 | } |
4139 | } | 4165 | } |
4166 | impl std::fmt::Display for ConstBlockPat { | ||
4167 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
4168 | std::fmt::Display::fmt(self.syntax(), f) | ||
4169 | } | ||
4170 | } | ||
4140 | impl std::fmt::Display for RecordPatFieldList { | 4171 | impl std::fmt::Display for RecordPatFieldList { |
4141 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 4172 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4142 | std::fmt::Display::fmt(self.syntax(), f) | 4173 | std::fmt::Display::fmt(self.syntax(), f) |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index ba7e5d2fb..cafa4c198 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -4,6 +4,11 @@ | |||
4 | //! Note that all functions here intended to be stupid constructors, which just | 4 | //! Note that all functions here intended to be stupid constructors, which just |
5 | //! assemble a finish node from immediate children. If you want to do something | 5 | //! assemble a finish node from immediate children. If you want to do something |
6 | //! smarter than that, it probably doesn't belong in this module. | 6 | //! smarter than that, it probably doesn't belong in this module. |
7 | //! | ||
8 | //! Keep in mind that `from_text` functions should be kept private. The public | ||
9 | //! API should require to assemble every node piecewise. The trick of | ||
10 | //! `parse(format!())` we use internally is an implementation detail -- long | ||
11 | //! term, it will be replaced with direct tree manipulation. | ||
7 | use itertools::Itertools; | 12 | use itertools::Itertools; |
8 | use stdx::format_to; | 13 | use stdx::format_to; |
9 | 14 | ||
@@ -16,7 +21,8 @@ pub fn name(text: &str) -> ast::Name { | |||
16 | pub fn name_ref(text: &str) -> ast::NameRef { | 21 | pub fn name_ref(text: &str) -> ast::NameRef { |
17 | ast_from_text(&format!("fn f() {{ {}; }}", text)) | 22 | ast_from_text(&format!("fn f() {{ {}; }}", text)) |
18 | } | 23 | } |
19 | 24 | // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la | |
25 | // `expr_xxx`. | ||
20 | pub fn ty(text: &str) -> ast::Type { | 26 | pub fn ty(text: &str) -> ast::Type { |
21 | ast_from_text(&format!("impl {} for D {{}};", text)) | 27 | ast_from_text(&format!("impl {} for D {{}};", text)) |
22 | } | 28 | } |
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast index 6403ff8d5..d3219f0b2 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast | |||
@@ -6,16 +6,16 @@ [email protected] | |||
6 | [email protected] "f" | 6 | [email protected] "f" |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "(" | 8 | [email protected] "(" |
9 | ATT[email protected]6 | 9 | SELF_PARAM@5..21 |
10 | POUND@5..6 "#" | 10 | ATTR@5..16 |
11 | L_BRACK@6..7 "[" | 11 | POUND@5..6 "#" |
12 | PATH@7..15 | 12 | L_BRACK@6..7 "[" |
13 | PATH_SEGMENT@7..15 | 13 | [email protected] |
14 | NAME_REF@7..15 | 14 | PATH_SEGMENT@7..15 |
15 | IDENT@7..15 "must_use" | 15 | NAME_REF@7..15 |
16 | R_BRACK@15..16 "]" | 16 | IDENT@7..15 "must_use" |
17 | WHITESPACE@16..17 " " | 17 | R_BRACK@15..16 "]" |
18 | SELF_PARAM@17..21 | 18 | WHITESPACE@16..17 " " |
19 | [email protected] "self" | 19 | [email protected] "self" |
20 | [email protected] ")" | 20 | [email protected] ")" |
21 | [email protected] " " | 21 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast new file mode 100644 index 000000000..edfcb288c --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast | |||
@@ -0,0 +1,43 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] "for" | ||
15 | [email protected] | ||
16 | [email protected] "<" | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "\'a" | ||
20 | [email protected] ">" | ||
21 | [email protected] " " | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] "Test" | ||
27 | [email protected] | ||
28 | [email protected] "<" | ||
29 | [email protected] | ||
30 | [email protected] | ||
31 | [email protected] "\'a" | ||
32 | [email protected] ">" | ||
33 | [email protected] " " | ||
34 | [email protected] "+" | ||
35 | [email protected] " " | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "Send" | ||
42 | [email protected] ";" | ||
43 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs new file mode 100644 index 000000000..47a71fd19 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs | |||
@@ -0,0 +1 @@ | |||
type A = for<'a> Test<'a> + Send; | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast new file mode 100644 index 000000000..d34b21abe --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast | |||
@@ -0,0 +1,50 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "const" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] ":" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "i64" | ||
16 | [email protected] "," | ||
17 | [email protected] " " | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] | ||
22 | [email protected] "i64" | ||
23 | [email protected] ")" | ||
24 | [email protected] " " | ||
25 | [email protected] "=" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "(" | ||
29 | [email protected] | ||
30 | [email protected] "1" | ||
31 | [email protected] "," | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "#" | ||
36 | [email protected] "[" | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] "cfg" | ||
41 | [email protected] | ||
42 | [email protected] "(" | ||
43 | [email protected] "test" | ||
44 | [email protected] ")" | ||
45 | [email protected] "]" | ||
46 | [email protected] " " | ||
47 | [email protected] "2" | ||
48 | [email protected] ")" | ||
49 | [email protected] ";" | ||
50 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs new file mode 100644 index 000000000..f84b7ab31 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs | |||
@@ -0,0 +1 @@ | |||
const A: (i64, i64) = (1, #[cfg(test)] 2); | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rast b/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rast new file mode 100644 index 000000000..8ff4822c4 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rast | |||
@@ -0,0 +1,76 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "main" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] "\n " | ||
14 | [email protected] | ||
15 | [email protected] "let" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] "const" | ||
19 | [email protected] " " | ||
20 | [email protected] | ||
21 | [email protected] "{" | ||
22 | [email protected] " " | ||
23 | [email protected] | ||
24 | [email protected] "15" | ||
25 | [email protected] " " | ||
26 | [email protected] "}" | ||
27 | [email protected] " " | ||
28 | [email protected] "=" | ||
29 | [email protected] " " | ||
30 | [email protected] | ||
31 | [email protected] "(" | ||
32 | [email protected] ")" | ||
33 | [email protected] ";" | ||
34 | [email protected] "\n " | ||
35 | [email protected] | ||
36 | [email protected] "let" | ||
37 | [email protected] " " | ||
38 | [email protected] | ||
39 | [email protected] "const" | ||
40 | [email protected] " " | ||
41 | [email protected] | ||
42 | [email protected] "{" | ||
43 | [email protected] " " | ||
44 | [email protected] | ||
45 | [email protected] | ||
46 | [email protected] | ||
47 | [email protected] | ||
48 | [email protected] | ||
49 | [email protected] | ||
50 | [email protected] "foo" | ||
51 | [email protected] | ||
52 | [email protected] "(" | ||
53 | [email protected] ")" | ||
54 | [email protected] ";" | ||
55 | [email protected] " " | ||
56 | [email protected] | ||
57 | [email protected] | ||
58 | [email protected] | ||
59 | [email protected] | ||
60 | [email protected] | ||
61 | [email protected] "bar" | ||
62 | [email protected] | ||
63 | [email protected] "(" | ||
64 | [email protected] ")" | ||
65 | [email protected] " " | ||
66 | [email protected] "}" | ||
67 | [email protected] " " | ||
68 | [email protected] "=" | ||
69 | [email protected] " " | ||
70 | [email protected] | ||
71 | [email protected] "(" | ||
72 | [email protected] ")" | ||
73 | [email protected] ";" | ||
74 | [email protected] "\n" | ||
75 | [email protected] "}" | ||
76 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rs b/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rs new file mode 100644 index 000000000..dce9defac --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0156_const_block_pat.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | let const { 15 } = (); | ||
3 | let const { foo(); bar() } = (); | ||
4 | } | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0157_const_block.rast b/crates/syntax/test_data/parser/inline/ok/0157_const_block.rast new file mode 100644 index 000000000..d5d2c8fe3 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0157_const_block.rast | |||
@@ -0,0 +1,23 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "f" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] "const" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] "{" | ||
19 | [email protected] " " | ||
20 | [email protected] "}" | ||
21 | [email protected] " " | ||
22 | [email protected] "}" | ||
23 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0157_const_block.rs b/crates/syntax/test_data/parser/inline/ok/0157_const_block.rs new file mode 100644 index 000000000..a2e3565a3 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0157_const_block.rs | |||
@@ -0,0 +1 @@ | |||
fn f() { const { } } | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast b/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast new file mode 100644 index 000000000..4a1f712aa --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast | |||
@@ -0,0 +1,57 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "macro_rules" | ||
4 | [email protected] "!" | ||
5 | [email protected] " " | ||
6 | [email protected] | ||
7 | [email protected] "m" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] " " | ||
12 | [email protected] | ||
13 | [email protected] "(" | ||
14 | [email protected] "$" | ||
15 | [email protected] "i" | ||
16 | [email protected] ":" | ||
17 | [email protected] "ident" | ||
18 | [email protected] ")" | ||
19 | [email protected] " " | ||
20 | [email protected] "=" | ||
21 | [email protected] ">" | ||
22 | [email protected] " " | ||
23 | [email protected] | ||
24 | [email protected] "{" | ||
25 | [email protected] "}" | ||
26 | [email protected] " " | ||
27 | [email protected] ")" | ||
28 | [email protected] ";" | ||
29 | [email protected] "\n" | ||
30 | [email protected] | ||
31 | [email protected] "macro_rules" | ||
32 | [email protected] "!" | ||
33 | [email protected] " " | ||
34 | [email protected] | ||
35 | [email protected] "m" | ||
36 | [email protected] " " | ||
37 | [email protected] | ||
38 | [email protected] "[" | ||
39 | [email protected] " " | ||
40 | [email protected] | ||
41 | [email protected] "(" | ||
42 | [email protected] "$" | ||
43 | [email protected] "i" | ||
44 | [email protected] ":" | ||
45 | [email protected] "ident" | ||
46 | [email protected] ")" | ||
47 | [email protected] " " | ||
48 | [email protected] "=" | ||
49 | [email protected] ">" | ||
50 | [email protected] " " | ||
51 | [email protected] | ||
52 | [email protected] "{" | ||
53 | [email protected] "}" | ||
54 | [email protected] " " | ||
55 | [email protected] "]" | ||
56 | [email protected] ";" | ||
57 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs b/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs new file mode 100644 index 000000000..6033a28cd --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | macro_rules! m ( ($i:ident) => {} ); | ||
2 | macro_rules! m [ ($i:ident) => {} ]; | ||
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast index 8974f9e40..3fed11838 100644 --- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast | |||
@@ -107,16 +107,16 @@ [email protected] | |||
107 | [email protected] "i8" | 107 | [email protected] "i8" |
108 | [email protected] "," | 108 | [email protected] "," |
109 | [email protected] " " | 109 | [email protected] " " |
110 | ATT[email protected]3 | 110 | PARAM@106..117 |
111 | POUND@106..107 "#" | 111 | ATTR@106..113 |
112 | L_BRACK@107..108 "[" | 112 | POUND@106..107 "#" |
113 | PATH@108..112 | 113 | L_BRACK@107..108 "[" |
114 | PATH_SEGMENT@108..112 | 114 | [email protected] |
115 | NAME_REF@108..112 | 115 | PATH_SEGMENT@108..112 |
116 | IDENT@108..112 "attr" | 116 | NAME_REF@108..112 |
117 | R_BRACK@112..113 "]" | 117 | IDENT@108..112 "attr" |
118 | WHITESPACE@113..114 " " | 118 | R_BRACK@112..113 "]" |
119 | PARAM@114..117 | 119 | WHITESPACE@113..114 " " |
120 | [email protected] "..." | 120 | [email protected] "..." |
121 | [email protected] ")" | 121 | [email protected] ")" |
122 | [email protected] " " | 122 | [email protected] " " |
@@ -153,16 +153,16 @@ [email protected] | |||
153 | [email protected] "FnMut" | 153 | [email protected] "FnMut" |
154 | [email protected] | 154 | [email protected] |
155 | [email protected] "(" | 155 | [email protected] "(" |
156 | ATT[email protected]53 | 156 | PARAM@146..166 |
157 | POUND@146..147 "#" | 157 | ATTR@146..153 |
158 | L_BRACK@147..148 "[" | 158 | POUND@146..147 "#" |
159 | PATH@148..152 | 159 | L_BRACK@147..148 "[" |
160 | PATH_SEGMENT@148..152 | 160 | [email protected] |
161 | NAME_REF@148..152 | 161 | PATH_SEGMENT@148..152 |
162 | IDENT@148..152 "attr" | 162 | NAME_REF@148..152 |
163 | R_BRACK@152..153 "]" | 163 | IDENT@148..152 "attr" |
164 | WHITESPACE@153..154 " " | 164 | R_BRACK@152..153 "]" |
165 | PARAM@154..166 | 165 | WHITESPACE@153..154 " " |
166 | [email protected] | 166 | [email protected] |
167 | [email protected] "&" | 167 | [email protected] "&" |
168 | [email protected] "mut" | 168 | [email protected] "mut" |
@@ -224,17 +224,17 @@ [email protected] | |||
224 | [email protected] "u64" | 224 | [email protected] "u64" |
225 | [email protected] "," | 225 | [email protected] "," |
226 | [email protected] " " | 226 | [email protected] " " |
227 | ATT[email protected]1 | 227 | PARAM@213..232 |
228 | POUND@213..214 "#" | 228 | ATTR@213..221 |
229 | WHITESPACE@214..215 " " | 229 | POUND@213..214 "#" |
230 | L_BRACK@215..216 "[" | 230 | WHITESPACE@214..215 " " |
231 | PATH@216..220 | 231 | L_BRACK@215..216 "[" |
232 | PATH_SEGMENT@216..220 | 232 | [email protected] |
233 | NAME_REF@216..220 | 233 | PATH_SEGMENT@216..220 |
234 | IDENT@216..220 "attr" | 234 | NAME_REF@216..220 |
235 | R_BRACK@220..221 "]" | 235 | IDENT@216..220 "attr" |
236 | WHITESPACE@221..222 " " | 236 | R_BRACK@220..221 "]" |
237 | PARAM@222..232 | 237 | WHITESPACE@221..222 " " |
238 | [email protected] | 238 | [email protected] |
239 | [email protected] "mut" | 239 | [email protected] "mut" |
240 | [email protected] " " | 240 | [email protected] " " |
@@ -271,16 +271,16 @@ [email protected] | |||
271 | [email protected] "f" | 271 | [email protected] "f" |
272 | [email protected] | 272 | [email protected] |
273 | [email protected] "(" | 273 | [email protected] "(" |
274 | ATT[email protected]68 | 274 | SELF_PARAM@257..273 |
275 | POUND@257..258 "#" | 275 | ATTR@257..268 |
276 | L_BRACK@258..259 "[" | 276 | POUND@257..258 "#" |
277 | PATH@259..267 | 277 | L_BRACK@258..259 "[" |
278 | PATH_SEGMENT@259..267 | 278 | [email protected] |
279 | NAME_REF@259..267 | 279 | PATH_SEGMENT@259..267 |
280 | IDENT@259..267 "must_use" | 280 | NAME_REF@259..267 |
281 | R_BRACK@267..268 "]" | 281 | IDENT@259..267 "must_use" |
282 | WHITESPACE@268..269 " " | 282 | R_BRACK@267..268 "]" |
283 | SELF_PARAM@269..273 | 283 | WHITESPACE@268..269 " " |
284 | [email protected] "self" | 284 | [email protected] "self" |
285 | [email protected] ")" | 285 | [email protected] ")" |
286 | [email protected] " " | 286 | [email protected] " " |
@@ -295,16 +295,16 @@ [email protected] | |||
295 | [email protected] "g1" | 295 | [email protected] "g1" |
296 | [email protected] | 296 | [email protected] |
297 | [email protected] "(" | 297 | [email protected] "(" |
298 | ATTR@289..296 | 298 | SELF_PARAM@289..301 |
299 | POUND@289..290 "#" | 299 | ATTR@289..296 |
300 | L_BRACK@290..291 "[" | 300 | POUND@289..290 "#" |
301 | PATH@291..295 | 301 | L_BRACK@290..291 "[" |
302 | PATH_SEGMENT@291..295 | 302 | [email protected] |
303 | NAME_REF@291..295 | 303 | PATH_SEGMENT@291..295 |
304 | IDENT@291..295 "attr" | 304 | NAME_REF@291..295 |
305 | R_BRACK@295..296 "]" | 305 | IDENT@291..295 "attr" |
306 | WHITESPACE@296..297 " " | 306 | R_BRACK@295..296 "]" |
307 | SELF_PARAM@297..301 | 307 | WHITESPACE@296..297 " " |
308 | [email protected] "self" | 308 | [email protected] "self" |
309 | [email protected] ")" | 309 | [email protected] ")" |
310 | [email protected] " " | 310 | [email protected] " " |
@@ -319,16 +319,16 @@ [email protected] | |||
319 | [email protected] "g2" | 319 | [email protected] "g2" |
320 | [email protected] | 320 | [email protected] |
321 | [email protected] "(" | 321 | [email protected] "(" |
322 | ATT[email protected]24 | 322 | SELF_PARAM@317..330 |
323 | POUND@317..318 "#" | 323 | ATTR@317..324 |
324 | L_BRACK@318..319 "[" | 324 | POUND@317..318 "#" |
325 | PATH@319..323 | 325 | L_BRACK@318..319 "[" |
326 | PATH_SEGMENT@319..323 | 326 | [email protected] |
327 | NAME_REF@319..323 | 327 | PATH_SEGMENT@319..323 |
328 | IDENT@319..323 "attr" | 328 | NAME_REF@319..323 |
329 | R_BRACK@323..324 "]" | 329 | IDENT@319..323 "attr" |
330 | WHITESPACE@324..325 " " | 330 | R_BRACK@323..324 "]" |
331 | SELF_PARAM@325..330 | 331 | WHITESPACE@324..325 " " |
332 | [email protected] "&" | 332 | [email protected] "&" |
333 | [email protected] "self" | 333 | [email protected] "self" |
334 | [email protected] ")" | 334 | [email protected] ")" |
@@ -350,16 +350,16 @@ [email protected] | |||
350 | [email protected] ">" | 350 | [email protected] ">" |
351 | [email protected] | 351 | [email protected] |
352 | [email protected] "(" | 352 | [email protected] "(" |
353 | ATT[email protected]57 | 353 | SELF_PARAM@350..367 |
354 | POUND@350..351 "#" | 354 | ATTR@350..357 |
355 | L_BRACK@351..352 "[" | 355 | POUND@350..351 "#" |
356 | PATH@352..356 | 356 | L_BRACK@351..352 "[" |
357 | PATH_SEGMENT@352..356 | 357 | [email protected] |
358 | NAME_REF@352..356 | 358 | PATH_SEGMENT@352..356 |
359 | IDENT@352..356 "attr" | 359 | NAME_REF@352..356 |
360 | R_BRACK@356..357 "]" | 360 | IDENT@352..356 "attr" |
361 | WHITESPACE@357..358 " " | 361 | R_BRACK@356..357 "]" |
362 | SELF_PARAM@358..367 | 362 | WHITESPACE@357..358 " " |
363 | [email protected] "&" | 363 | [email protected] "&" |
364 | [email protected] "mut" | 364 | [email protected] "mut" |
365 | [email protected] " " | 365 | [email protected] " " |
@@ -383,16 +383,16 @@ [email protected] | |||
383 | [email protected] ">" | 383 | [email protected] ">" |
384 | [email protected] | 384 | [email protected] |
385 | [email protected] "(" | 385 | [email protected] "(" |
386 | ATTR@387..394 | 386 | SELF_PARAM@387..403 |
387 | POUND@387..388 "#" | 387 | ATTR@387..394 |
388 | L_BRACK@388..389 "[" | 388 | POUND@387..388 "#" |
389 | PATH@389..393 | 389 | L_BRACK@388..389 "[" |
390 | PATH_SEGMENT@389..393 | 390 | [email protected] |
391 | NAME_REF@389..393 | 391 | PATH_SEGMENT@389..393 |
392 | IDENT@389..393 "attr" | 392 | NAME_REF@389..393 |
393 | R_BRACK@393..394 "]" | 393 | IDENT@389..393 "attr" |
394 | WHITESPACE@394..395 " " | 394 | R_BRACK@393..394 "]" |
395 | SELF_PARAM@395..403 | 395 | WHITESPACE@394..395 " " |
396 | [email protected] "&" | 396 | [email protected] "&" |
397 | [email protected] | 397 | [email protected] |
398 | [email protected] "\'a" | 398 | [email protected] "\'a" |
@@ -417,16 +417,16 @@ [email protected] | |||
417 | [email protected] ">" | 417 | [email protected] ">" |
418 | [email protected] | 418 | [email protected] |
419 | [email protected] "(" | 419 | [email protected] "(" |
420 | ATT[email protected]0 | 420 | SELF_PARAM@423..443 |
421 | POUND@423..424 "#" | 421 | ATTR@423..430 |
422 | L_BRACK@424..425 "[" | 422 | POUND@423..424 "#" |
423 | PATH@425..429 | 423 | L_BRACK@424..425 "[" |
424 | PATH_SEGMENT@425..429 | 424 | [email protected] |
425 | NAME_REF@425..429 | 425 | PATH_SEGMENT@425..429 |
426 | IDENT@425..429 "attr" | 426 | NAME_REF@425..429 |
427 | R_BRACK@429..430 "]" | 427 | IDENT@425..429 "attr" |
428 | WHITESPACE@430..431 " " | 428 | R_BRACK@429..430 "]" |
429 | SELF_PARAM@431..443 | 429 | WHITESPACE@430..431 " " |
430 | [email protected] "&" | 430 | [email protected] "&" |
431 | [email protected] | 431 | [email protected] |
432 | [email protected] "\'a" | 432 | [email protected] "\'a" |
@@ -447,16 +447,16 @@ [email protected] | |||
447 | [email protected] "c" | 447 | [email protected] "c" |
448 | [email protected] | 448 | [email protected] |
449 | [email protected] "(" | 449 | [email protected] "(" |
450 | ATT[email protected]5 | 450 | SELF_PARAM@458..476 |
451 | POUND@458..459 "#" | 451 | ATTR@458..465 |
452 | L_BRACK@459..460 "[" | 452 | POUND@458..459 "#" |
453 | PATH@460..464 | 453 | L_BRACK@459..460 "[" |
454 | PATH_SEGMENT@460..464 | 454 | [email protected] |
455 | NAME_REF@460..464 | 455 | PATH_SEGMENT@460..464 |
456 | IDENT@460..464 "attr" | 456 | NAME_REF@460..464 |
457 | R_BRACK@464..465 "]" | 457 | IDENT@460..464 "attr" |
458 | WHITESPACE@465..466 " " | 458 | R_BRACK@464..465 "]" |
459 | SELF_PARAM@466..476 | 459 | WHITESPACE@465..466 " " |
460 | [email protected] "self" | 460 | [email protected] "self" |
461 | [email protected] ":" | 461 | [email protected] ":" |
462 | [email protected] " " | 462 | [email protected] " " |
@@ -478,16 +478,16 @@ [email protected] | |||
478 | [email protected] "d" | 478 | [email protected] "d" |
479 | [email protected] | 479 | [email protected] |
480 | [email protected] "(" | 480 | [email protected] "(" |
481 | ATTR@491..498 | 481 | SELF_PARAM@491..513 |
482 | POUND@491..492 "#" | 482 | ATTR@491..498 |
483 | L_BRACK@492..493 "[" | 483 | POUND@491..492 "#" |
484 | PATH@493..497 | 484 | L_BRACK@492..493 "[" |
485 | PATH_SEGMENT@493..497 | 485 | [email protected] |
486 | NAME_REF@493..497 | 486 | PATH_SEGMENT@493..497 |
487 | IDENT@493..497 "attr" | 487 | NAME_REF@493..497 |
488 | R_BRACK@497..498 "]" | 488 | IDENT@493..497 "attr" |
489 | WHITESPACE@498..499 " " | 489 | R_BRACK@497..498 "]" |
490 | SELF_PARAM@499..513 | 490 | WHITESPACE@498..499 " " |
491 | [email protected] "self" | 491 | [email protected] "self" |
492 | [email protected] ":" | 492 | [email protected] ":" |
493 | [email protected] " " | 493 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast index 4009b3ff8..f7c094898 100644 --- a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast +++ b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast | |||
@@ -92,20 +92,20 @@ [email protected] | |||
92 | [email protected] "u8" | 92 | [email protected] "u8" |
93 | [email protected] "," | 93 | [email protected] "," |
94 | [email protected] " " | 94 | [email protected] " " |
95 | ATT[email protected]5 | 95 | PARAM@92..120 |
96 | POUND@92..93 "#" | 96 | ATTR@92..105 |
97 | L_BRACK@93..94 "[" | 97 | POUND@92..93 "#" |
98 | PATH@94..97 | 98 | L_BRACK@93..94 "[" |
99 | PATH_SEGMENT@94..97 | 99 | [email protected] |
100 | NAME_REF@94..97 | 100 | PATH_SEGMENT@94..97 |
101 | IDENT@94..97 "cfg" | 101 | NAME_REF@94..97 |
102 | TOKEN_TREE@97..104 | 102 | IDENT@94..97 "cfg" |
103 | L_PAREN@97..98 "(" | 103 | TOKEN_TREE@97..104 |
104 | IDENT@98..103 "never" | 104 | L_PAREN@97..98 "(" |
105 | R_PAREN@103..104 ")" | 105 | IDENT@98..103 "never" |
106 | R_BRACK@104..105 "]" | 106 | R_PAREN@103..104 ")" |
107 | WHITESPACE@105..106 " " | 107 | R_BRACK@104..105 "]" |
108 | PARAM@106..120 | 108 | WHITESPACE@105..106 " " |
109 | [email protected] | 109 | [email protected] |
110 | [email protected] "[" | 110 | [email protected] "[" |
111 | [email protected] | 111 | [email protected] |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index cb2ae6fc1..3025dc8d6 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -5,7 +5,7 @@ rust-analyzer.assist.importPrefix (default: `"plain"`):: | |||
5 | rust-analyzer.callInfo.full (default: `true`):: | 5 | rust-analyzer.callInfo.full (default: `true`):: |
6 | Show function name and docs in parameter hints. | 6 | Show function name and docs in parameter hints. |
7 | rust-analyzer.cargo.autoreload (default: `true`):: | 7 | rust-analyzer.cargo.autoreload (default: `true`):: |
8 | Automatically refresh project info via `cargo metadata` on Cargo.toml changes. | 8 | Automatically refresh project info via `cargo metadata` on `Cargo.toml` changes. |
9 | rust-analyzer.cargo.allFeatures (default: `false`):: | 9 | rust-analyzer.cargo.allFeatures (default: `false`):: |
10 | Activate all available features. | 10 | Activate all available features. |
11 | rust-analyzer.cargo.features (default: `[]`):: | 11 | rust-analyzer.cargo.features (default: `[]`):: |
@@ -21,7 +21,7 @@ rust-analyzer.cargo.noSysroot (default: `false`):: | |||
21 | rust-analyzer.checkOnSave.enable (default: `true`):: | 21 | rust-analyzer.checkOnSave.enable (default: `true`):: |
22 | Run specified `cargo check` command for diagnostics on save. | 22 | Run specified `cargo check` command for diagnostics on save. |
23 | rust-analyzer.checkOnSave.allFeatures (default: `null`):: | 23 | rust-analyzer.checkOnSave.allFeatures (default: `null`):: |
24 | Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`. | 24 | Check with all features (will be passed as `--all-features`). Defaults to `#rust-analyzer.cargo.allFeatures#`. |
25 | rust-analyzer.checkOnSave.allTargets (default: `true`):: | 25 | rust-analyzer.checkOnSave.allTargets (default: `true`):: |
26 | Check all targets and tests (will be passed as `--all-targets`). | 26 | Check all targets and tests (will be passed as `--all-targets`). |
27 | rust-analyzer.checkOnSave.command (default: `"check"`):: | 27 | rust-analyzer.checkOnSave.command (default: `"check"`):: |
@@ -29,11 +29,11 @@ rust-analyzer.checkOnSave.command (default: `"check"`):: | |||
29 | rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: | 29 | rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: |
30 | Do not activate the `default` feature. | 30 | Do not activate the `default` feature. |
31 | rust-analyzer.checkOnSave.target (default: `null`):: | 31 | rust-analyzer.checkOnSave.target (default: `null`):: |
32 | Check for a specific target. Defaults to `rust-analyzer.cargo.target`. | 32 | Check for a specific target. Defaults to `#rust-analyzer.cargo.target#`. |
33 | rust-analyzer.checkOnSave.extraArgs (default: `[]`):: | 33 | rust-analyzer.checkOnSave.extraArgs (default: `[]`):: |
34 | Extra arguments for `cargo check`. | 34 | Extra arguments for `cargo check`. |
35 | rust-analyzer.checkOnSave.features (default: `null`):: | 35 | rust-analyzer.checkOnSave.features (default: `null`):: |
36 | List of features to activate. Defaults to `rust-analyzer.cargo.features`. | 36 | List of features to activate. Defaults to `#rust-analyzer.cargo.features#`. |
37 | rust-analyzer.checkOnSave.overrideCommand (default: `null`):: | 37 | rust-analyzer.checkOnSave.overrideCommand (default: `null`):: |
38 | Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option. | 38 | Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option. |
39 | rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: | 39 | rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: |
@@ -43,7 +43,7 @@ rust-analyzer.completion.addCallParenthesis (default: `true`):: | |||
43 | rust-analyzer.completion.postfix.enable (default: `true`):: | 43 | rust-analyzer.completion.postfix.enable (default: `true`):: |
44 | Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | 44 | Whether to show postfix snippets like `dbg`, `if`, `not`, etc. |
45 | rust-analyzer.completion.autoimport.enable (default: `true`):: | 45 | rust-analyzer.completion.autoimport.enable (default: `true`):: |
46 | Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | 46 | Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. |
47 | rust-analyzer.diagnostics.enable (default: `true`):: | 47 | rust-analyzer.diagnostics.enable (default: `true`):: |
48 | Whether to show native rust-analyzer diagnostics. | 48 | Whether to show native rust-analyzer diagnostics. |
49 | rust-analyzer.diagnostics.enableExperimental (default: `true`):: | 49 | rust-analyzer.diagnostics.enableExperimental (default: `true`):: |
@@ -51,9 +51,9 @@ rust-analyzer.diagnostics.enableExperimental (default: `true`):: | |||
51 | rust-analyzer.diagnostics.disabled (default: `[]`):: | 51 | rust-analyzer.diagnostics.disabled (default: `[]`):: |
52 | List of rust-analyzer diagnostics to disable. | 52 | List of rust-analyzer diagnostics to disable. |
53 | rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: | 53 | rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: |
54 | List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel. | 54 | List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the `Problems Panel`. |
55 | rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: | 55 | rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: |
56 | List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel. | 56 | List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code and will not show up in the `Problems Panel`. |
57 | rust-analyzer.files.watcher (default: `"client"`):: | 57 | rust-analyzer.files.watcher (default: `"client"`):: |
58 | Controls file watching implementation. | 58 | Controls file watching implementation. |
59 | rust-analyzer.hoverActions.debug (default: `true`):: | 59 | rust-analyzer.hoverActions.debug (default: `true`):: |
@@ -71,7 +71,7 @@ rust-analyzer.hoverActions.linksInHover (default: `true`):: | |||
71 | rust-analyzer.inlayHints.chainingHints (default: `true`):: | 71 | rust-analyzer.inlayHints.chainingHints (default: `true`):: |
72 | Whether to show inlay type hints for method chains. | 72 | Whether to show inlay type hints for method chains. |
73 | rust-analyzer.inlayHints.maxLength (default: `null`):: | 73 | rust-analyzer.inlayHints.maxLength (default: `null`):: |
74 | Maximum length for inlay hints. | 74 | Maximum length for inlay hints. Default is unlimited. |
75 | rust-analyzer.inlayHints.parameterHints (default: `true`):: | 75 | rust-analyzer.inlayHints.parameterHints (default: `true`):: |
76 | Whether to show function parameter name inlay hints at the call site. | 76 | Whether to show function parameter name inlay hints at the call site. |
77 | rust-analyzer.inlayHints.typeHints (default: `true`):: | 77 | rust-analyzer.inlayHints.typeHints (default: `true`):: |
@@ -87,20 +87,20 @@ rust-analyzer.lens.run (default: `true`):: | |||
87 | rust-analyzer.lens.methodReferences (default: `false`):: | 87 | rust-analyzer.lens.methodReferences (default: `false`):: |
88 | Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. | 88 | Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. |
89 | rust-analyzer.linkedProjects (default: `[]`):: | 89 | rust-analyzer.linkedProjects (default: `[]`):: |
90 | Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format. | 90 | Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format. |
91 | rust-analyzer.lruCapacity (default: `null`):: | 91 | rust-analyzer.lruCapacity (default: `null`):: |
92 | Number of syntax trees rust-analyzer keeps in memory. | 92 | Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
93 | rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: | 93 | rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: |
94 | Whether to show `can't find Cargo.toml` error message. | 94 | Whether to show `can't find Cargo.toml` error message. |
95 | rust-analyzer.procMacro.enable (default: `false`):: | 95 | rust-analyzer.procMacro.enable (default: `false`):: |
96 | Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled. | 96 | Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled. |
97 | rust-analyzer.runnables.overrideCargo (default: `null`):: | 97 | rust-analyzer.runnables.overrideCargo (default: `null`):: |
98 | Command to be executed instead of 'cargo' for runnables. | 98 | Command to be executed instead of 'cargo' for runnables. |
99 | rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: | 99 | rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: |
100 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'. | 100 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`. |
101 | rust-analyzer.rustcSource (default: `null`):: | 101 | rust-analyzer.rustcSource (default: `null`):: |
102 | Path to the rust compiler sources, for usage in rustc_private projects. | 102 | Path to the rust compiler sources, for usage in rustc_private projects. |
103 | rust-analyzer.rustfmt.extraArgs (default: `[]`):: | 103 | rust-analyzer.rustfmt.extraArgs (default: `[]`):: |
104 | Additional arguments to rustfmt. | 104 | Additional arguments to `rustfmt`. |
105 | rust-analyzer.rustfmt.overrideCommand (default: `null`):: | 105 | rust-analyzer.rustfmt.overrideCommand (default: `null`):: |
106 | Advanced option, fully override the command rust-analyzer uses for formatting. | 106 | Advanced option, fully override the command rust-analyzer uses for formatting. |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 1ec6e81bb..d4121b401 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -46,8 +46,8 @@ You can install the latest release of the plugin from | |||
46 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. | 46 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. |
47 | 47 | ||
48 | Note that the plugin may cause conflicts with the | 48 | Note that the plugin may cause conflicts with the |
49 | https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. It is | 49 | https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. |
50 | recommended to disable the Rust plugin when using the rust-analyzer extension. | 50 | It is recommended to disable the Rust plugin when using the rust-analyzer extension. |
51 | 51 | ||
52 | By default, the plugin will prompt you to download the matching version of the server as well: | 52 | By default, the plugin will prompt you to download the matching version of the server as well: |
53 | 53 | ||
@@ -74,18 +74,21 @@ Note that we only support two most recent versions of VS Code. | |||
74 | 74 | ||
75 | ==== Updates | 75 | ==== Updates |
76 | 76 | ||
77 | The extension will be updated automatically as new versions become available. It will ask your permission to download the matching language server version binary if needed. | 77 | The extension will be updated automatically as new versions become available. |
78 | It will ask your permission to download the matching language server version binary if needed. | ||
78 | 79 | ||
79 | ===== Nightly | 80 | ===== Nightly |
80 | 81 | ||
81 | We ship nightly releases for VS Code. To help us out with testing the newest code and follow the bleeding edge of our `master`, please use the following config: | 82 | We ship nightly releases for VS Code. |
83 | To help us out with testing the newest code and follow the bleeding edge of our `master`, please use the following config: | ||
82 | 84 | ||
83 | [source,json] | 85 | [source,json] |
84 | ---- | 86 | ---- |
85 | { "rust-analyzer.updates.channel": "nightly" } | 87 | { "rust-analyzer.updates.channel": "nightly" } |
86 | ---- | 88 | ---- |
87 | 89 | ||
88 | You will be prompted to install the `nightly` extension version. Just click `Download now` and from that moment you will get automatic updates every 24 hours. | 90 | You will be prompted to install the `nightly` extension version. |
91 | Just click `Download now` and from that moment you will get automatic updates every 24 hours. | ||
89 | 92 | ||
90 | If you don't want to be asked for `Download now` every day when the new nightly version is released add the following to your `settings.json`: | 93 | If you don't want to be asked for `Download now` every day when the new nightly version is released add the following to your `settings.json`: |
91 | [source,json] | 94 | [source,json] |
@@ -160,7 +163,8 @@ $ chmod +x ~/.local/bin/rust-analyzer | |||
160 | 163 | ||
161 | Ensure `~/.local/bin` is listed in the `$PATH` variable. | 164 | Ensure `~/.local/bin` is listed in the `$PATH` variable. |
162 | 165 | ||
163 | Alternatively, you can install it from source using the following command: | 166 | Alternatively, you can install it from source using the command below. |
167 | You'll need the latest stable version of the Rust toolchain. | ||
164 | 168 | ||
165 | [source,bash] | 169 | [source,bash] |
166 | ---- | 170 | ---- |
@@ -198,7 +202,8 @@ Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode | |||
198 | 202 | ||
199 | === Vim/NeoVim | 203 | === Vim/NeoVim |
200 | 204 | ||
201 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example. | 205 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
206 | Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example. | ||
202 | 207 | ||
203 | The are several LSP client implementations for vim or neovim: | 208 | The are several LSP client implementations for vim or neovim: |
204 | 209 | ||
@@ -213,7 +218,7 @@ The are several LSP client implementations for vim or neovim: | |||
213 | * automatically install and upgrade stable/nightly releases | 218 | * automatically install and upgrade stable/nightly releases |
214 | * same configurations as VSCode extension, `rust-analyzer.serverPath`, `rust-analyzer.cargo.features` etc. | 219 | * same configurations as VSCode extension, `rust-analyzer.serverPath`, `rust-analyzer.cargo.features` etc. |
215 | * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc. | 220 | * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc. |
216 | * inlay hints for method chaining support, _Neovim Only_ | 221 | * inlay hints for variables and method chaining, _Neovim Only_ |
217 | * semantic highlighting is not implemented yet | 222 | * semantic highlighting is not implemented yet |
218 | 223 | ||
219 | ==== LanguageClient-neovim | 224 | ==== LanguageClient-neovim |
@@ -270,14 +275,16 @@ Once `neovim/nvim-lspconfig` is installed, use `+lua require'nvim_lsp'.rust_anal | |||
270 | 275 | ||
271 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. | 276 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
272 | 277 | ||
273 | You also need the `LSP` package. To install it: | 278 | You also need the `LSP` package. |
279 | To install it: | ||
274 | 280 | ||
275 | 1. If you've never installed a Sublime Text package, install Package Control: | 281 | 1. If you've never installed a Sublime Text package, install Package Control: |
276 | * Open the command palette (Win/Linux: `ctrl+shift+p`, Mac: `cmd+shift+p`) | 282 | * Open the command palette (Win/Linux: `ctrl+shift+p`, Mac: `cmd+shift+p`) |
277 | * Type `Install Package Control`, press enter | 283 | * Type `Install Package Control`, press enter |
278 | 2. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter. | 284 | 2. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter. |
279 | 285 | ||
280 | Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. The latter means that rust-analyzer is enabled by default in Rust projects. | 286 | Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. |
287 | The latter means that rust-analyzer is enabled by default in Rust projects. | ||
281 | 288 | ||
282 | If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. | 289 | If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. |
283 | 290 | ||
@@ -285,7 +292,8 @@ If you get an error saying `No such file or directory: 'rust-analyzer'`, see the | |||
285 | 292 | ||
286 | === GNOME Builder | 293 | === GNOME Builder |
287 | 294 | ||
288 | GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If the LSP binary is not available, GNOME Builder can install it when opening a Rust file. | 295 | GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. |
296 | If the LSP binary is not available, GNOME Builder can install it when opening a Rust file. | ||
289 | 297 | ||
290 | == Configuration | 298 | == Configuration |
291 | 299 | ||
@@ -294,6 +302,9 @@ GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If the LSP bi | |||
294 | rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. | 302 | rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. |
295 | Please consult your editor's documentation to learn how to configure LSP servers. | 303 | Please consult your editor's documentation to learn how to configure LSP servers. |
296 | 304 | ||
305 | To verify which configuration is actually used by rust-analyzer, set `RA_LOG` environment variable to `rust_analyzer=info` and look for config-related messages. | ||
306 | Logs should show both the JSON that rust-analyzer sees as well as the updated config. | ||
307 | |||
297 | This is the list of config options rust-analyzer supports: | 308 | This is the list of config options rust-analyzer supports: |
298 | 309 | ||
299 | include::./generated_config.adoc[] | 310 | include::./generated_config.adoc[] |
@@ -413,8 +424,8 @@ include::./generated_diagnostic.adoc[] | |||
413 | 424 | ||
414 | ==== Color configurations | 425 | ==== Color configurations |
415 | 426 | ||
416 | It is possible to change the foreground/background color of inlay hints. Just add this to your | 427 | It is possible to change the foreground/background color of inlay hints. |
417 | `settings.json`: | 428 | Just add this to your `settings.json`: |
418 | 429 | ||
419 | [source,jsonc] | 430 | [source,jsonc] |
420 | ---- | 431 | ---- |
@@ -436,7 +447,8 @@ It is possible to change the foreground/background color of inlay hints. Just ad | |||
436 | 447 | ||
437 | ==== Semantic style customizations | 448 | ==== Semantic style customizations |
438 | 449 | ||
439 | You can customize the look of different semantic elements in the source code. For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`: | 450 | You can customize the look of different semantic elements in the source code. |
451 | For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`: | ||
440 | 452 | ||
441 | [source,jsonc] | 453 | [source,jsonc] |
442 | ---- | 454 | ---- |
@@ -452,7 +464,9 @@ You can customize the look of different semantic elements in the source code. Fo | |||
452 | ---- | 464 | ---- |
453 | 465 | ||
454 | ==== Special `when` clause context for keybindings. | 466 | ==== Special `when` clause context for keybindings. |
455 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | 467 | You may use `inRustProject` context to configure keybindings for rust projects only. |
468 | For example: | ||
469 | |||
456 | [source,json] | 470 | [source,json] |
457 | ---- | 471 | ---- |
458 | { | 472 | { |
@@ -491,7 +505,8 @@ Or it is possible to specify vars more granularly: | |||
491 | ] | 505 | ] |
492 | ``` | 506 | ``` |
493 | 507 | ||
494 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | 508 | You can use any valid regular expression as a mask. |
509 | Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | ||
495 | 510 | ||
496 | ==== Compiler feedback from external commands | 511 | ==== Compiler feedback from external commands |
497 | 512 | ||
diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore index 5096ce4da..c1cf00fa0 100644 --- a/editors/code/.vscodeignore +++ b/editors/code/.vscodeignore | |||
@@ -4,6 +4,5 @@ | |||
4 | !package.json | 4 | !package.json |
5 | !package-lock.json | 5 | !package-lock.json |
6 | !ra_syntax_tree.tmGrammar.json | 6 | !ra_syntax_tree.tmGrammar.json |
7 | !rust.tmGrammar.json | ||
8 | !icon.png | 7 | !icon.png |
9 | !README.md | 8 | !README.md |
diff --git a/editors/code/package.json b/editors/code/package.json index ad01fea7b..13749a084 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -250,12 +250,12 @@ | |||
250 | } | 250 | } |
251 | ], | 251 | ], |
252 | "default": null, | 252 | "default": null, |
253 | "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command." | 253 | "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command." |
254 | }, | 254 | }, |
255 | "rust-analyzer.inlayHints.enable": { | 255 | "rust-analyzer.inlayHints.enable": { |
256 | "type": "boolean", | 256 | "type": "boolean", |
257 | "default": true, | 257 | "default": true, |
258 | "description": "Whether to show inlay hints" | 258 | "description": "Whether to show inlay hints." |
259 | }, | 259 | }, |
260 | "rust-analyzer.updates.channel": { | 260 | "rust-analyzer.updates.channel": { |
261 | "type": "string", | 261 | "type": "string", |
@@ -265,15 +265,15 @@ | |||
265 | ], | 265 | ], |
266 | "default": "stable", | 266 | "default": "stable", |
267 | "markdownEnumDescriptions": [ | 267 | "markdownEnumDescriptions": [ |
268 | "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general", | 268 | "`stable` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general.", |
269 | "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**" | 269 | "`nightly` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**." |
270 | ], | 270 | ], |
271 | "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs" | 271 | "markdownDescription": "Choose `nightly` updates to get the latest features and bug fixes every day. While `stable` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs." |
272 | }, | 272 | }, |
273 | "rust-analyzer.updates.askBeforeDownload": { | 273 | "rust-analyzer.updates.askBeforeDownload": { |
274 | "type": "boolean", | 274 | "type": "boolean", |
275 | "default": true, | 275 | "default": true, |
276 | "description": "Whether to ask for permission before downloading any files from the Internet" | 276 | "description": "Whether to ask for permission before downloading any files from the Internet." |
277 | }, | 277 | }, |
278 | "rust-analyzer.serverPath": { | 278 | "rust-analyzer.serverPath": { |
279 | "type": [ | 279 | "type": [ |
@@ -281,7 +281,7 @@ | |||
281 | "string" | 281 | "string" |
282 | ], | 282 | ], |
283 | "default": null, | 283 | "default": null, |
284 | "description": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used" | 284 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used" |
285 | }, | 285 | }, |
286 | "rust-analyzer.trace.server": { | 286 | "rust-analyzer.trace.server": { |
287 | "type": "string", | 287 | "type": "string", |
@@ -297,10 +297,10 @@ | |||
297 | "Full log" | 297 | "Full log" |
298 | ], | 298 | ], |
299 | "default": "off", | 299 | "default": "off", |
300 | "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)" | 300 | "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)." |
301 | }, | 301 | }, |
302 | "rust-analyzer.trace.extension": { | 302 | "rust-analyzer.trace.extension": { |
303 | "description": "Enable logging of VS Code extensions itself", | 303 | "description": "Enable logging of VS Code extensions itself.", |
304 | "type": "boolean", | 304 | "type": "boolean", |
305 | "default": false | 305 | "default": false |
306 | }, | 306 | }, |
@@ -327,14 +327,14 @@ | |||
327 | } | 327 | } |
328 | }, | 328 | }, |
329 | "rust-analyzer.debug.openDebugPane": { | 329 | "rust-analyzer.debug.openDebugPane": { |
330 | "description": "Whether to open up the Debug Pane on debugging start.", | 330 | "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.", |
331 | "type": "boolean", | 331 | "type": "boolean", |
332 | "default": false | 332 | "default": false |
333 | }, | 333 | }, |
334 | "rust-analyzer.debug.engineSettings": { | 334 | "rust-analyzer.debug.engineSettings": { |
335 | "type": "object", | 335 | "type": "object", |
336 | "default": {}, | 336 | "default": {}, |
337 | "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" | 337 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" |
338 | }, | 338 | }, |
339 | "rust-analyzer.assist.importMergeBehaviour": { | 339 | "rust-analyzer.assist.importMergeBehaviour": { |
340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", | 340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", |
@@ -362,7 +362,7 @@ | |||
362 | ], | 362 | ], |
363 | "enumDescriptions": [ | 363 | "enumDescriptions": [ |
364 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 364 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
365 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 365 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", |
366 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 366 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." |
367 | ] | 367 | ] |
368 | }, | 368 | }, |
@@ -372,7 +372,7 @@ | |||
372 | "type": "boolean" | 372 | "type": "boolean" |
373 | }, | 373 | }, |
374 | "rust-analyzer.cargo.autoreload": { | 374 | "rust-analyzer.cargo.autoreload": { |
375 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes.", | 375 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on `Cargo.toml` changes.", |
376 | "default": true, | 376 | "default": true, |
377 | "type": "boolean" | 377 | "type": "boolean" |
378 | }, | 378 | }, |
@@ -418,7 +418,7 @@ | |||
418 | "type": "boolean" | 418 | "type": "boolean" |
419 | }, | 419 | }, |
420 | "rust-analyzer.checkOnSave.allFeatures": { | 420 | "rust-analyzer.checkOnSave.allFeatures": { |
421 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`.", | 421 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `#rust-analyzer.cargo.allFeatures#`.", |
422 | "default": null, | 422 | "default": null, |
423 | "type": [ | 423 | "type": [ |
424 | "null", | 424 | "null", |
@@ -444,7 +444,7 @@ | |||
444 | ] | 444 | ] |
445 | }, | 445 | }, |
446 | "rust-analyzer.checkOnSave.target": { | 446 | "rust-analyzer.checkOnSave.target": { |
447 | "markdownDescription": "Check for a specific target. Defaults to `rust-analyzer.cargo.target`.", | 447 | "markdownDescription": "Check for a specific target. Defaults to `#rust-analyzer.cargo.target#`.", |
448 | "default": null, | 448 | "default": null, |
449 | "type": [ | 449 | "type": [ |
450 | "null", | 450 | "null", |
@@ -460,7 +460,7 @@ | |||
460 | } | 460 | } |
461 | }, | 461 | }, |
462 | "rust-analyzer.checkOnSave.features": { | 462 | "rust-analyzer.checkOnSave.features": { |
463 | "markdownDescription": "List of features to activate. Defaults to `rust-analyzer.cargo.features`.", | 463 | "markdownDescription": "List of features to activate. Defaults to `#rust-analyzer.cargo.features#`.", |
464 | "default": null, | 464 | "default": null, |
465 | "type": [ | 465 | "type": [ |
466 | "null", | 466 | "null", |
@@ -497,7 +497,7 @@ | |||
497 | "type": "boolean" | 497 | "type": "boolean" |
498 | }, | 498 | }, |
499 | "rust-analyzer.completion.autoimport.enable": { | 499 | "rust-analyzer.completion.autoimport.enable": { |
500 | "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", | 500 | "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", |
501 | "default": true, | 501 | "default": true, |
502 | "type": "boolean" | 502 | "type": "boolean" |
503 | }, | 503 | }, |
@@ -521,7 +521,7 @@ | |||
521 | "uniqueItems": true | 521 | "uniqueItems": true |
522 | }, | 522 | }, |
523 | "rust-analyzer.diagnostics.warningsAsHint": { | 523 | "rust-analyzer.diagnostics.warningsAsHint": { |
524 | "markdownDescription": "List of warnings that should be displayed with info severity.\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | 524 | "markdownDescription": "List of warnings that should be displayed with info severity.\\n\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the `Problems Panel`.", |
525 | "default": [], | 525 | "default": [], |
526 | "type": "array", | 526 | "type": "array", |
527 | "items": { | 527 | "items": { |
@@ -529,7 +529,7 @@ | |||
529 | } | 529 | } |
530 | }, | 530 | }, |
531 | "rust-analyzer.diagnostics.warningsAsInfo": { | 531 | "rust-analyzer.diagnostics.warningsAsInfo": { |
532 | "markdownDescription": "List of warnings that should be displayed with hint severity.\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | 532 | "markdownDescription": "List of warnings that should be displayed with hint severity.\\n\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the `Problems Panel`.", |
533 | "default": [], | 533 | "default": [], |
534 | "type": "array", | 534 | "type": "array", |
535 | "items": { | 535 | "items": { |
@@ -577,7 +577,7 @@ | |||
577 | "type": "boolean" | 577 | "type": "boolean" |
578 | }, | 578 | }, |
579 | "rust-analyzer.inlayHints.maxLength": { | 579 | "rust-analyzer.inlayHints.maxLength": { |
580 | "markdownDescription": "Maximum length for inlay hints.", | 580 | "markdownDescription": "Maximum length for inlay hints. Default is unlimited.", |
581 | "default": null, | 581 | "default": null, |
582 | "type": [ | 582 | "type": [ |
583 | "null", | 583 | "null", |
@@ -621,7 +621,7 @@ | |||
621 | "type": "boolean" | 621 | "type": "boolean" |
622 | }, | 622 | }, |
623 | "rust-analyzer.linkedProjects": { | 623 | "rust-analyzer.linkedProjects": { |
624 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \\nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format.", | 624 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\\n\\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.", |
625 | "default": [], | 625 | "default": [], |
626 | "type": "array", | 626 | "type": "array", |
627 | "items": { | 627 | "items": { |
@@ -632,7 +632,7 @@ | |||
632 | } | 632 | } |
633 | }, | 633 | }, |
634 | "rust-analyzer.lruCapacity": { | 634 | "rust-analyzer.lruCapacity": { |
635 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory.", | 635 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", |
636 | "default": null, | 636 | "default": null, |
637 | "type": [ | 637 | "type": [ |
638 | "null", | 638 | "null", |
@@ -646,7 +646,7 @@ | |||
646 | "type": "boolean" | 646 | "type": "boolean" |
647 | }, | 647 | }, |
648 | "rust-analyzer.procMacro.enable": { | 648 | "rust-analyzer.procMacro.enable": { |
649 | "markdownDescription": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.", | 649 | "markdownDescription": "Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled.", |
650 | "default": false, | 650 | "default": false, |
651 | "type": "boolean" | 651 | "type": "boolean" |
652 | }, | 652 | }, |
@@ -659,7 +659,7 @@ | |||
659 | ] | 659 | ] |
660 | }, | 660 | }, |
661 | "rust-analyzer.runnables.cargoExtraArgs": { | 661 | "rust-analyzer.runnables.cargoExtraArgs": { |
662 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be '--release'.", | 662 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be `--release`.", |
663 | "default": [], | 663 | "default": [], |
664 | "type": "array", | 664 | "type": "array", |
665 | "items": { | 665 | "items": { |
@@ -675,7 +675,7 @@ | |||
675 | ] | 675 | ] |
676 | }, | 676 | }, |
677 | "rust-analyzer.rustfmt.extraArgs": { | 677 | "rust-analyzer.rustfmt.extraArgs": { |
678 | "markdownDescription": "Additional arguments to rustfmt.", | 678 | "markdownDescription": "Additional arguments to `rustfmt`.", |
679 | "default": [], | 679 | "default": [], |
680 | "type": "array", | 680 | "type": "array", |
681 | "items": { | 681 | "items": { |
@@ -749,11 +749,6 @@ | |||
749 | ], | 749 | ], |
750 | "grammars": [ | 750 | "grammars": [ |
751 | { | 751 | { |
752 | "language": "rust", | ||
753 | "scopeName": "source.rust", | ||
754 | "path": "rust.tmGrammar.json" | ||
755 | }, | ||
756 | { | ||
757 | "language": "ra_syntax_tree", | 752 | "language": "ra_syntax_tree", |
758 | "scopeName": "source.ra_syntax_tree", | 753 | "scopeName": "source.ra_syntax_tree", |
759 | "path": "ra_syntax_tree.tmGrammar.json" | 754 | "path": "ra_syntax_tree.tmGrammar.json" |
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json deleted file mode 100644 index 4759bb116..000000000 --- a/editors/code/rust.tmGrammar.json +++ /dev/null | |||
@@ -1,1140 +0,0 @@ | |||
1 | { | ||
2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", | ||
3 | "name": "Rust", | ||
4 | "fileTypes": [ | ||
5 | "rs" | ||
6 | ], | ||
7 | "scopeName": "source.rust", | ||
8 | "patterns": [ | ||
9 | { | ||
10 | "comment": "boxed slice literal", | ||
11 | "begin": "(<)(\\[)", | ||
12 | "beginCaptures": { | ||
13 | "1": { | ||
14 | "name": "punctuation.brackets.angle.rust" | ||
15 | }, | ||
16 | "2": { | ||
17 | "name": "punctuation.brackets.square.rust" | ||
18 | } | ||
19 | }, | ||
20 | "end": ">", | ||
21 | "endCaptures": { | ||
22 | "0": { | ||
23 | "name": "punctuation.brackets.angle.rust" | ||
24 | } | ||
25 | }, | ||
26 | "patterns": [ | ||
27 | { | ||
28 | "include": "#block-comments" | ||
29 | }, | ||
30 | { | ||
31 | "include": "#comments" | ||
32 | }, | ||
33 | { | ||
34 | "include": "#gtypes" | ||
35 | }, | ||
36 | { | ||
37 | "include": "#lvariables" | ||
38 | }, | ||
39 | { | ||
40 | "include": "#lifetimes" | ||
41 | }, | ||
42 | { | ||
43 | "include": "#punctuation" | ||
44 | }, | ||
45 | { | ||
46 | "include": "#types" | ||
47 | } | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "comment": "macro type metavariables", | ||
52 | "name": "meta.macro.metavariable.type.rust", | ||
53 | "match": "(\\$)((crate)|([A-Z][A-Za-z0-9_]*))((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?", | ||
54 | "captures": { | ||
55 | "1": { | ||
56 | "name": "keyword.operator.macro.dollar.rust" | ||
57 | }, | ||
58 | "3": { | ||
59 | "name": "keyword.other.crate.rust" | ||
60 | }, | ||
61 | "4": { | ||
62 | "name": "entity.name.type.metavariable.rust" | ||
63 | }, | ||
64 | "6": { | ||
65 | "name": "keyword.operator.key-value.rust" | ||
66 | }, | ||
67 | "7": { | ||
68 | "name": "variable.other.metavariable.specifier.rust" | ||
69 | } | ||
70 | }, | ||
71 | "patterns": [ | ||
72 | { | ||
73 | "include": "#keywords" | ||
74 | } | ||
75 | ] | ||
76 | }, | ||
77 | { | ||
78 | "comment": "macro metavariables", | ||
79 | "name": "meta.macro.metavariable.rust", | ||
80 | "match": "(\\$)([a-z][A-Za-z0-9_]*)((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?", | ||
81 | "captures": { | ||
82 | "1": { | ||
83 | "name": "keyword.operator.macro.dollar.rust" | ||
84 | }, | ||
85 | "2": { | ||
86 | "name": "variable.other.metavariable.name.rust" | ||
87 | }, | ||
88 | "4": { | ||
89 | "name": "keyword.operator.key-value.rust" | ||
90 | }, | ||
91 | "5": { | ||
92 | "name": "variable.other.metavariable.specifier.rust" | ||
93 | } | ||
94 | }, | ||
95 | "patterns": [ | ||
96 | { | ||
97 | "include": "#keywords" | ||
98 | } | ||
99 | ] | ||
100 | }, | ||
101 | { | ||
102 | "comment": "macro rules", | ||
103 | "name": "meta.macro.rules.rust", | ||
104 | "match": "\\b(macro_rules!)\\s+(([a-z0-9_]+)|([A-Z][a-z0-9_]*))\\s+(\\{)", | ||
105 | "captures": { | ||
106 | "1": { | ||
107 | "name": "entity.name.function.macro.rules.rust" | ||
108 | }, | ||
109 | "3": { | ||
110 | "name": "entity.name.function.macro.rust" | ||
111 | }, | ||
112 | "4": { | ||
113 | "name": "entity.name.type.macro.rust" | ||
114 | }, | ||
115 | "5": { | ||
116 | "name": "punctuation.brackets.curly.rust" | ||
117 | } | ||
118 | } | ||
119 | }, | ||
120 | { | ||
121 | "comment": "attributes", | ||
122 | "name": "meta.attribute.rust", | ||
123 | "begin": "(#)(\\!?)(\\[)", | ||
124 | "beginCaptures": { | ||
125 | "1": { | ||
126 | "name": "punctuation.definition.attribute.rust" | ||
127 | }, | ||
128 | "2": { | ||
129 | "name": "keyword.operator.attribute.inner.rust" | ||
130 | }, | ||
131 | "3": { | ||
132 | "name": "punctuation.brackets.attribute.rust" | ||
133 | } | ||
134 | }, | ||
135 | "end": "\\]", | ||
136 | "endCaptures": { | ||
137 | "0": { | ||
138 | "name": "punctuation.brackets.attribute.rust" | ||
139 | } | ||
140 | }, | ||
141 | "patterns": [ | ||
142 | { | ||
143 | "include": "#block-comments" | ||
144 | }, | ||
145 | { | ||
146 | "include": "#comments" | ||
147 | }, | ||
148 | { | ||
149 | "include": "#keywords" | ||
150 | }, | ||
151 | { | ||
152 | "include": "#punctuation" | ||
153 | }, | ||
154 | { | ||
155 | "include": "#strings" | ||
156 | }, | ||
157 | { | ||
158 | "include": "#gtypes" | ||
159 | }, | ||
160 | { | ||
161 | "include": "#types" | ||
162 | } | ||
163 | ] | ||
164 | }, | ||
165 | { | ||
166 | "comment": "modules", | ||
167 | "match": "(mod)\\s+((?:r#(?!crate|[Ss]elf|super))?[a-z][A-Za-z0-9_]*)", | ||
168 | "captures": { | ||
169 | "1": { | ||
170 | "name": "storage.type.rust" | ||
171 | }, | ||
172 | "2": { | ||
173 | "name": "entity.name.module.rust" | ||
174 | } | ||
175 | } | ||
176 | }, | ||
177 | { | ||
178 | "comment": "external crate imports", | ||
179 | "name": "meta.import.rust", | ||
180 | "begin": "\\b(extern)\\s+(crate)", | ||
181 | "beginCaptures": { | ||
182 | "1": { | ||
183 | "name": "storage.type.rust" | ||
184 | }, | ||
185 | "2": { | ||
186 | "name": "keyword.other.crate.rust" | ||
187 | } | ||
188 | }, | ||
189 | "end": ";", | ||
190 | "endCaptures": { | ||
191 | "0": { | ||
192 | "name": "punctuation.semi.rust" | ||
193 | } | ||
194 | }, | ||
195 | "patterns": [ | ||
196 | { | ||
197 | "include": "#block-comments" | ||
198 | }, | ||
199 | { | ||
200 | "include": "#comments" | ||
201 | }, | ||
202 | { | ||
203 | "include": "#keywords" | ||
204 | }, | ||
205 | { | ||
206 | "include": "#punctuation" | ||
207 | } | ||
208 | ] | ||
209 | }, | ||
210 | { | ||
211 | "comment": "use statements", | ||
212 | "name": "meta.use.rust", | ||
213 | "begin": "\\b(use)\\s", | ||
214 | "beginCaptures": { | ||
215 | "1": { | ||
216 | "name": "keyword.other.rust" | ||
217 | } | ||
218 | }, | ||
219 | "end": ";", | ||
220 | "endCaptures": { | ||
221 | "0": { | ||
222 | "name": "punctuation.semi.rust" | ||
223 | } | ||
224 | }, | ||
225 | "patterns": [ | ||
226 | { | ||
227 | "include": "#block-comments" | ||
228 | }, | ||
229 | { | ||
230 | "include": "#comments" | ||
231 | }, | ||
232 | { | ||
233 | "include": "#keywords" | ||
234 | }, | ||
235 | { | ||
236 | "include": "#namespaces" | ||
237 | }, | ||
238 | { | ||
239 | "include": "#punctuation" | ||
240 | }, | ||
241 | { | ||
242 | "include": "#types" | ||
243 | }, | ||
244 | { | ||
245 | "include": "#lvariables" | ||
246 | } | ||
247 | ] | ||
248 | }, | ||
249 | { | ||
250 | "include": "#block-comments" | ||
251 | }, | ||
252 | { | ||
253 | "include": "#comments" | ||
254 | }, | ||
255 | { | ||
256 | "include": "#lvariables" | ||
257 | }, | ||
258 | { | ||
259 | "include": "#constants" | ||
260 | }, | ||
261 | { | ||
262 | "include": "#gtypes" | ||
263 | }, | ||
264 | { | ||
265 | "include": "#functions" | ||
266 | }, | ||
267 | { | ||
268 | "include": "#types" | ||
269 | }, | ||
270 | { | ||
271 | "include": "#keywords" | ||
272 | }, | ||
273 | { | ||
274 | "include": "#lifetimes" | ||
275 | }, | ||
276 | { | ||
277 | "include": "#macros" | ||
278 | }, | ||
279 | { | ||
280 | "include": "#namespaces" | ||
281 | }, | ||
282 | { | ||
283 | "include": "#punctuation" | ||
284 | }, | ||
285 | { | ||
286 | "include": "#strings" | ||
287 | }, | ||
288 | { | ||
289 | "include": "#variables" | ||
290 | } | ||
291 | ], | ||
292 | "repository": { | ||
293 | "comments": { | ||
294 | "patterns": [ | ||
295 | { | ||
296 | "comment": "documentation comments", | ||
297 | "name": "comment.line.documentation.rust", | ||
298 | "match": "^\\s*///.*" | ||
299 | }, | ||
300 | { | ||
301 | "comment": "line comments", | ||
302 | "name": "comment.line.double-slash.rust", | ||
303 | "match": "\\s*//.*" | ||
304 | } | ||
305 | ] | ||
306 | }, | ||
307 | "block-comments": { | ||
308 | "patterns": [ | ||
309 | { | ||
310 | "comment": "empty block comments", | ||
311 | "name": "comment.block.rust", | ||
312 | "match": "/\\*\\*/" | ||
313 | }, | ||
314 | { | ||
315 | "comment": "block documentation comments", | ||
316 | "name": "comment.block.documentation.rust", | ||
317 | "begin": "/\\*\\*", | ||
318 | "end": "\\*/", | ||
319 | "patterns": [ | ||
320 | { | ||
321 | "include": "#block-comments" | ||
322 | } | ||
323 | ] | ||
324 | }, | ||
325 | { | ||
326 | "comment": "block comments", | ||
327 | "name": "comment.block.rust", | ||
328 | "begin": "/\\*(?!\\*)", | ||
329 | "end": "\\*/", | ||
330 | "patterns": [ | ||
331 | { | ||
332 | "include": "#block-comments" | ||
333 | } | ||
334 | ] | ||
335 | } | ||
336 | ] | ||
337 | }, | ||
338 | "constants": { | ||
339 | "patterns": [ | ||
340 | { | ||
341 | "comment": "ALL CAPS constants", | ||
342 | "name": "constant.other.caps.rust", | ||
343 | "match": "\\b[A-Z]{2}[A-Z0-9_]*\\b" | ||
344 | }, | ||
345 | { | ||
346 | "comment": "constant declarations", | ||
347 | "match": "\\b(const)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
348 | "captures": { | ||
349 | "1": { | ||
350 | "name": "storage.type.rust" | ||
351 | }, | ||
352 | "2": { | ||
353 | "name": "constant.other.caps.rust" | ||
354 | } | ||
355 | } | ||
356 | }, | ||
357 | { | ||
358 | "comment": "decimal integers and floats", | ||
359 | "name": "constant.numeric.decimal.rust", | ||
360 | "match": "\\b\\d[\\d_]*(\\.?)[\\d_]*(?:(E)([+-])([\\d_]+))?(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
361 | "captures": { | ||
362 | "1": { | ||
363 | "name": "punctuation.separator.dot.decimal.rust" | ||
364 | }, | ||
365 | "2": { | ||
366 | "name": "keyword.operator.exponent.rust" | ||
367 | }, | ||
368 | "3": { | ||
369 | "name": "keyword.operator.exponent.sign.rust" | ||
370 | }, | ||
371 | "4": { | ||
372 | "name": "constant.numeric.decimal.exponent.mantissa.rust" | ||
373 | }, | ||
374 | "5": { | ||
375 | "name": "entity.name.type.numeric.rust" | ||
376 | } | ||
377 | } | ||
378 | }, | ||
379 | { | ||
380 | "comment": "hexadecimal integers", | ||
381 | "name": "constant.numeric.hex.rust", | ||
382 | "match": "\\b0x[\\da-fA-F_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
383 | "captures": { | ||
384 | "1": { | ||
385 | "name": "entity.name.type.numeric.rust" | ||
386 | } | ||
387 | } | ||
388 | }, | ||
389 | { | ||
390 | "comment": "octal integers", | ||
391 | "name": "constant.numeric.oct.rust", | ||
392 | "match": "\\b0o[0-7_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
393 | "captures": { | ||
394 | "1": { | ||
395 | "name": "entity.name.type.numeric.rust" | ||
396 | } | ||
397 | } | ||
398 | }, | ||
399 | { | ||
400 | "comment": "binary integers", | ||
401 | "name": "constant.numeric.bin.rust", | ||
402 | "match": "\\b0b[01_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
403 | "captures": { | ||
404 | "1": { | ||
405 | "name": "entity.name.type.numeric.rust" | ||
406 | } | ||
407 | } | ||
408 | }, | ||
409 | { | ||
410 | "comment": "booleans", | ||
411 | "name": "constant.language.bool.rust", | ||
412 | "match": "\\b(true|false)\\b" | ||
413 | } | ||
414 | ] | ||
415 | }, | ||
416 | "escapes": { | ||
417 | "comment": "escapes: ASCII, byte, Unicode, quote, regex", | ||
418 | "name": "constant.character.escape.rust", | ||
419 | "match": "(\\\\)(?:(?:(x[0-7][0-7a-fA-F])|(u(\\{)[\\da-fA-F]{4,6}(\\}))|.))", | ||
420 | "captures": { | ||
421 | "1": { | ||
422 | "name": "constant.character.escape.backslash.rust" | ||
423 | }, | ||
424 | "2": { | ||
425 | "name": "constant.character.escape.bit.rust" | ||
426 | }, | ||
427 | "3": { | ||
428 | "name": "constant.character.escape.unicode.rust" | ||
429 | }, | ||
430 | "4": { | ||
431 | "name": "constant.character.escape.unicode.punctuation.rust" | ||
432 | }, | ||
433 | "5": { | ||
434 | "name": "constant.character.escape.unicode.punctuation.rust" | ||
435 | } | ||
436 | } | ||
437 | }, | ||
438 | "functions": { | ||
439 | "patterns": [ | ||
440 | { | ||
441 | "comment": "pub as a function", | ||
442 | "match": "\\b(pub)(\\()", | ||
443 | "captures": { | ||
444 | "1": { | ||
445 | "name": "keyword.other.rust" | ||
446 | }, | ||
447 | "2": { | ||
448 | "name": "punctuation.brackets.round.rust" | ||
449 | } | ||
450 | } | ||
451 | }, | ||
452 | { | ||
453 | "comment": "function definition", | ||
454 | "name": "meta.function.definition.rust", | ||
455 | "begin": "\\b(fn)\\s+((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)((\\()|(<))", | ||
456 | "beginCaptures": { | ||
457 | "1": { | ||
458 | "name": "keyword.other.fn.rust" | ||
459 | }, | ||
460 | "2": { | ||
461 | "name": "entity.name.function.rust" | ||
462 | }, | ||
463 | "4": { | ||
464 | "name": "punctuation.brackets.round.rust" | ||
465 | }, | ||
466 | "5": { | ||
467 | "name": "punctuation.brackets.angle.rust" | ||
468 | } | ||
469 | }, | ||
470 | "end": "\\{|;", | ||
471 | "endCaptures": { | ||
472 | "0": { | ||
473 | "name": "punctuation.brackets.curly.rust" | ||
474 | } | ||
475 | }, | ||
476 | "patterns": [ | ||
477 | { | ||
478 | "include": "#block-comments" | ||
479 | }, | ||
480 | { | ||
481 | "include": "#comments" | ||
482 | }, | ||
483 | { | ||
484 | "include": "#keywords" | ||
485 | }, | ||
486 | { | ||
487 | "include": "#lvariables" | ||
488 | }, | ||
489 | { | ||
490 | "include": "#constants" | ||
491 | }, | ||
492 | { | ||
493 | "include": "#gtypes" | ||
494 | }, | ||
495 | { | ||
496 | "include": "#functions" | ||
497 | }, | ||
498 | { | ||
499 | "include": "#lifetimes" | ||
500 | }, | ||
501 | { | ||
502 | "include": "#macros" | ||
503 | }, | ||
504 | { | ||
505 | "include": "#namespaces" | ||
506 | }, | ||
507 | { | ||
508 | "include": "#punctuation" | ||
509 | }, | ||
510 | { | ||
511 | "include": "#strings" | ||
512 | }, | ||
513 | { | ||
514 | "include": "#types" | ||
515 | }, | ||
516 | { | ||
517 | "include": "#variables" | ||
518 | } | ||
519 | ] | ||
520 | }, | ||
521 | { | ||
522 | "comment": "function/method calls, chaining", | ||
523 | "name": "meta.function.call.rust", | ||
524 | "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(\\()", | ||
525 | "beginCaptures": { | ||
526 | "1": { | ||
527 | "name": "entity.name.function.rust" | ||
528 | }, | ||
529 | "2": { | ||
530 | "name": "punctuation.brackets.round.rust" | ||
531 | } | ||
532 | }, | ||
533 | "end": "\\)", | ||
534 | "endCaptures": { | ||
535 | "0": { | ||
536 | "name": "punctuation.brackets.round.rust" | ||
537 | } | ||
538 | }, | ||
539 | "patterns": [ | ||
540 | { | ||
541 | "include": "#block-comments" | ||
542 | }, | ||
543 | { | ||
544 | "include": "#comments" | ||
545 | }, | ||
546 | { | ||
547 | "include": "#keywords" | ||
548 | }, | ||
549 | { | ||
550 | "include": "#lvariables" | ||
551 | }, | ||
552 | { | ||
553 | "include": "#constants" | ||
554 | }, | ||
555 | { | ||
556 | "include": "#gtypes" | ||
557 | }, | ||
558 | { | ||
559 | "include": "#functions" | ||
560 | }, | ||
561 | { | ||
562 | "include": "#lifetimes" | ||
563 | }, | ||
564 | { | ||
565 | "include": "#macros" | ||
566 | }, | ||
567 | { | ||
568 | "include": "#namespaces" | ||
569 | }, | ||
570 | { | ||
571 | "include": "#punctuation" | ||
572 | }, | ||
573 | { | ||
574 | "include": "#strings" | ||
575 | }, | ||
576 | { | ||
577 | "include": "#types" | ||
578 | }, | ||
579 | { | ||
580 | "include": "#variables" | ||
581 | } | ||
582 | ] | ||
583 | }, | ||
584 | { | ||
585 | "comment": "function/method calls with turbofish", | ||
586 | "name": "meta.function.call.rust", | ||
587 | "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(?=::<.*>\\()", | ||
588 | "beginCaptures": { | ||
589 | "1": { | ||
590 | "name": "entity.name.function.rust" | ||
591 | } | ||
592 | }, | ||
593 | "end": "\\)", | ||
594 | "endCaptures": { | ||
595 | "0": { | ||
596 | "name": "punctuation.brackets.round.rust" | ||
597 | } | ||
598 | }, | ||
599 | "patterns": [ | ||
600 | { | ||
601 | "include": "#block-comments" | ||
602 | }, | ||
603 | { | ||
604 | "include": "#comments" | ||
605 | }, | ||
606 | { | ||
607 | "include": "#keywords" | ||
608 | }, | ||
609 | { | ||
610 | "include": "#lvariables" | ||
611 | }, | ||
612 | { | ||
613 | "include": "#constants" | ||
614 | }, | ||
615 | { | ||
616 | "include": "#gtypes" | ||
617 | }, | ||
618 | { | ||
619 | "include": "#functions" | ||
620 | }, | ||
621 | { | ||
622 | "include": "#lifetimes" | ||
623 | }, | ||
624 | { | ||
625 | "include": "#macros" | ||
626 | }, | ||
627 | { | ||
628 | "include": "#namespaces" | ||
629 | }, | ||
630 | { | ||
631 | "include": "#punctuation" | ||
632 | }, | ||
633 | { | ||
634 | "include": "#strings" | ||
635 | }, | ||
636 | { | ||
637 | "include": "#types" | ||
638 | }, | ||
639 | { | ||
640 | "include": "#variables" | ||
641 | } | ||
642 | ] | ||
643 | } | ||
644 | ] | ||
645 | }, | ||
646 | "keywords": { | ||
647 | "patterns": [ | ||
648 | { | ||
649 | "comment": "control flow keywords", | ||
650 | "name": "keyword.control.rust", | ||
651 | "match": "\\b(await|break|continue|do|else|for|if|loop|match|return|try|while|yield)\\b" | ||
652 | }, | ||
653 | { | ||
654 | "comment": "storage keywords", | ||
655 | "name": "storage.type.rust", | ||
656 | "match": "\\b(const|enum|extern|let|macro|mod|struct|trait|type)\\b" | ||
657 | }, | ||
658 | { | ||
659 | "comment": "storage modifiers", | ||
660 | "name": "storage.modifier.rust", | ||
661 | "match": "\\b(abstract|static)\\b" | ||
662 | }, | ||
663 | { | ||
664 | "comment": "other keywords", | ||
665 | "name": "keyword.other.rust", | ||
666 | "match": "\\b(as|async|become|box|dyn|move|final|impl|in|override|priv|pub|ref|typeof|union|unsafe|unsized|use|virtual|where)\\b" | ||
667 | }, | ||
668 | { | ||
669 | "comment": "fn", | ||
670 | "name": "keyword.other.fn.rust", | ||
671 | "match": "\\bfn\\b" | ||
672 | }, | ||
673 | { | ||
674 | "comment": "crate", | ||
675 | "name": "keyword.other.crate.rust", | ||
676 | "match": "\\bcrate\\b" | ||
677 | }, | ||
678 | { | ||
679 | "comment": "mut", | ||
680 | "name": "storage.modifier.mut.rust", | ||
681 | "match": "\\bmut\\b" | ||
682 | }, | ||
683 | { | ||
684 | "comment": "logical operators", | ||
685 | "name": "keyword.operator.logical.rust", | ||
686 | "match": "(\\^|\\||\\|\\||&&|<<|>>|!)(?!=)" | ||
687 | }, | ||
688 | { | ||
689 | "comment": "logical AND, borrow references", | ||
690 | "name": "keyword.operator.borrow.and.rust", | ||
691 | "match": "&(?![&=])" | ||
692 | }, | ||
693 | { | ||
694 | "comment": "assignment operators", | ||
695 | "name": "keyword.operator.assignment.rust", | ||
696 | "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|<<=|>>=)" | ||
697 | }, | ||
698 | { | ||
699 | "comment": "single equal", | ||
700 | "name": "keyword.operator.assignment.equal.rust", | ||
701 | "match": "(?<![<>])=(?!=|>)" | ||
702 | }, | ||
703 | { | ||
704 | "comment": "comparison operators", | ||
705 | "name": "keyword.operator.comparison.rust", | ||
706 | "match": "(=(=)?(?!>)|!=|<=|(?<!=)>=)" | ||
707 | }, | ||
708 | { | ||
709 | "comment": "math operators", | ||
710 | "name": "keyword.operator.math.rust", | ||
711 | "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))" | ||
712 | }, | ||
713 | { | ||
714 | "comment": "less than, greater than (special case)", | ||
715 | "match": "(?:\\b|(?:(\\))|(\\])|(\\})))[ \\t]+([<>])[ \\t]+(?:\\b|(?:(\\()|(\\[)|(\\{)))", | ||
716 | "captures": { | ||
717 | "1": { | ||
718 | "name": "punctuation.brackets.round.rust" | ||
719 | }, | ||
720 | "2": { | ||
721 | "name": "punctuation.brackets.square.rust" | ||
722 | }, | ||
723 | "3": { | ||
724 | "name": "punctuation.brackets.curly.rust" | ||
725 | }, | ||
726 | "4": { | ||
727 | "name": "keyword.operator.comparison.rust" | ||
728 | }, | ||
729 | "5": { | ||
730 | "name": "punctuation.brackets.round.rust" | ||
731 | }, | ||
732 | "6": { | ||
733 | "name": "punctuation.brackets.square.rust" | ||
734 | }, | ||
735 | "7": { | ||
736 | "name": "punctuation.brackets.curly.rust" | ||
737 | } | ||
738 | } | ||
739 | }, | ||
740 | { | ||
741 | "comment": "namespace operator", | ||
742 | "name": "keyword.operator.namespace.rust", | ||
743 | "match": "::" | ||
744 | }, | ||
745 | { | ||
746 | "comment": "dereference asterisk", | ||
747 | "match": "(\\*)(?=\\w+)", | ||
748 | "captures": { | ||
749 | "1": { | ||
750 | "name": "keyword.operator.dereference.rust" | ||
751 | } | ||
752 | } | ||
753 | }, | ||
754 | { | ||
755 | "comment": "subpattern binding", | ||
756 | "name": "keyword.operator.subpattern.rust", | ||
757 | "match": "@" | ||
758 | }, | ||
759 | { | ||
760 | "comment": "dot access", | ||
761 | "name": "keyword.operator.access.dot.rust", | ||
762 | "match": "\\.(?!\\.)" | ||
763 | }, | ||
764 | { | ||
765 | "comment": "ranges, range patterns", | ||
766 | "name": "keyword.operator.range.rust", | ||
767 | "match": "\\.{2}(=|\\.)?" | ||
768 | }, | ||
769 | { | ||
770 | "comment": "colon", | ||
771 | "name": "keyword.operator.key-value.rust", | ||
772 | "match": ":(?!:)" | ||
773 | }, | ||
774 | { | ||
775 | "comment": "dashrocket, skinny arrow", | ||
776 | "name": "keyword.operator.arrow.skinny.rust", | ||
777 | "match": "->" | ||
778 | }, | ||
779 | { | ||
780 | "comment": "hashrocket, fat arrow", | ||
781 | "name": "keyword.operator.arrow.fat.rust", | ||
782 | "match": "=>" | ||
783 | }, | ||
784 | { | ||
785 | "comment": "dollar macros", | ||
786 | "name": "keyword.operator.macro.dollar.rust", | ||
787 | "match": "\\$" | ||
788 | }, | ||
789 | { | ||
790 | "comment": "question mark operator, questionably sized, macro kleene matcher", | ||
791 | "name": "keyword.operator.question.rust", | ||
792 | "match": "\\?" | ||
793 | } | ||
794 | ] | ||
795 | }, | ||
796 | "interpolations": { | ||
797 | "comment": "curly brace interpolations", | ||
798 | "name": "meta.interpolation.rust", | ||
799 | "match": "({)[^\"{}]*(})", | ||
800 | "captures": { | ||
801 | "1": { | ||
802 | "name": "punctuation.definition.interpolation.rust" | ||
803 | }, | ||
804 | "2": { | ||
805 | "name": "punctuation.definition.interpolation.rust" | ||
806 | } | ||
807 | } | ||
808 | }, | ||
809 | "lifetimes": { | ||
810 | "patterns": [ | ||
811 | { | ||
812 | "comment": "named lifetime parameters", | ||
813 | "match": "(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b", | ||
814 | "captures": { | ||
815 | "1": { | ||
816 | "name": "punctuation.definition.lifetime.rust" | ||
817 | }, | ||
818 | "2": { | ||
819 | "name": "entity.name.type.lifetime.rust" | ||
820 | } | ||
821 | } | ||
822 | }, | ||
823 | { | ||
824 | "comment": "borrowing references to named lifetimes", | ||
825 | "match": "(\\&)(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b", | ||
826 | "captures": { | ||
827 | "1": { | ||
828 | "name": "keyword.operator.borrow.rust" | ||
829 | }, | ||
830 | "2": { | ||
831 | "name": "punctuation.definition.lifetime.rust" | ||
832 | }, | ||
833 | "3": { | ||
834 | "name": "entity.name.type.lifetime.rust" | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | ] | ||
839 | }, | ||
840 | "macros": { | ||
841 | "patterns": [ | ||
842 | { | ||
843 | "comment": "macros", | ||
844 | "name": "meta.macro.rust", | ||
845 | "match": "(([a-z_][A-Za-z0-9_]*!)|([A-Z_][A-Za-z0-9_]*!))", | ||
846 | "captures": { | ||
847 | "2": { | ||
848 | "name": "entity.name.function.macro.rust" | ||
849 | }, | ||
850 | "3": { | ||
851 | "name": "entity.name.type.macro.rust" | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | ] | ||
856 | }, | ||
857 | "namespaces": { | ||
858 | "patterns": [ | ||
859 | { | ||
860 | "comment": "namespace (non-type, non-function path segment)", | ||
861 | "match": "(?<![A-Za-z0-9_])([a-z0-9_]+)((?<!super|self)::)", | ||
862 | "captures": { | ||
863 | "1": { | ||
864 | "name": "entity.name.namespace.rust" | ||
865 | }, | ||
866 | "2": { | ||
867 | "name": "keyword.operator.namespace.rust" | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | ] | ||
872 | }, | ||
873 | "types": { | ||
874 | "patterns": [ | ||
875 | { | ||
876 | "comment": "numeric types", | ||
877 | "match": "(?<![A-Za-z])(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)\\b", | ||
878 | "captures": { | ||
879 | "1": { | ||
880 | "name": "entity.name.type.numeric.rust" | ||
881 | } | ||
882 | } | ||
883 | }, | ||
884 | { | ||
885 | "comment": "parameterized types", | ||
886 | "begin": "\\b([A-Z][A-Za-z0-9]*)(<)", | ||
887 | "beginCaptures": { | ||
888 | "1": { | ||
889 | "name": "entity.name.type.rust" | ||
890 | }, | ||
891 | "2": { | ||
892 | "name": "punctuation.brackets.angle.rust" | ||
893 | } | ||
894 | }, | ||
895 | "end": ">", | ||
896 | "endCaptures": { | ||
897 | "0": { | ||
898 | "name": "punctuation.brackets.angle.rust" | ||
899 | } | ||
900 | }, | ||
901 | "patterns": [ | ||
902 | { | ||
903 | "include": "#block-comments" | ||
904 | }, | ||
905 | { | ||
906 | "include": "#comments" | ||
907 | }, | ||
908 | { | ||
909 | "include": "#keywords" | ||
910 | }, | ||
911 | { | ||
912 | "include": "#lvariables" | ||
913 | }, | ||
914 | { | ||
915 | "include": "#lifetimes" | ||
916 | }, | ||
917 | { | ||
918 | "include": "#punctuation" | ||
919 | }, | ||
920 | { | ||
921 | "include": "#types" | ||
922 | }, | ||
923 | { | ||
924 | "include": "#variables" | ||
925 | } | ||
926 | ] | ||
927 | }, | ||
928 | { | ||
929 | "comment": "primitive types", | ||
930 | "name": "entity.name.type.primitive.rust", | ||
931 | "match": "\\b(bool|char|str)\\b" | ||
932 | }, | ||
933 | { | ||
934 | "comment": "trait declarations", | ||
935 | "match": "\\b(trait)\\s+([A-Z][A-Za-z0-9]*)\\b", | ||
936 | "captures": { | ||
937 | "1": { | ||
938 | "name": "storage.type.rust" | ||
939 | }, | ||
940 | "2": { | ||
941 | "name": "entity.name.type.trait.rust" | ||
942 | } | ||
943 | } | ||
944 | }, | ||
945 | { | ||
946 | "comment": "struct declarations", | ||
947 | "match": "\\b(struct)\\s+([A-Z][A-Za-z0-9]*)\\b", | ||
948 | "captures": { | ||
949 | "1": { | ||
950 | "name": "storage.type.rust" | ||
951 | }, | ||
952 | "2": { | ||
953 | "name": "entity.name.type.struct.rust" | ||
954 | } | ||
955 | } | ||
956 | }, | ||
957 | { | ||
958 | "comment": "enum declarations", | ||
959 | "match": "\\b(enum)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
960 | "captures": { | ||
961 | "1": { | ||
962 | "name": "storage.type.rust" | ||
963 | }, | ||
964 | "2": { | ||
965 | "name": "entity.name.type.enum.rust" | ||
966 | } | ||
967 | } | ||
968 | }, | ||
969 | { | ||
970 | "comment": "type declarations", | ||
971 | "match": "\\b(type)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
972 | "captures": { | ||
973 | "1": { | ||
974 | "name": "storage.type.rust" | ||
975 | }, | ||
976 | "2": { | ||
977 | "name": "entity.name.type.declaration.rust" | ||
978 | } | ||
979 | } | ||
980 | }, | ||
981 | { | ||
982 | "comment": "types", | ||
983 | "name": "entity.name.type.rust", | ||
984 | "match": "\\b[A-Z][A-Za-z0-9]*\\b(?!!)" | ||
985 | } | ||
986 | ] | ||
987 | }, | ||
988 | "gtypes": { | ||
989 | "patterns": [ | ||
990 | { | ||
991 | "comment": "option types", | ||
992 | "name": "entity.name.type.option.rust", | ||
993 | "match": "\\b(Some|None)\\b" | ||
994 | }, | ||
995 | { | ||
996 | "comment": "result types", | ||
997 | "name": "entity.name.type.result.rust", | ||
998 | "match": "\\b(Ok|Err)\\b" | ||
999 | } | ||
1000 | ] | ||
1001 | }, | ||
1002 | "punctuation": { | ||
1003 | "patterns": [ | ||
1004 | { | ||
1005 | "comment": "comma", | ||
1006 | "name": "punctuation.comma.rust", | ||
1007 | "match": "," | ||
1008 | }, | ||
1009 | { | ||
1010 | "comment": "curly braces", | ||
1011 | "name": "punctuation.brackets.curly.rust", | ||
1012 | "match": "[{}]" | ||
1013 | }, | ||
1014 | { | ||
1015 | "comment": "parentheses, round brackets", | ||
1016 | "name": "punctuation.brackets.round.rust", | ||
1017 | "match": "[()]" | ||
1018 | }, | ||
1019 | { | ||
1020 | "comment": "semicolon", | ||
1021 | "name": "punctuation.semi.rust", | ||
1022 | "match": ";" | ||
1023 | }, | ||
1024 | { | ||
1025 | "comment": "square brackets", | ||
1026 | "name": "punctuation.brackets.square.rust", | ||
1027 | "match": "[\\[\\]]" | ||
1028 | }, | ||
1029 | { | ||
1030 | "comment": "angle brackets", | ||
1031 | "name": "punctuation.brackets.angle.rust", | ||
1032 | "match": "(?<!=)[<>]" | ||
1033 | } | ||
1034 | ] | ||
1035 | }, | ||
1036 | "strings": { | ||
1037 | "patterns": [ | ||
1038 | { | ||
1039 | "comment": "double-quoted strings and byte strings", | ||
1040 | "name": "string.quoted.double.rust", | ||
1041 | "begin": "(b?)(\")", | ||
1042 | "beginCaptures": { | ||
1043 | "1": { | ||
1044 | "name": "string.quoted.byte.raw.rust" | ||
1045 | }, | ||
1046 | "2": { | ||
1047 | "name": "punctuation.definition.string.rust" | ||
1048 | } | ||
1049 | }, | ||
1050 | "end": "\"", | ||
1051 | "endCaptures": { | ||
1052 | "0": { | ||
1053 | "name": "punctuation.definition.string.rust" | ||
1054 | } | ||
1055 | }, | ||
1056 | "patterns": [ | ||
1057 | { | ||
1058 | "include": "#escapes" | ||
1059 | }, | ||
1060 | { | ||
1061 | "include": "#interpolations" | ||
1062 | } | ||
1063 | ] | ||
1064 | }, | ||
1065 | { | ||
1066 | "comment": "double-quoted raw strings and raw byte strings", | ||
1067 | "name": "string.quoted.double.rust", | ||
1068 | "begin": "(b?r)(#*)(\")", | ||
1069 | "beginCaptures": { | ||
1070 | "1": { | ||
1071 | "name": "string.quoted.byte.raw.rust" | ||
1072 | }, | ||
1073 | "2": { | ||
1074 | "name": "punctuation.definition.string.raw.rust" | ||
1075 | }, | ||
1076 | "3": { | ||
1077 | "name": "punctuation.definition.string.rust" | ||
1078 | } | ||
1079 | }, | ||
1080 | "end": "(\")(\\2)", | ||
1081 | "endCaptures": { | ||
1082 | "1": { | ||
1083 | "name": "punctuation.definition.string.rust" | ||
1084 | }, | ||
1085 | "2": { | ||
1086 | "name": "punctuation.definition.string.raw.rust" | ||
1087 | } | ||
1088 | } | ||
1089 | }, | ||
1090 | { | ||
1091 | "comment": "characters and bytes", | ||
1092 | "name": "string.quoted.single.char.rust", | ||
1093 | "begin": "(b)?(')", | ||
1094 | "beginCaptures": { | ||
1095 | "1": { | ||
1096 | "name": "string.quoted.byte.raw.rust" | ||
1097 | }, | ||
1098 | "2": { | ||
1099 | "name": "punctuation.definition.char.rust" | ||
1100 | } | ||
1101 | }, | ||
1102 | "end": "'", | ||
1103 | "endCaptures": { | ||
1104 | "0": { | ||
1105 | "name": "punctuation.definition.char.rust" | ||
1106 | } | ||
1107 | }, | ||
1108 | "patterns": [ | ||
1109 | { | ||
1110 | "include": "#escapes" | ||
1111 | } | ||
1112 | ] | ||
1113 | } | ||
1114 | ] | ||
1115 | }, | ||
1116 | "lvariables": { | ||
1117 | "patterns": [ | ||
1118 | { | ||
1119 | "comment": "self", | ||
1120 | "name": "variable.language.self.rust", | ||
1121 | "match": "\\b[Ss]elf\\b" | ||
1122 | }, | ||
1123 | { | ||
1124 | "comment": "super", | ||
1125 | "name": "variable.language.super.rust", | ||
1126 | "match": "\\bsuper\\b" | ||
1127 | } | ||
1128 | ] | ||
1129 | }, | ||
1130 | "variables": { | ||
1131 | "patterns": [ | ||
1132 | { | ||
1133 | "comment": "variables", | ||
1134 | "name": "variable.other.rust", | ||
1135 | "match": "\\b(?<!(?<!\\.)\\.)(?:r#(?!(crate|[Ss]elf|super)))?[a-z0-9_]+\\b" | ||
1136 | } | ||
1137 | ] | ||
1138 | } | ||
1139 | } | ||
1140 | } | ||
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 92bc4d7f7..9d4823a34 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -470,7 +470,7 @@ export function resolveCodeAction(ctx: Ctx): Cmd { | |||
470 | return; | 470 | return; |
471 | } | 471 | } |
472 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); | 472 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); |
473 | await applySnippetWorkspaceEdit(edit); | 473 | await vscode.workspace.applyEdit(edit); |
474 | }; | 474 | }; |
475 | } | 475 | } |
476 | 476 | ||
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 191960960..282240d84 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -19,9 +19,8 @@ let ctx: Ctx | undefined; | |||
19 | const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; | 19 | const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; |
20 | 20 | ||
21 | export async function activate(context: vscode.ExtensionContext) { | 21 | export async function activate(context: vscode.ExtensionContext) { |
22 | // For some reason vscode not always shows pop-up error notifications | 22 | // VS Code doesn't show a notification when an extension fails to activate |
23 | // when an extension fails to activate, so we do it explicitly by ourselves. | 23 | // so we do it ourselves. |
24 | // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242 | ||
25 | await tryActivate(context).catch(err => { | 24 | await tryActivate(context).catch(err => { |
26 | void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); | 25 | void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); |
27 | throw err; | 26 | throw err; |
@@ -132,7 +131,7 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
132 | ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); | 131 | ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); |
133 | 132 | ||
134 | activateInlayHints(ctx); | 133 | activateInlayHints(ctx); |
135 | warnAboutRustLangExtensionConflict(); | 134 | warnAboutExtensionConflicts(); |
136 | 135 | ||
137 | vscode.workspace.onDidChangeConfiguration( | 136 | vscode.workspace.onDidChangeConfiguration( |
138 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), | 137 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), |
@@ -288,10 +287,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
288 | if (config.package.releaseTag === null) return "rust-analyzer"; | 287 | if (config.package.releaseTag === null) return "rust-analyzer"; |
289 | 288 | ||
290 | let platform: string | undefined; | 289 | let platform: string | undefined; |
291 | if (process.arch === "x64" || process.arch === "ia32") { | 290 | if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") { |
292 | if (process.platform === "linux") platform = "linux"; | 291 | platform = "x86_64-pc-windows-msvc"; |
293 | if (process.platform === "darwin") platform = "mac"; | 292 | } else if (process.arch === "x64" && process.platform === "linux") { |
294 | if (process.platform === "win32") platform = "windows"; | 293 | platform = "x86_64-unknown-linux-gnu"; |
294 | } else if (process.arch === "x64" && process.platform === "darwin") { | ||
295 | platform = "x86_64-apple-darwin"; | ||
296 | } else if (process.arch === "arm64" && process.platform === "darwin") { | ||
297 | platform = "aarch64-apple-darwin"; | ||
295 | } | 298 | } |
296 | if (platform === undefined) { | 299 | if (platform === undefined) { |
297 | vscode.window.showErrorMessage( | 300 | vscode.window.showErrorMessage( |
@@ -304,7 +307,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
304 | ); | 307 | ); |
305 | return undefined; | 308 | return undefined; |
306 | } | 309 | } |
307 | const ext = platform === "windows" ? ".exe" : ""; | 310 | const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : ""; |
308 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); | 311 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); |
309 | const exists = await fs.stat(dest).then(() => true, () => false); | 312 | const exists = await fs.stat(dest).then(() => true, () => false); |
310 | if (!exists) { | 313 | if (!exists) { |
@@ -340,7 +343,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
340 | }); | 343 | }); |
341 | 344 | ||
342 | // Patching executable if that's NixOS. | 345 | // Patching executable if that's NixOS. |
343 | if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) { | 346 | if (await isNixOs()) { |
344 | await patchelf(dest); | 347 | await patchelf(dest); |
345 | } | 348 | } |
346 | 349 | ||
@@ -348,6 +351,15 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
348 | return dest; | 351 | return dest; |
349 | } | 352 | } |
350 | 353 | ||
354 | async function isNixOs(): Promise<boolean> { | ||
355 | try { | ||
356 | const contents = await fs.readFile("/etc/os-release"); | ||
357 | return contents.indexOf("ID=nixos") !== -1; | ||
358 | } catch (e) { | ||
359 | return false; | ||
360 | } | ||
361 | } | ||
362 | |||
351 | async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { | 363 | async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { |
352 | while (true) { | 364 | while (true) { |
353 | try { | 365 | try { |
@@ -401,11 +413,21 @@ async function queryForGithubToken(state: PersistentState): Promise<void> { | |||
401 | } | 413 | } |
402 | } | 414 | } |
403 | 415 | ||
404 | function warnAboutRustLangExtensionConflict() { | 416 | function warnAboutExtensionConflicts() { |
405 | const rustLangExt = vscode.extensions.getExtension("rust-lang.rust"); | 417 | const conflicting = [ |
406 | if (rustLangExt !== undefined) { | 418 | ["rust-analyzer", "matklad.rust-analyzer"], |
419 | ["Rust", "rust-lang.rust"], | ||
420 | ["Rust", "kalitaalexey.vscode-rust"], | ||
421 | ]; | ||
422 | |||
423 | const found = conflicting.filter( | ||
424 | nameId => vscode.extensions.getExtension(nameId[1]) !== undefined); | ||
425 | |||
426 | if (found.length > 1) { | ||
427 | const fst = found[0]; | ||
428 | const sec = found[1]; | ||
407 | vscode.window.showWarningMessage( | 429 | vscode.window.showWarningMessage( |
408 | "You have both rust-analyzer (matklad.rust-analyzer) and Rust (rust-lang.rust) " + | 430 | `You have both the ${fst[0]} (${fst[1]}) and ${sec[0]} (${sec[1]}) ` + |
409 | "plugins enabled. These are known to conflict and cause various functions of " + | 431 | "plugins enabled. These are known to conflict and cause various functions of " + |
410 | "both plugins to not work correctly. You should disable one of them.", "Got it"); | 432 | "both plugins to not work correctly. You should disable one of them.", "Got it"); |
411 | }; | 433 | }; |
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 78a0b54ba..96b4ea448 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml | |||
@@ -15,7 +15,7 @@ flate2 = "1.0" | |||
15 | pico-args = "0.3.1" | 15 | pico-args = "0.3.1" |
16 | proc-macro2 = "1.0.8" | 16 | proc-macro2 = "1.0.8" |
17 | quote = "1.0.2" | 17 | quote = "1.0.2" |
18 | ungrammar = "1.4" | 18 | ungrammar = "1.5" |
19 | walkdir = "2.3.1" | 19 | walkdir = "2.3.1" |
20 | write-json = "0.1.0" | 20 | write-json = "0.1.0" |
21 | xshell = "0.1" | 21 | xshell = "0.1" |
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index a69ced5cc..2b8012bdd 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -132,6 +132,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
132 | "RANGE_PAT", | 132 | "RANGE_PAT", |
133 | "LITERAL_PAT", | 133 | "LITERAL_PAT", |
134 | "MACRO_PAT", | 134 | "MACRO_PAT", |
135 | "CONST_BLOCK_PAT", | ||
135 | // atoms | 136 | // atoms |
136 | "TUPLE_EXPR", | 137 | "TUPLE_EXPR", |
137 | "ARRAY_EXPR", | 138 | "ARRAY_EXPR", |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index 9e15a5a4c..d59b88131 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -58,30 +58,73 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | fn dist_server() -> Result<()> { | 60 | fn dist_server() -> Result<()> { |
61 | if cfg!(target_os = "linux") { | 61 | let target = get_target(); |
62 | if target.contains("-linux-gnu") { | ||
62 | env::set_var("CC", "clang"); | 63 | env::set_var("CC", "clang"); |
63 | } | 64 | } |
64 | cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release").run()?; | ||
65 | |||
66 | let (src, dst) = if cfg!(target_os = "linux") { | ||
67 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux") | ||
68 | } else if cfg!(target_os = "windows") { | ||
69 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") | ||
70 | } else if cfg!(target_os = "macos") { | ||
71 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-mac") | ||
72 | } else { | ||
73 | panic!("Unsupported OS") | ||
74 | }; | ||
75 | 65 | ||
76 | let src = Path::new(src); | 66 | let toolchain = toolchain(&target); |
77 | let dst = Path::new(dst); | 67 | cmd!("cargo +{toolchain} build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?; |
78 | 68 | ||
79 | cp(&src, &dst)?; | 69 | let suffix = exe_suffix(&target); |
70 | let src = | ||
71 | Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix)); | ||
72 | let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix)); | ||
80 | gzip(&src, &dst.with_extension("gz"))?; | 73 | gzip(&src, &dst.with_extension("gz"))?; |
81 | 74 | ||
75 | // FIXME: the old names are temporarily kept for client compatibility, but they should be removed | ||
76 | // Remove this block after a couple of releases | ||
77 | match target.as_ref() { | ||
78 | "x86_64-unknown-linux-gnu" => { | ||
79 | cp(&src, "dist/rust-analyzer-linux")?; | ||
80 | gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?; | ||
81 | } | ||
82 | "x86_64-pc-windows-msvc" => { | ||
83 | cp(&src, "dist/rust-analyzer-windows.exe")?; | ||
84 | gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?; | ||
85 | } | ||
86 | "x86_64-apple-darwin" => { | ||
87 | cp(&src, "dist/rust-analyzer-mac")?; | ||
88 | gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?; | ||
89 | } | ||
90 | _ => {} | ||
91 | } | ||
92 | |||
82 | Ok(()) | 93 | Ok(()) |
83 | } | 94 | } |
84 | 95 | ||
96 | fn get_target() -> String { | ||
97 | match env::var("RA_TARGET") { | ||
98 | Ok(target) => target, | ||
99 | _ => { | ||
100 | if cfg!(target_os = "linux") { | ||
101 | "x86_64-unknown-linux-gnu".to_string() | ||
102 | } else if cfg!(target_os = "windows") { | ||
103 | "x86_64-pc-windows-msvc".to_string() | ||
104 | } else if cfg!(target_os = "macos") { | ||
105 | "x86_64-apple-darwin".to_string() | ||
106 | } else { | ||
107 | panic!("Unsupported OS, maybe try setting RA_TARGET") | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | fn exe_suffix(target: &str) -> String { | ||
114 | if target.contains("-windows-") { | ||
115 | ".exe".into() | ||
116 | } else { | ||
117 | "".into() | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn toolchain(target: &str) -> String { | ||
122 | match target { | ||
123 | "aarch64-apple-darwin" => "beta".to_string(), | ||
124 | _ => "stable".to_string(), | ||
125 | } | ||
126 | } | ||
127 | |||
85 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { | 128 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { |
86 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); | 129 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); |
87 | let mut input = io::BufReader::new(File::open(src_path)?); | 130 | let mut input = io::BufReader::new(File::open(src_path)?); |