diff options
56 files changed, 985 insertions, 443 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 889ada401..ece1fd364 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -15,8 +15,8 @@ env: | |||
15 | RUSTUP_MAX_RETRIES: 10 | 15 | RUSTUP_MAX_RETRIES: 10 |
16 | 16 | ||
17 | jobs: | 17 | jobs: |
18 | dist-windows: | 18 | dist-x86_64-pc-windows-msvc: |
19 | name: dist (Windows) | 19 | name: dist (x86_64-pc-windows-msvc) |
20 | runs-on: windows-latest | 20 | runs-on: windows-latest |
21 | env: | 21 | env: |
22 | RA_TARGET: x86_64-pc-windows-msvc | 22 | RA_TARGET: x86_64-pc-windows-msvc |
@@ -45,11 +45,41 @@ jobs: | |||
45 | - name: Upload artifacts | 45 | - name: Upload artifacts |
46 | uses: actions/upload-artifact@v1 | 46 | uses: actions/upload-artifact@v1 |
47 | with: | 47 | with: |
48 | name: dist-windows-latest | 48 | name: dist-x86_64-pc-windows-msvc |
49 | path: ./dist | 49 | path: ./dist |
50 | 50 | ||
51 | dist-ubuntu: | 51 | dist-aarch64-pc-windows-msvc: |
52 | name: dist (Ubuntu 16.04) | 52 | name: dist (aarch64-pc-windows-msvc) |
53 | runs-on: windows-latest | ||
54 | env: | ||
55 | RA_TARGET: aarch64-pc-windows-msvc | ||
56 | |||
57 | steps: | ||
58 | - name: Checkout repository | ||
59 | uses: actions/checkout@v2 | ||
60 | |||
61 | - name: Rename existing rust toolchain | ||
62 | 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 | ||
63 | |||
64 | - name: Install Rust toolchain | ||
65 | uses: actions-rs/toolchain@v1 | ||
66 | with: | ||
67 | toolchain: stable | ||
68 | target: aarch64-pc-windows-msvc | ||
69 | profile: minimal | ||
70 | override: true | ||
71 | |||
72 | - name: Dist | ||
73 | run: cargo xtask dist | ||
74 | |||
75 | - name: Upload artifacts | ||
76 | uses: actions/upload-artifact@v1 | ||
77 | with: | ||
78 | name: dist-aarch64-pc-windows-msvc | ||
79 | path: ./dist | ||
80 | |||
81 | dist-x86_64-unknown-linux-gnu: | ||
82 | name: dist (x86_64-unknown-linux-gnu) | ||
53 | runs-on: ubuntu-16.04 | 83 | runs-on: ubuntu-16.04 |
54 | env: | 84 | env: |
55 | RA_TARGET: x86_64-unknown-linux-gnu | 85 | RA_TARGET: x86_64-unknown-linux-gnu |
@@ -85,11 +115,11 @@ jobs: | |||
85 | - name: Upload artifacts | 115 | - name: Upload artifacts |
86 | uses: actions/upload-artifact@v1 | 116 | uses: actions/upload-artifact@v1 |
87 | with: | 117 | with: |
88 | name: dist-ubuntu-16.04 | 118 | name: dist-x86_64-unknown-linux-gnu |
89 | path: ./dist | 119 | path: ./dist |
90 | 120 | ||
91 | dist-macos-latest: | 121 | dist-x86_64-apple-darwin: |
92 | name: dist (MacOS latest) | 122 | name: dist (x86_64-apple-darwin) |
93 | runs-on: macos-latest | 123 | runs-on: macos-latest |
94 | env: | 124 | env: |
95 | RA_TARGET: x86_64-apple-darwin | 125 | RA_TARGET: x86_64-apple-darwin |
@@ -111,12 +141,12 @@ jobs: | |||
111 | - name: Upload artifacts | 141 | - name: Upload artifacts |
112 | uses: actions/upload-artifact@v1 | 142 | uses: actions/upload-artifact@v1 |
113 | with: | 143 | with: |
114 | name: dist-macos-latest | 144 | name: dist-x86_64-apple-darwin |
115 | path: ./dist | 145 | path: ./dist |
116 | 146 | ||
117 | dist-macos-11: | 147 | dist-aarch64-apple-darwin: |
118 | name: dist (MacOS 11.0) | 148 | name: dist (aarch64-apple-darwin) |
119 | runs-on: macos-11.0 | 149 | runs-on: macos-latest |
120 | env: | 150 | env: |
121 | RA_TARGET: aarch64-apple-darwin | 151 | RA_TARGET: aarch64-apple-darwin |
122 | 152 | ||
@@ -133,18 +163,18 @@ jobs: | |||
133 | override: true | 163 | override: true |
134 | 164 | ||
135 | - name: Dist | 165 | - name: Dist |
136 | run: cargo xtask dist | 166 | run: SDKROOT=$(xcrun -sdk macosx11.0 --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx11.0 --show-sdk-platform-version) cargo xtask dist |
137 | 167 | ||
138 | - name: Upload artifacts | 168 | - name: Upload artifacts |
139 | uses: actions/upload-artifact@v1 | 169 | uses: actions/upload-artifact@v1 |
140 | with: | 170 | with: |
141 | name: dist-macos-11.0 | 171 | name: dist-aarch64-apple-darwin |
142 | path: ./dist | 172 | path: ./dist |
143 | 173 | ||
144 | publish: | 174 | publish: |
145 | name: publish | 175 | name: publish |
146 | runs-on: ubuntu-16.04 | 176 | runs-on: ubuntu-16.04 |
147 | needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11'] | 177 | needs: ['dist-x86_64-pc-windows-msvc', 'dist-aarch64-pc-windows-msvc', 'dist-x86_64-unknown-linux-gnu', 'dist-x86_64-apple-darwin', 'dist-aarch64-apple-darwin'] |
148 | steps: | 178 | steps: |
149 | - name: Install Nodejs | 179 | - name: Install Nodejs |
150 | uses: actions/setup-node@v1 | 180 | uses: actions/setup-node@v1 |
@@ -165,19 +195,23 @@ jobs: | |||
165 | 195 | ||
166 | - uses: actions/download-artifact@v1 | 196 | - uses: actions/download-artifact@v1 |
167 | with: | 197 | with: |
168 | name: dist-macos-11.0 | 198 | name: dist-aarch64-apple-darwin |
199 | path: dist | ||
200 | - uses: actions/download-artifact@v1 | ||
201 | with: | ||
202 | name: dist-x86_64-apple-darwin | ||
169 | path: dist | 203 | path: dist |
170 | - uses: actions/download-artifact@v1 | 204 | - uses: actions/download-artifact@v1 |
171 | with: | 205 | with: |
172 | name: dist-macos-latest | 206 | name: dist-x86_64-unknown-linux-gnu |
173 | path: dist | 207 | path: dist |
174 | - uses: actions/download-artifact@v1 | 208 | - uses: actions/download-artifact@v1 |
175 | with: | 209 | with: |
176 | name: dist-ubuntu-16.04 | 210 | name: dist-x86_64-pc-windows-msvc |
177 | path: dist | 211 | path: dist |
178 | - uses: actions/download-artifact@v1 | 212 | - uses: actions/download-artifact@v1 |
179 | with: | 213 | with: |
180 | name: dist-windows-latest | 214 | name: dist-aarch64-pc-windows-msvc |
181 | path: dist | 215 | path: dist |
182 | - run: ls -al ./dist | 216 | - run: ls -al ./dist |
183 | 217 | ||
diff --git a/Cargo.lock b/Cargo.lock index 4aaee3ab1..f87c590a4 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -2,9 +2,9 @@ | |||
2 | # It is not intended for manual editing. | 2 | # It is not intended for manual editing. |
3 | [[package]] | 3 | [[package]] |
4 | name = "addr2line" | 4 | name = "addr2line" |
5 | version = "0.14.0" | 5 | version = "0.14.1" |
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | 6 | source = "registry+https://github.com/rust-lang/crates.io-index" |
7 | checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" | 7 | checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" |
8 | dependencies = [ | 8 | dependencies = [ |
9 | "gimli", | 9 | "gimli", |
10 | ] | 10 | ] |
@@ -132,7 +132,7 @@ version = "0.12.0" | |||
132 | source = "registry+https://github.com/rust-lang/crates.io-index" | 132 | source = "registry+https://github.com/rust-lang/crates.io-index" |
133 | checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" | 133 | checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" |
134 | dependencies = [ | 134 | dependencies = [ |
135 | "semver 0.11.0", | 135 | "semver", |
136 | "serde", | 136 | "serde", |
137 | "serde_json", | 137 | "serde_json", |
138 | ] | 138 | ] |
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | |||
168 | 168 | ||
169 | [[package]] | 169 | [[package]] |
170 | name = "chalk-derive" | 170 | name = "chalk-derive" |
171 | version = "0.45.0" | 171 | version = "0.47.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 = "ec7dacf94958d1a930b95d049d9443860859af59eadc77849392093eb577bcee" | 173 | checksum = "3f00f6342a387edc822002d36a381e117afcac9f744951ff75fbf4a218edea5c" |
174 | dependencies = [ | 174 | dependencies = [ |
175 | "proc-macro2", | 175 | "proc-macro2", |
176 | "quote", | 176 | "quote", |
@@ -180,9 +180,9 @@ dependencies = [ | |||
180 | 180 | ||
181 | [[package]] | 181 | [[package]] |
182 | name = "chalk-ir" | 182 | name = "chalk-ir" |
183 | version = "0.45.0" | 183 | version = "0.47.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 = "a1a5b38ede247def17da87f4badb62396a5753db6048e2011d3089d8b3796c67" | 185 | checksum = "c686e69913591ae753e5526e73cbee39db3d9b0a92cc9078ab780cabf1c70aa9" |
186 | dependencies = [ | 186 | dependencies = [ |
187 | "bitflags", | 187 | "bitflags", |
188 | "chalk-derive", | 188 | "chalk-derive", |
@@ -191,9 +191,9 @@ dependencies = [ | |||
191 | 191 | ||
192 | [[package]] | 192 | [[package]] |
193 | name = "chalk-recursive" | 193 | name = "chalk-recursive" |
194 | version = "0.45.0" | 194 | version = "0.47.0" |
195 | source = "registry+https://github.com/rust-lang/crates.io-index" | 195 | source = "registry+https://github.com/rust-lang/crates.io-index" |
196 | checksum = "7a18db146d7a023edc20ad094e8c2284451f7888719645004979617d1f17c041" | 196 | checksum = "310fdcac0340dab4163b766baa8067266e3b909108d1ac1b5246c033bde63975" |
197 | dependencies = [ | 197 | dependencies = [ |
198 | "chalk-derive", | 198 | "chalk-derive", |
199 | "chalk-ir", | 199 | "chalk-ir", |
@@ -204,9 +204,9 @@ dependencies = [ | |||
204 | 204 | ||
205 | [[package]] | 205 | [[package]] |
206 | name = "chalk-solve" | 206 | name = "chalk-solve" |
207 | version = "0.45.0" | 207 | version = "0.47.0" |
208 | source = "registry+https://github.com/rust-lang/crates.io-index" | 208 | source = "registry+https://github.com/rust-lang/crates.io-index" |
209 | checksum = "7f73e0de04a0f394e47ed8118e00541bcf681d7c3c2ef500fa743eb4cf3a4850" | 209 | checksum = "c3c3252116111c3548f1164ab8d98c67c49848b3bde10dd11b650fd023e91c72" |
210 | dependencies = [ | 210 | dependencies = [ |
211 | "chalk-derive", | 211 | "chalk-derive", |
212 | "chalk-ir", | 212 | "chalk-ir", |
@@ -488,19 +488,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
488 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" | 488 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" |
489 | 489 | ||
490 | [[package]] | 490 | [[package]] |
491 | name = "generator" | ||
492 | version = "0.6.23" | ||
493 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
494 | checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" | ||
495 | dependencies = [ | ||
496 | "cc", | ||
497 | "libc", | ||
498 | "log", | ||
499 | "rustc_version", | ||
500 | "winapi 0.3.9", | ||
501 | ] | ||
502 | |||
503 | [[package]] | ||
504 | name = "gimli" | 491 | name = "gimli" |
505 | version = "0.23.0" | 492 | version = "0.23.0" |
506 | source = "registry+https://github.com/rust-lang/crates.io-index" | 493 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -834,19 +821,6 @@ dependencies = [ | |||
834 | ] | 821 | ] |
835 | 822 | ||
836 | [[package]] | 823 | [[package]] |
837 | name = "loom" | ||
838 | version = "0.3.6" | ||
839 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
840 | checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" | ||
841 | dependencies = [ | ||
842 | "cfg-if 0.1.10", | ||
843 | "generator", | ||
844 | "scoped-tls", | ||
845 | "serde", | ||
846 | "serde_json", | ||
847 | ] | ||
848 | |||
849 | [[package]] | ||
850 | name = "lsp-server" | 824 | name = "lsp-server" |
851 | version = "0.5.0" | 825 | version = "0.5.0" |
852 | source = "registry+https://github.com/rust-lang/crates.io-index" | 826 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1394,9 +1368,9 @@ dependencies = [ | |||
1394 | 1368 | ||
1395 | [[package]] | 1369 | [[package]] |
1396 | name = "rustc-ap-rustc_lexer" | 1370 | name = "rustc-ap-rustc_lexer" |
1397 | version = "695.0.0" | 1371 | version = "697.0.0" |
1398 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1399 | checksum = "390bad134705b0bff02cd9541ac66df751a91c3cc734c3369cd6151ca269caed" | 1373 | checksum = "67adbe260a0a11910624d6d28c0304fcf7b063e666682111005c83b09f73429d" |
1400 | dependencies = [ | 1374 | dependencies = [ |
1401 | "unicode-xid", | 1375 | "unicode-xid", |
1402 | ] | 1376 | ] |
@@ -1414,15 +1388,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1414 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | 1388 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" |
1415 | 1389 | ||
1416 | [[package]] | 1390 | [[package]] |
1417 | name = "rustc_version" | ||
1418 | version = "0.2.3" | ||
1419 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1420 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" | ||
1421 | dependencies = [ | ||
1422 | "semver 0.9.0", | ||
1423 | ] | ||
1424 | |||
1425 | [[package]] | ||
1426 | name = "ryu" | 1391 | name = "ryu" |
1427 | version = "1.0.5" | 1392 | version = "1.0.5" |
1428 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1480,31 +1445,16 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | |||
1480 | 1445 | ||
1481 | [[package]] | 1446 | [[package]] |
1482 | name = "semver" | 1447 | name = "semver" |
1483 | version = "0.9.0" | ||
1484 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1485 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" | ||
1486 | dependencies = [ | ||
1487 | "semver-parser 0.7.0", | ||
1488 | ] | ||
1489 | |||
1490 | [[package]] | ||
1491 | name = "semver" | ||
1492 | version = "0.11.0" | 1448 | version = "0.11.0" |
1493 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1494 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" | 1450 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" |
1495 | dependencies = [ | 1451 | dependencies = [ |
1496 | "semver-parser 0.10.1", | 1452 | "semver-parser", |
1497 | "serde", | 1453 | "serde", |
1498 | ] | 1454 | ] |
1499 | 1455 | ||
1500 | [[package]] | 1456 | [[package]] |
1501 | name = "semver-parser" | 1457 | name = "semver-parser" |
1502 | version = "0.7.0" | ||
1503 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1504 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | ||
1505 | |||
1506 | [[package]] | ||
1507 | name = "semver-parser" | ||
1508 | version = "0.10.1" | 1458 | version = "0.10.1" |
1509 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1510 | checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" | 1460 | checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" |
@@ -1566,12 +1516,11 @@ dependencies = [ | |||
1566 | 1516 | ||
1567 | [[package]] | 1517 | [[package]] |
1568 | name = "sharded-slab" | 1518 | name = "sharded-slab" |
1569 | version = "0.1.0" | 1519 | version = "0.1.1" |
1570 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1571 | checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" | 1521 | checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" |
1572 | dependencies = [ | 1522 | dependencies = [ |
1573 | "lazy_static", | 1523 | "lazy_static", |
1574 | "loom", | ||
1575 | ] | 1524 | ] |
1576 | 1525 | ||
1577 | [[package]] | 1526 | [[package]] |
@@ -1582,9 +1531,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | |||
1582 | 1531 | ||
1583 | [[package]] | 1532 | [[package]] |
1584 | name = "smallvec" | 1533 | name = "smallvec" |
1585 | version = "1.5.1" | 1534 | version = "1.6.0" |
1586 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1587 | checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" | 1536 | checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" |
1588 | 1537 | ||
1589 | [[package]] | 1538 | [[package]] |
1590 | name = "smol_str" | 1539 | name = "smol_str" |
@@ -1615,9 +1564,9 @@ version = "0.0.0" | |||
1615 | 1564 | ||
1616 | [[package]] | 1565 | [[package]] |
1617 | name = "syn" | 1566 | name = "syn" |
1618 | version = "1.0.56" | 1567 | version = "1.0.57" |
1619 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1620 | checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" | 1569 | checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6" |
1621 | dependencies = [ | 1570 | dependencies = [ |
1622 | "proc-macro2", | 1571 | "proc-macro2", |
1623 | "quote", | 1572 | "quote", |
@@ -1826,15 +1775,16 @@ dependencies = [ | |||
1826 | 1775 | ||
1827 | [[package]] | 1776 | [[package]] |
1828 | name = "tracing-tree" | 1777 | name = "tracing-tree" |
1829 | version = "0.1.6" | 1778 | version = "0.1.7" |
1830 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1831 | checksum = "43aac8afb493b08e1e1904956f7407c1e671b9c83b26a17e1bd83d6a3520e350" | 1780 | checksum = "023e80cdb7c8468b7aade1d756afa2acbe2ae0a6142a25ec664b5239d6ef2794" |
1832 | dependencies = [ | 1781 | dependencies = [ |
1833 | "ansi_term", | 1782 | "ansi_term", |
1834 | "atty", | 1783 | "atty", |
1835 | "chrono", | 1784 | "chrono", |
1836 | "termcolor", | 1785 | "termcolor", |
1837 | "tracing", | 1786 | "tracing", |
1787 | "tracing-log", | ||
1838 | "tracing-subscriber", | 1788 | "tracing-subscriber", |
1839 | ] | 1789 | ] |
1840 | 1790 | ||
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/pull_assignment_up.rs index ae99598c0..560d93e10 100644 --- a/crates/assists/src/handlers/extract_assignment.rs +++ b/crates/assists/src/handlers/pull_assignment_up.rs | |||
@@ -9,9 +9,9 @@ use crate::{ | |||
9 | AssistId, AssistKind, | 9 | AssistId, AssistKind, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | // Assist: extract_assignment | 12 | // Assist: pull_assignment_up |
13 | // | 13 | // |
14 | // Extracts variable assigment to outside an if or match statement. | 14 | // Extracts variable assignment to outside an if or match statement. |
15 | // | 15 | // |
16 | // ``` | 16 | // ``` |
17 | // fn main() { | 17 | // fn main() { |
@@ -36,7 +36,7 @@ use crate::{ | |||
36 | // }; | 36 | // }; |
37 | // } | 37 | // } |
38 | // ``` | 38 | // ``` |
39 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | 40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; |
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | 41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { |
42 | assign_expr.lhs()? | 42 | assign_expr.lhs()? |
@@ -61,8 +61,8 @@ pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
61 | let expr_stmt = make::expr_stmt(new_stmt); | 61 | let expr_stmt = make::expr_stmt(new_stmt); |
62 | 62 | ||
63 | acc.add( | 63 | acc.add( |
64 | AssistId("extract_assignment", AssistKind::RefactorExtract), | 64 | AssistId("pull_assignment_up", AssistKind::RefactorExtract), |
65 | "Extract assignment", | 65 | "Pull assignment up", |
66 | old_stmt.syntax().text_range(), | 66 | old_stmt.syntax().text_range(), |
67 | move |edit| { | 67 | move |edit| { |
68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); | 68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); |
@@ -104,7 +104,7 @@ fn exprify_if( | |||
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | 104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) |
105 | } | 105 | } |
106 | ast::ElseBranch::IfExpr(expr) => { | 106 | ast::ElseBranch::IfExpr(expr) => { |
107 | mark::hit!(test_extract_assigment_chained_if); | 107 | mark::hit!(test_pull_assignment_up_chained_if); |
108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | 108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( |
109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), | 109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), |
110 | )?) | 110 | )?) |
@@ -144,7 +144,7 @@ fn is_equivalent( | |||
144 | ) -> bool { | 144 | ) -> bool { |
145 | match (expr0, expr1) { | 145 | match (expr0, expr1) { |
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | 146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { |
147 | mark::hit!(test_extract_assignment_field_assignment); | 147 | mark::hit!(test_pull_assignment_up_field_assignment); |
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | 148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) |
149 | } | 149 | } |
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | 150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { |
@@ -167,9 +167,9 @@ mod tests { | |||
167 | use crate::tests::{check_assist, check_assist_not_applicable}; | 167 | use crate::tests::{check_assist, check_assist_not_applicable}; |
168 | 168 | ||
169 | #[test] | 169 | #[test] |
170 | fn test_extract_assignment_if() { | 170 | fn test_pull_assignment_up_if() { |
171 | check_assist( | 171 | check_assist( |
172 | extract_assigment, | 172 | pull_assignment_up, |
173 | r#" | 173 | r#" |
174 | fn foo() { | 174 | fn foo() { |
175 | let mut a = 1; | 175 | let mut a = 1; |
@@ -194,9 +194,9 @@ fn foo() { | |||
194 | } | 194 | } |
195 | 195 | ||
196 | #[test] | 196 | #[test] |
197 | fn test_extract_assignment_match() { | 197 | fn test_pull_assignment_up_match() { |
198 | check_assist( | 198 | check_assist( |
199 | extract_assigment, | 199 | pull_assignment_up, |
200 | r#" | 200 | r#" |
201 | fn foo() { | 201 | fn foo() { |
202 | let mut a = 1; | 202 | let mut a = 1; |
@@ -233,9 +233,9 @@ fn foo() { | |||
233 | } | 233 | } |
234 | 234 | ||
235 | #[test] | 235 | #[test] |
236 | fn test_extract_assignment_not_last_not_applicable() { | 236 | fn test_pull_assignment_up_not_last_not_applicable() { |
237 | check_assist_not_applicable( | 237 | check_assist_not_applicable( |
238 | extract_assigment, | 238 | pull_assignment_up, |
239 | r#" | 239 | r#" |
240 | fn foo() { | 240 | fn foo() { |
241 | let mut a = 1; | 241 | let mut a = 1; |
@@ -251,10 +251,10 @@ fn foo() { | |||
251 | } | 251 | } |
252 | 252 | ||
253 | #[test] | 253 | #[test] |
254 | fn test_extract_assignment_chained_if() { | 254 | fn test_pull_assignment_up_chained_if() { |
255 | mark::check!(test_extract_assigment_chained_if); | 255 | mark::check!(test_pull_assignment_up_chained_if); |
256 | check_assist( | 256 | check_assist( |
257 | extract_assigment, | 257 | pull_assignment_up, |
258 | r#" | 258 | r#" |
259 | fn foo() { | 259 | fn foo() { |
260 | let mut a = 1; | 260 | let mut a = 1; |
@@ -283,9 +283,9 @@ fn foo() { | |||
283 | } | 283 | } |
284 | 284 | ||
285 | #[test] | 285 | #[test] |
286 | fn test_extract_assigment_retains_stmts() { | 286 | fn test_pull_assignment_up_retains_stmts() { |
287 | check_assist( | 287 | check_assist( |
288 | extract_assigment, | 288 | pull_assignment_up, |
289 | r#" | 289 | r#" |
290 | fn foo() { | 290 | fn foo() { |
291 | let mut a = 1; | 291 | let mut a = 1; |
@@ -314,9 +314,9 @@ fn foo() { | |||
314 | } | 314 | } |
315 | 315 | ||
316 | #[test] | 316 | #[test] |
317 | fn extract_assignment_let_stmt_not_applicable() { | 317 | fn pull_assignment_up_let_stmt_not_applicable() { |
318 | check_assist_not_applicable( | 318 | check_assist_not_applicable( |
319 | extract_assigment, | 319 | pull_assignment_up, |
320 | r#" | 320 | r#" |
321 | fn foo() { | 321 | fn foo() { |
322 | let mut a = 1; | 322 | let mut a = 1; |
@@ -331,9 +331,9 @@ fn foo() { | |||
331 | } | 331 | } |
332 | 332 | ||
333 | #[test] | 333 | #[test] |
334 | fn extract_assignment_if_missing_assigment_not_applicable() { | 334 | fn pull_assignment_up_if_missing_assigment_not_applicable() { |
335 | check_assist_not_applicable( | 335 | check_assist_not_applicable( |
336 | extract_assigment, | 336 | pull_assignment_up, |
337 | r#" | 337 | r#" |
338 | fn foo() { | 338 | fn foo() { |
339 | let mut a = 1; | 339 | let mut a = 1; |
@@ -346,9 +346,9 @@ fn foo() { | |||
346 | } | 346 | } |
347 | 347 | ||
348 | #[test] | 348 | #[test] |
349 | fn extract_assignment_match_missing_assigment_not_applicable() { | 349 | fn pull_assignment_up_match_missing_assigment_not_applicable() { |
350 | check_assist_not_applicable( | 350 | check_assist_not_applicable( |
351 | extract_assigment, | 351 | pull_assignment_up, |
352 | r#" | 352 | r#" |
353 | fn foo() { | 353 | fn foo() { |
354 | let mut a = 1; | 354 | let mut a = 1; |
@@ -367,10 +367,10 @@ fn foo() { | |||
367 | } | 367 | } |
368 | 368 | ||
369 | #[test] | 369 | #[test] |
370 | fn test_extract_assignment_field_assignment() { | 370 | fn test_pull_assignment_up_field_assignment() { |
371 | mark::check!(test_extract_assignment_field_assignment); | 371 | mark::check!(test_pull_assignment_up_field_assignment); |
372 | check_assist( | 372 | check_assist( |
373 | extract_assigment, | 373 | pull_assignment_up, |
374 | r#" | 374 | r#" |
375 | struct A(usize); | 375 | struct A(usize); |
376 | 376 | ||
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 212464f85..01baa65fe 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -116,7 +116,6 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_assignment; | ||
120 | mod extract_module_to_file; | 119 | mod extract_module_to_file; |
121 | mod extract_struct_from_enum_variant; | 120 | mod extract_struct_from_enum_variant; |
122 | mod extract_variable; | 121 | mod extract_variable; |
@@ -125,8 +124,8 @@ mod handlers { | |||
125 | mod flip_binexpr; | 124 | mod flip_binexpr; |
126 | mod flip_comma; | 125 | mod flip_comma; |
127 | mod flip_trait_bound; | 126 | mod flip_trait_bound; |
128 | mod generate_derive; | ||
129 | mod generate_default_from_enum_variant; | 127 | mod generate_default_from_enum_variant; |
128 | mod generate_derive; | ||
130 | mod generate_from_impl_for_enum; | 129 | mod generate_from_impl_for_enum; |
131 | mod generate_function; | 130 | mod generate_function; |
132 | mod generate_impl; | 131 | mod generate_impl; |
@@ -139,6 +138,7 @@ mod handlers { | |||
139 | mod merge_match_arms; | 138 | mod merge_match_arms; |
140 | mod move_bounds; | 139 | mod move_bounds; |
141 | mod move_guard; | 140 | mod move_guard; |
141 | mod pull_assignment_up; | ||
142 | mod qualify_path; | 142 | mod qualify_path; |
143 | mod raw_string; | 143 | mod raw_string; |
144 | mod remove_dbg; | 144 | mod remove_dbg; |
@@ -168,7 +168,6 @@ mod handlers { | |||
168 | convert_integer_literal::convert_integer_literal, | 168 | convert_integer_literal::convert_integer_literal, |
169 | early_return::convert_to_guarded_return, | 169 | early_return::convert_to_guarded_return, |
170 | expand_glob_import::expand_glob_import, | 170 | expand_glob_import::expand_glob_import, |
171 | extract_assignment::extract_assigment, | ||
172 | extract_module_to_file::extract_module_to_file, | 171 | extract_module_to_file::extract_module_to_file, |
173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 172 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
174 | extract_variable::extract_variable, | 173 | extract_variable::extract_variable, |
@@ -177,8 +176,8 @@ mod handlers { | |||
177 | flip_binexpr::flip_binexpr, | 176 | flip_binexpr::flip_binexpr, |
178 | flip_comma::flip_comma, | 177 | flip_comma::flip_comma, |
179 | flip_trait_bound::flip_trait_bound, | 178 | flip_trait_bound::flip_trait_bound, |
180 | generate_derive::generate_derive, | ||
181 | generate_default_from_enum_variant::generate_default_from_enum_variant, | 179 | generate_default_from_enum_variant::generate_default_from_enum_variant, |
180 | generate_derive::generate_derive, | ||
182 | generate_from_impl_for_enum::generate_from_impl_for_enum, | 181 | generate_from_impl_for_enum::generate_from_impl_for_enum, |
183 | generate_function::generate_function, | 182 | generate_function::generate_function, |
184 | generate_impl::generate_impl, | 183 | generate_impl::generate_impl, |
@@ -192,6 +191,7 @@ mod handlers { | |||
192 | move_bounds::move_bounds_to_where_clause, | 191 | move_bounds::move_bounds_to_where_clause, |
193 | move_guard::move_arm_cond_to_match_guard, | 192 | move_guard::move_arm_cond_to_match_guard, |
194 | move_guard::move_guard_to_arm_body, | 193 | move_guard::move_guard_to_arm_body, |
194 | pull_assignment_up::pull_assignment_up, | ||
195 | qualify_path::qualify_path, | 195 | qualify_path::qualify_path, |
196 | raw_string::add_hash, | 196 | raw_string::add_hash, |
197 | raw_string::make_usual_string, | 197 | raw_string::make_usual_string, |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index b91a816e8..85e3c6742 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -238,35 +238,6 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn main() { | ||
257 | let mut foo = 6; | ||
258 | |||
259 | foo = if true { | ||
260 | 5 | ||
261 | } else { | ||
262 | 4 | ||
263 | }; | ||
264 | } | ||
265 | "#####, | ||
266 | ) | ||
267 | } | ||
268 | |||
269 | #[test] | ||
270 | fn doctest_extract_module_to_file() { | 241 | fn doctest_extract_module_to_file() { |
271 | check_doc_test( | 242 | check_doc_test( |
272 | "extract_module_to_file", | 243 | "extract_module_to_file", |
@@ -767,6 +738,35 @@ fn handle(action: Action) { | |||
767 | } | 738 | } |
768 | 739 | ||
769 | #[test] | 740 | #[test] |
741 | fn doctest_pull_assignment_up() { | ||
742 | check_doc_test( | ||
743 | "pull_assignment_up", | ||
744 | r#####" | ||
745 | fn main() { | ||
746 | let mut foo = 6; | ||
747 | |||
748 | if true { | ||
749 | <|>foo = 5; | ||
750 | } else { | ||
751 | foo = 4; | ||
752 | } | ||
753 | } | ||
754 | "#####, | ||
755 | r#####" | ||
756 | fn main() { | ||
757 | let mut foo = 6; | ||
758 | |||
759 | foo = if true { | ||
760 | 5 | ||
761 | } else { | ||
762 | 4 | ||
763 | }; | ||
764 | } | ||
765 | "#####, | ||
766 | ) | ||
767 | } | ||
768 | |||
769 | #[test] | ||
770 | fn doctest_qualify_path() { | 770 | fn doctest_qualify_path() { |
771 | check_doc_test( | 771 | check_doc_test( |
772 | "qualify_path", | 772 | "qualify_path", |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 62eccf475..1a4aa78fb 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -5,9 +5,7 @@ use arrayvec::ArrayVec; | |||
5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | adt::ReprKind, | 8 | adt::{ReprKind, StructKind, VariantData}, |
9 | adt::StructKind, | ||
10 | adt::VariantData, | ||
11 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
12 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 10 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
13 | import_map, | 11 | import_map, |
@@ -31,7 +29,7 @@ use hir_expand::{ | |||
31 | }; | 29 | }; |
32 | use hir_ty::{ | 30 | use hir_ty::{ |
33 | autoderef, | 31 | autoderef, |
34 | display::{HirDisplayError, HirFormatter}, | 32 | display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, |
35 | method_resolution, | 33 | method_resolution, |
36 | traits::{FnTrait, Solution, SolutionVariables}, | 34 | traits::{FnTrait, Solution, SolutionVariables}, |
37 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, | 35 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, |
@@ -745,6 +743,18 @@ impl Function { | |||
745 | db.function_data(self.id).name.clone() | 743 | db.function_data(self.id).name.clone() |
746 | } | 744 | } |
747 | 745 | ||
746 | /// Get this function's return type | ||
747 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
748 | let resolver = self.id.resolver(db.upcast()); | ||
749 | let ret_type = &db.function_data(self.id).ret_type; | ||
750 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
751 | let environment = TraitEnvironment::lower(db, &resolver); | ||
752 | Type { | ||
753 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, | ||
754 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
755 | } | ||
756 | } | ||
757 | |||
748 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | 758 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { |
749 | if !db.function_data(self.id).has_self_param { | 759 | if !db.function_data(self.id).has_self_param { |
750 | return None; | 760 | return None; |
@@ -1278,6 +1288,18 @@ impl TypeParam { | |||
1278 | } | 1288 | } |
1279 | } | 1289 | } |
1280 | 1290 | ||
1291 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1292 | db.generic_predicates_for_param(self.id) | ||
1293 | .into_iter() | ||
1294 | .filter_map(|pred| match &pred.value { | ||
1295 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1296 | Some(Trait::from(trait_ref.trait_)) | ||
1297 | } | ||
1298 | _ => None, | ||
1299 | }) | ||
1300 | .collect() | ||
1301 | } | ||
1302 | |||
1281 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | 1303 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { |
1282 | let params = db.generic_defaults(self.id.parent); | 1304 | let params = db.generic_defaults(self.id.parent); |
1283 | let local_idx = hir_ty::param_idx(db, self.id)?; | 1305 | let local_idx = hir_ty::param_idx(db, self.id)?; |
@@ -1293,6 +1315,20 @@ impl TypeParam { | |||
1293 | } | 1315 | } |
1294 | } | 1316 | } |
1295 | 1317 | ||
1318 | impl HirDisplay for TypeParam { | ||
1319 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1320 | write!(f, "{}", self.name(f.db))?; | ||
1321 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1322 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1323 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1324 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1325 | write!(f, ": ")?; | ||
1326 | write_bounds_like_dyn_trait(&predicates, f)?; | ||
1327 | } | ||
1328 | Ok(()) | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1296 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1332 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1297 | pub struct LifetimeParam { | 1333 | pub struct LifetimeParam { |
1298 | pub(crate) id: LifetimeParamId, | 1334 | pub(crate) id: LifetimeParamId, |
@@ -1331,6 +1367,12 @@ impl ConstParam { | |||
1331 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | 1367 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { |
1332 | self.id.parent.into() | 1368 | self.id.parent.into() |
1333 | } | 1369 | } |
1370 | |||
1371 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1372 | let def = self.id.parent; | ||
1373 | let krate = def.module(db.upcast()).krate; | ||
1374 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1375 | } | ||
1334 | } | 1376 | } |
1335 | 1377 | ||
1336 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1378 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 7c77f6ce0..1923daca5 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -58,7 +58,7 @@ impl ProcMacroExpander { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | 60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { |
61 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() { | 61 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() { |
62 | if punct.char == c { | 62 | if punct.char == c { |
63 | *cursor = cursor.bump(); | 63 | *cursor = cursor.bump(); |
64 | return true; | 64 | return true; |
@@ -68,7 +68,7 @@ fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | 70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { |
71 | if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() { | 71 | if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() { |
72 | if Some(kind) == subtree.delimiter_kind() { | 72 | if Some(kind) == subtree.delimiter_kind() { |
73 | *cursor = cursor.bump_subtree(); | 73 | *cursor = cursor.bump_subtree(); |
74 | return true; | 74 | return true; |
@@ -78,7 +78,7 @@ fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | 80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { |
81 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() { | 81 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() { |
82 | if t == ident.text.as_str() { | 82 | if t == ident.text.as_str() { |
83 | *cursor = cursor.bump(); | 83 | *cursor = cursor.bump(); |
84 | return true; | 84 | return true; |
@@ -88,7 +88,7 @@ fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | |||
88 | } | 88 | } |
89 | 89 | ||
90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | 90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { |
91 | let buffer = TokenBuffer::new(&tt.token_trees); | 91 | let buffer = TokenBuffer::from_tokens(&tt.token_trees); |
92 | let mut p = buffer.begin(); | 92 | let mut p = buffer.begin(); |
93 | let mut result = tt::Subtree::default(); | 93 | let mut result = tt::Subtree::default(); |
94 | 94 | ||
@@ -106,7 +106,7 @@ fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | result.token_trees.push(curr.token_tree()?.clone()); | 109 | result.token_trees.push(curr.token_tree()?.cloned()); |
110 | p = curr.bump(); | 110 | p = curr.bump(); |
111 | } | 111 | } |
112 | 112 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 3d1778590..b0a453961 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.45", default-features = false } | 20 | chalk-solve = { version = "0.47", default-features = false } |
21 | chalk-ir = "0.45" | 21 | chalk-ir = "0.47" |
22 | chalk-recursive = "0.45" | 22 | chalk-recursive = "0.47" |
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/display.rs b/crates/hir_ty/src/display.rs index 0e827a29e..a54225c18 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -595,7 +595,7 @@ impl HirDisplay for FnSig { | |||
595 | } | 595 | } |
596 | } | 596 | } |
597 | 597 | ||
598 | fn write_bounds_like_dyn_trait( | 598 | pub fn write_bounds_like_dyn_trait( |
599 | predicates: &[GenericPredicate], | 599 | predicates: &[GenericPredicate], |
600 | f: &mut HirFormatter, | 600 | f: &mut HirFormatter, |
601 | ) -> Result<(), HirDisplayError> { | 601 | ) -> Result<(), HirDisplayError> { |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index ea49d9f97..990f740b8 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -87,6 +87,17 @@ impl ShortLabel for ast::Variant { | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | impl ShortLabel for ast::ConstParam { | ||
91 | fn short_label(&self) -> Option<String> { | ||
92 | let mut buf = "const ".to_owned(); | ||
93 | buf.push_str(self.name()?.text().as_str()); | ||
94 | if let Some(type_ref) = self.ty() { | ||
95 | format_to!(buf, ": {}", type_ref.syntax()); | ||
96 | } | ||
97 | Some(buf) | ||
98 | } | ||
99 | } | ||
100 | |||
90 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> | 101 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> |
91 | where | 102 | where |
92 | T: NameOwner + VisibilityOwner, | 103 | T: NameOwner + VisibilityOwner, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2737c900f..f2ad95cb6 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -70,7 +70,7 @@ impl HoverConfig { | |||
70 | #[derive(Debug, Clone)] | 70 | #[derive(Debug, Clone)] |
71 | pub enum HoverAction { | 71 | pub enum HoverAction { |
72 | Runnable(Runnable), | 72 | Runnable(Runnable), |
73 | Implementaion(FilePosition), | 73 | Implementation(FilePosition), |
74 | GoToType(Vec<HoverGotoTypeData>), | 74 | GoToType(Vec<HoverGotoTypeData>), |
75 | } | 75 | } |
76 | 76 | ||
@@ -116,12 +116,13 @@ pub(crate) fn hover( | |||
116 | }; | 116 | }; |
117 | if let Some(definition) = definition { | 117 | if let Some(definition) = definition { |
118 | if let Some(markup) = hover_for_definition(db, definition) { | 118 | if let Some(markup) = hover_for_definition(db, definition) { |
119 | let markup = markup.as_str(); | ||
119 | let markup = if !markdown { | 120 | let markup = if !markdown { |
120 | remove_markdown(&markup.as_str()) | 121 | remove_markdown(markup) |
121 | } else if links_in_hover { | 122 | } else if links_in_hover { |
122 | rewrite_links(db, &markup.as_str(), &definition) | 123 | rewrite_links(db, markup, &definition) |
123 | } else { | 124 | } else { |
124 | remove_links(&markup.as_str()) | 125 | remove_links(markup) |
125 | }; | 126 | }; |
126 | res.markup = Markup::from(markup); | 127 | res.markup = Markup::from(markup); |
127 | if let Some(action) = show_implementations_action(db, definition) { | 128 | if let Some(action) = show_implementations_action(db, definition) { |
@@ -175,22 +176,24 @@ pub(crate) fn hover( | |||
175 | 176 | ||
176 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 177 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
177 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | 178 | fn to_action(nav_target: NavigationTarget) -> HoverAction { |
178 | HoverAction::Implementaion(FilePosition { | 179 | HoverAction::Implementation(FilePosition { |
179 | file_id: nav_target.file_id, | 180 | file_id: nav_target.file_id, |
180 | offset: nav_target.focus_or_full_range().start(), | 181 | offset: nav_target.focus_or_full_range().start(), |
181 | }) | 182 | }) |
182 | } | 183 | } |
183 | 184 | ||
184 | match def { | 185 | let adt = match def { |
185 | Definition::ModuleDef(it) => match it { | 186 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
186 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), | 187 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
187 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), | 188 | Definition::SelfType(it) => it.target_ty(db).as_adt(), |
188 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), | ||
189 | ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), | ||
190 | _ => None, | ||
191 | }, | ||
192 | _ => None, | 189 | _ => None, |
190 | }?; | ||
191 | match adt { | ||
192 | Adt::Struct(it) => it.try_to_nav(db), | ||
193 | Adt::Union(it) => it.try_to_nav(db), | ||
194 | Adt::Enum(it) => it.try_to_nav(db), | ||
193 | } | 195 | } |
196 | .map(to_action) | ||
194 | } | 197 | } |
195 | 198 | ||
196 | fn runnable_action( | 199 | fn runnable_action( |
@@ -225,45 +228,46 @@ fn runnable_action( | |||
225 | } | 228 | } |
226 | 229 | ||
227 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 230 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
228 | match def { | 231 | let mut targets: Vec<ModuleDef> = Vec::new(); |
229 | Definition::Local(it) => { | 232 | let mut push_new_def = |item: ModuleDef| { |
230 | let mut targets: Vec<ModuleDef> = Vec::new(); | 233 | if !targets.contains(&item) { |
231 | let mut push_new_def = |item: ModuleDef| { | 234 | targets.push(item); |
232 | if !targets.contains(&item) { | ||
233 | targets.push(item); | ||
234 | } | ||
235 | }; | ||
236 | |||
237 | it.ty(db).walk(db, |t| { | ||
238 | if let Some(adt) = t.as_adt() { | ||
239 | push_new_def(adt.into()); | ||
240 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
241 | push_new_def(trait_.into()); | ||
242 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
243 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
244 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
245 | push_new_def(trait_.into()); | ||
246 | } | ||
247 | }); | ||
248 | |||
249 | let targets = targets | ||
250 | .into_iter() | ||
251 | .filter_map(|it| { | ||
252 | Some(HoverGotoTypeData { | ||
253 | mod_path: render_path( | ||
254 | db, | ||
255 | it.module(db)?, | ||
256 | it.name(db).map(|name| name.to_string()), | ||
257 | ), | ||
258 | nav: it.try_to_nav(db)?, | ||
259 | }) | ||
260 | }) | ||
261 | .collect(); | ||
262 | |||
263 | Some(HoverAction::GoToType(targets)) | ||
264 | } | 235 | } |
265 | _ => None, | 236 | }; |
237 | |||
238 | if let Definition::TypeParam(it) = def { | ||
239 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | ||
240 | } else { | ||
241 | let ty = match def { | ||
242 | Definition::Local(it) => it.ty(db), | ||
243 | Definition::ConstParam(it) => it.ty(db), | ||
244 | _ => return None, | ||
245 | }; | ||
246 | |||
247 | ty.walk(db, |t| { | ||
248 | if let Some(adt) = t.as_adt() { | ||
249 | push_new_def(adt.into()); | ||
250 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
251 | push_new_def(trait_.into()); | ||
252 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
253 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
254 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
255 | push_new_def(trait_.into()); | ||
256 | } | ||
257 | }); | ||
266 | } | 258 | } |
259 | |||
260 | let targets = targets | ||
261 | .into_iter() | ||
262 | .filter_map(|it| { | ||
263 | Some(HoverGotoTypeData { | ||
264 | mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())), | ||
265 | nav: it.try_to_nav(db)?, | ||
266 | }) | ||
267 | }) | ||
268 | .collect(); | ||
269 | |||
270 | Some(HoverAction::GoToType(targets)) | ||
267 | } | 271 | } |
268 | 272 | ||
269 | fn hover_markup( | 273 | fn hover_markup( |
@@ -370,10 +374,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | } | 374 | } |
371 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 375 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
372 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | 376 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), |
373 | Definition::TypeParam(_) | Definition::ConstParam(_) => { | 377 | Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), |
374 | // FIXME: Hover for generic param | 378 | Definition::ConstParam(it) => from_def_source(db, it, None), |
375 | None | ||
376 | } | ||
377 | }; | 379 | }; |
378 | 380 | ||
379 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 381 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
@@ -1393,7 +1395,7 @@ fn bar() { fo<|>o(); } | |||
1393 | r"unsafe trait foo<|>() {}", | 1395 | r"unsafe trait foo<|>() {}", |
1394 | expect![[r#" | 1396 | expect![[r#" |
1395 | [ | 1397 | [ |
1396 | Implementaion( | 1398 | Implementation( |
1397 | FilePosition { | 1399 | FilePosition { |
1398 | file_id: FileId( | 1400 | file_id: FileId( |
1399 | 0, | 1401 | 0, |
@@ -2105,7 +2107,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2105 | r#"trait foo<|>() {}"#, | 2107 | r#"trait foo<|>() {}"#, |
2106 | expect![[r#" | 2108 | expect![[r#" |
2107 | [ | 2109 | [ |
2108 | Implementaion( | 2110 | Implementation( |
2109 | FilePosition { | 2111 | FilePosition { |
2110 | file_id: FileId( | 2112 | file_id: FileId( |
2111 | 0, | 2113 | 0, |
@@ -2124,7 +2126,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2124 | r"struct foo<|>() {}", | 2126 | r"struct foo<|>() {}", |
2125 | expect![[r#" | 2127 | expect![[r#" |
2126 | [ | 2128 | [ |
2127 | Implementaion( | 2129 | Implementation( |
2128 | FilePosition { | 2130 | FilePosition { |
2129 | file_id: FileId( | 2131 | file_id: FileId( |
2130 | 0, | 2132 | 0, |
@@ -2143,7 +2145,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2143 | r#"union foo<|>() {}"#, | 2145 | r#"union foo<|>() {}"#, |
2144 | expect![[r#" | 2146 | expect![[r#" |
2145 | [ | 2147 | [ |
2146 | Implementaion( | 2148 | Implementation( |
2147 | FilePosition { | 2149 | FilePosition { |
2148 | file_id: FileId( | 2150 | file_id: FileId( |
2149 | 0, | 2151 | 0, |
@@ -2162,7 +2164,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2162 | r"enum foo<|>() { A, B }", | 2164 | r"enum foo<|>() { A, B }", |
2163 | expect![[r#" | 2165 | expect![[r#" |
2164 | [ | 2166 | [ |
2165 | Implementaion( | 2167 | Implementation( |
2166 | FilePosition { | 2168 | FilePosition { |
2167 | file_id: FileId( | 2169 | file_id: FileId( |
2168 | 0, | 2170 | 0, |
@@ -2176,6 +2178,25 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2176 | } | 2178 | } |
2177 | 2179 | ||
2178 | #[test] | 2180 | #[test] |
2181 | fn test_hover_self_has_impl_action() { | ||
2182 | check_actions( | ||
2183 | r#"struct foo where Self<|>:;"#, | ||
2184 | expect![[r#" | ||
2185 | [ | ||
2186 | Implementation( | ||
2187 | FilePosition { | ||
2188 | file_id: FileId( | ||
2189 | 0, | ||
2190 | ), | ||
2191 | offset: 7, | ||
2192 | }, | ||
2193 | ), | ||
2194 | ] | ||
2195 | "#]], | ||
2196 | ); | ||
2197 | } | ||
2198 | |||
2199 | #[test] | ||
2179 | fn test_hover_test_has_action() { | 2200 | fn test_hover_test_has_action() { |
2180 | check_actions( | 2201 | check_actions( |
2181 | r#" | 2202 | r#" |
@@ -3064,6 +3085,71 @@ fn main() { let s<|>t = test().get(); } | |||
3064 | } | 3085 | } |
3065 | 3086 | ||
3066 | #[test] | 3087 | #[test] |
3088 | fn test_hover_const_param_has_goto_type_action() { | ||
3089 | check_actions( | ||
3090 | r#" | ||
3091 | struct Bar; | ||
3092 | struct Foo<const BAR: Bar>; | ||
3093 | |||
3094 | impl<const BAR: Bar> Foo<BAR<|>> {} | ||
3095 | "#, | ||
3096 | expect![[r#" | ||
3097 | [ | ||
3098 | GoToType( | ||
3099 | [ | ||
3100 | HoverGotoTypeData { | ||
3101 | mod_path: "test::Bar", | ||
3102 | nav: NavigationTarget { | ||
3103 | file_id: FileId( | ||
3104 | 0, | ||
3105 | ), | ||
3106 | full_range: 0..11, | ||
3107 | focus_range: 7..10, | ||
3108 | name: "Bar", | ||
3109 | kind: Struct, | ||
3110 | description: "struct Bar", | ||
3111 | }, | ||
3112 | }, | ||
3113 | ], | ||
3114 | ), | ||
3115 | ] | ||
3116 | "#]], | ||
3117 | ); | ||
3118 | } | ||
3119 | |||
3120 | #[test] | ||
3121 | fn test_hover_type_param_has_goto_type_action() { | ||
3122 | check_actions( | ||
3123 | r#" | ||
3124 | trait Foo {} | ||
3125 | |||
3126 | fn foo<T: Foo>(t: T<|>){} | ||
3127 | "#, | ||
3128 | expect![[r#" | ||
3129 | [ | ||
3130 | GoToType( | ||
3131 | [ | ||
3132 | HoverGotoTypeData { | ||
3133 | mod_path: "test::Foo", | ||
3134 | nav: NavigationTarget { | ||
3135 | file_id: FileId( | ||
3136 | 0, | ||
3137 | ), | ||
3138 | full_range: 0..12, | ||
3139 | focus_range: 6..9, | ||
3140 | name: "Foo", | ||
3141 | kind: Trait, | ||
3142 | description: "trait Foo", | ||
3143 | }, | ||
3144 | }, | ||
3145 | ], | ||
3146 | ), | ||
3147 | ] | ||
3148 | "#]], | ||
3149 | ); | ||
3150 | } | ||
3151 | |||
3152 | #[test] | ||
3067 | fn hover_displays_normalized_crate_names() { | 3153 | fn hover_displays_normalized_crate_names() { |
3068 | check( | 3154 | check( |
3069 | r#" | 3155 | r#" |
@@ -3257,4 +3343,68 @@ fn foo() { | |||
3257 | "#]], | 3343 | "#]], |
3258 | ); | 3344 | ); |
3259 | } | 3345 | } |
3346 | |||
3347 | #[test] | ||
3348 | fn hover_type_param() { | ||
3349 | check( | ||
3350 | r#" | ||
3351 | struct Foo<T>(T); | ||
3352 | trait Copy {} | ||
3353 | trait Clone {} | ||
3354 | trait Sized {} | ||
3355 | impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} | ||
3356 | "#, | ||
3357 | expect![[r#" | ||
3358 | *T* | ||
3359 | |||
3360 | ```rust | ||
3361 | T: Copy + Clone + Sized | ||
3362 | ``` | ||
3363 | "#]], | ||
3364 | ); | ||
3365 | check( | ||
3366 | r#" | ||
3367 | struct Foo<T>(T); | ||
3368 | impl<T> Foo<T<|>> {} | ||
3369 | "#, | ||
3370 | expect![[r#" | ||
3371 | *T* | ||
3372 | |||
3373 | ```rust | ||
3374 | T | ||
3375 | ``` | ||
3376 | "#]], | ||
3377 | ); | ||
3378 | // lifetimes aren't being substituted yet | ||
3379 | check( | ||
3380 | r#" | ||
3381 | struct Foo<T>(T); | ||
3382 | impl<T: 'static> Foo<T<|>> {} | ||
3383 | "#, | ||
3384 | expect![[r#" | ||
3385 | *T* | ||
3386 | |||
3387 | ```rust | ||
3388 | T: {error} | ||
3389 | ``` | ||
3390 | "#]], | ||
3391 | ); | ||
3392 | } | ||
3393 | |||
3394 | #[test] | ||
3395 | fn hover_const_param() { | ||
3396 | check( | ||
3397 | r#" | ||
3398 | struct Foo<const LEN: usize>; | ||
3399 | impl<const LEN: usize> Foo<LEN<|>> {} | ||
3400 | "#, | ||
3401 | expect![[r#" | ||
3402 | *LEN* | ||
3403 | |||
3404 | ```rust | ||
3405 | const LEN: usize | ||
3406 | ``` | ||
3407 | "#]], | ||
3408 | ); | ||
3409 | } | ||
3260 | } | 3410 | } |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index ab5f87c48..fdc8844ce 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -309,7 +309,7 @@ impl<'a> TtIter<'a> { | |||
309 | } | 309 | } |
310 | } | 310 | } |
311 | 311 | ||
312 | let buffer = TokenBuffer::new(&self.inner.as_slice()); | 312 | let buffer = TokenBuffer::from_tokens(&self.inner.as_slice()); |
313 | let mut src = SubtreeTokenSource::new(&buffer); | 313 | let mut src = SubtreeTokenSource::new(&buffer); |
314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | 314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; |
315 | 315 | ||
@@ -336,11 +336,11 @@ impl<'a> TtIter<'a> { | |||
336 | err = Some(err!("no tokens consumed")); | 336 | err = Some(err!("no tokens consumed")); |
337 | } | 337 | } |
338 | let res = match res.len() { | 338 | let res = match res.len() { |
339 | 1 => Some(res[0].clone()), | 339 | 1 => Some(res[0].cloned()), |
340 | 0 => None, | 340 | 0 => None, |
341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { | 341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { |
342 | delimiter: None, | 342 | delimiter: None, |
343 | token_trees: res.into_iter().cloned().collect(), | 343 | token_trees: res.into_iter().map(|it| it.cloned()).collect(), |
344 | })), | 344 | })), |
345 | }; | 345 | }; |
346 | ExpandResult { value: res, err } | 346 | ExpandResult { value: res, err } |
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs index d10d4b70e..d7433bd35 100644 --- a/crates/mbe/src/subtree_source.rs +++ b/crates/mbe/src/subtree_source.rs | |||
@@ -1,129 +1,104 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use parser::{Token, TokenSource}; | 3 | use parser::{Token, TokenSource}; |
4 | use std::cell::{Cell, Ref, RefCell}; | ||
5 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 5 | use tt::buffer::TokenBuffer; |
7 | 6 | ||
8 | #[derive(Debug, Clone, Eq, PartialEq)] | 7 | #[derive(Debug, Clone, Eq, PartialEq)] |
9 | struct TtToken { | 8 | struct TtToken { |
10 | kind: SyntaxKind, | 9 | tt: Token, |
11 | is_joint_to_next: bool, | ||
12 | text: SmolStr, | 10 | text: SmolStr, |
13 | } | 11 | } |
14 | 12 | ||
15 | pub(crate) struct SubtreeTokenSource<'a> { | 13 | pub(crate) struct SubtreeTokenSource { |
16 | cached_cursor: Cell<Cursor<'a>>, | 14 | cached: Vec<TtToken>, |
17 | cached: RefCell<Vec<Option<TtToken>>>, | ||
18 | curr: (Token, usize), | 15 | curr: (Token, usize), |
19 | } | 16 | } |
20 | 17 | ||
21 | impl<'a> SubtreeTokenSource<'a> { | 18 | impl<'a> SubtreeTokenSource { |
22 | // Helper function used in test | 19 | // Helper function used in test |
23 | #[cfg(test)] | 20 | #[cfg(test)] |
24 | pub(crate) fn text(&self) -> SmolStr { | 21 | pub(crate) fn text(&self) -> SmolStr { |
25 | match *self.get(self.curr.1) { | 22 | match self.cached.get(self.curr.1) { |
26 | Some(ref tt) => tt.text.clone(), | 23 | Some(ref tt) => tt.text.clone(), |
27 | _ => SmolStr::new(""), | 24 | _ => SmolStr::new(""), |
28 | } | 25 | } |
29 | } | 26 | } |
30 | } | 27 | } |
31 | 28 | ||
32 | impl<'a> SubtreeTokenSource<'a> { | 29 | impl<'a> SubtreeTokenSource { |
33 | pub(crate) fn new(buffer: &'a TokenBuffer) -> SubtreeTokenSource<'a> { | 30 | pub(crate) fn new(buffer: &TokenBuffer) -> SubtreeTokenSource { |
34 | let cursor = buffer.begin(); | 31 | let mut current = buffer.begin(); |
32 | let mut cached = Vec::with_capacity(100); | ||
35 | 33 | ||
36 | let mut res = SubtreeTokenSource { | 34 | while !current.eof() { |
37 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | 35 | let cursor = current; |
38 | cached_cursor: Cell::new(cursor), | 36 | let tt = cursor.token_tree(); |
39 | cached: RefCell::new(Vec::with_capacity(10)), | ||
40 | }; | ||
41 | res.curr = (res.mk_token(0), 0); | ||
42 | res | ||
43 | } | ||
44 | 37 | ||
45 | fn mk_token(&self, pos: usize) -> Token { | 38 | // Check if it is lifetime |
46 | match *self.get(pos) { | 39 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = tt { |
47 | Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next }, | ||
48 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
49 | } | ||
50 | } | ||
51 | |||
52 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { | ||
53 | fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> { | ||
54 | let tkn = c.token_tree(); | ||
55 | |||
56 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn { | ||
57 | if punct.char == '\'' { | 40 | if punct.char == '\'' { |
58 | let next = c.bump(); | 41 | let next = cursor.bump(); |
59 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() { | 42 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = |
60 | let res_cursor = next.bump(); | 43 | next.token_tree() |
61 | let text = SmolStr::new("'".to_string() + &ident.to_string()); | 44 | { |
62 | 45 | let text = SmolStr::new("'".to_string() + &ident.text); | |
63 | return Some((res_cursor, text)); | 46 | cached.push(TtToken { |
47 | tt: Token { kind: LIFETIME_IDENT, is_jointed_to_next: false }, | ||
48 | text, | ||
49 | }); | ||
50 | current = next.bump(); | ||
51 | continue; | ||
64 | } else { | 52 | } else { |
65 | panic!("Next token must be ident : {:#?}", next.token_tree()); | 53 | panic!("Next token must be ident : {:#?}", next.token_tree()); |
66 | } | 54 | } |
67 | } | 55 | } |
68 | } | 56 | } |
69 | 57 | ||
70 | None | 58 | current = match tt { |
71 | } | 59 | Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { |
72 | 60 | cached.push(convert_leaf(&leaf)); | |
73 | if pos < self.cached.borrow().len() { | 61 | cursor.bump() |
74 | return Ref::map(self.cached.borrow(), |c| &c[pos]); | ||
75 | } | ||
76 | |||
77 | { | ||
78 | let mut cached = self.cached.borrow_mut(); | ||
79 | while pos >= cached.len() { | ||
80 | let cursor = self.cached_cursor.get(); | ||
81 | if cursor.eof() { | ||
82 | cached.push(None); | ||
83 | continue; | ||
84 | } | 62 | } |
85 | 63 | Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { | |
86 | if let Some((curr, text)) = is_lifetime(cursor) { | 64 | cached.push(convert_delim(subtree.delimiter_kind(), false)); |
87 | cached.push(Some(TtToken { | 65 | cursor.subtree().unwrap() |
88 | kind: LIFETIME_IDENT, | ||
89 | is_joint_to_next: false, | ||
90 | text, | ||
91 | })); | ||
92 | self.cached_cursor.set(curr); | ||
93 | continue; | ||
94 | } | 66 | } |
95 | 67 | None => { | |
96 | match cursor.token_tree() { | 68 | if let Some(subtree) = cursor.end() { |
97 | Some(tt::TokenTree::Leaf(leaf)) => { | 69 | cached.push(convert_delim(subtree.delimiter_kind(), true)); |
98 | cached.push(Some(convert_leaf(&leaf))); | 70 | cursor.bump() |
99 | self.cached_cursor.set(cursor.bump()); | 71 | } else { |
100 | } | 72 | continue; |
101 | Some(tt::TokenTree::Subtree(subtree)) => { | ||
102 | self.cached_cursor.set(cursor.subtree().unwrap()); | ||
103 | cached.push(Some(convert_delim(subtree.delimiter_kind(), false))); | ||
104 | } | ||
105 | None => { | ||
106 | if let Some(subtree) = cursor.end() { | ||
107 | cached.push(Some(convert_delim(subtree.delimiter_kind(), true))); | ||
108 | self.cached_cursor.set(cursor.bump()); | ||
109 | } | ||
110 | } | 73 | } |
111 | } | 74 | } |
112 | } | 75 | }; |
113 | } | 76 | } |
114 | 77 | ||
115 | Ref::map(self.cached.borrow(), |c| &c[pos]) | 78 | let mut res = SubtreeTokenSource { |
79 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | ||
80 | cached, | ||
81 | }; | ||
82 | res.curr = (res.token(0), 0); | ||
83 | res | ||
84 | } | ||
85 | |||
86 | fn token(&self, pos: usize) -> Token { | ||
87 | match self.cached.get(pos) { | ||
88 | Some(it) => it.tt, | ||
89 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
90 | } | ||
116 | } | 91 | } |
117 | } | 92 | } |
118 | 93 | ||
119 | impl<'a> TokenSource for SubtreeTokenSource<'a> { | 94 | impl<'a> TokenSource for SubtreeTokenSource { |
120 | fn current(&self) -> Token { | 95 | fn current(&self) -> Token { |
121 | self.curr.0 | 96 | self.curr.0 |
122 | } | 97 | } |
123 | 98 | ||
124 | /// Lookahead n token | 99 | /// Lookahead n token |
125 | fn lookahead_nth(&self, n: usize) -> Token { | 100 | fn lookahead_nth(&self, n: usize) -> Token { |
126 | self.mk_token(self.curr.1 + n) | 101 | self.token(self.curr.1 + n) |
127 | } | 102 | } |
128 | 103 | ||
129 | /// bump cursor to next token | 104 | /// bump cursor to next token |
@@ -131,13 +106,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
131 | if self.current().kind == EOF { | 106 | if self.current().kind == EOF { |
132 | return; | 107 | return; |
133 | } | 108 | } |
134 | 109 | self.curr = (self.token(self.curr.1 + 1), self.curr.1 + 1); | |
135 | self.curr = (self.mk_token(self.curr.1 + 1), self.curr.1 + 1); | ||
136 | } | 110 | } |
137 | 111 | ||
138 | /// Is the current token a specified keyword? | 112 | /// Is the current token a specified keyword? |
139 | fn is_keyword(&self, kw: &str) -> bool { | 113 | fn is_keyword(&self, kw: &str) -> bool { |
140 | match *self.get(self.curr.1) { | 114 | match self.cached.get(self.curr.1) { |
141 | Some(ref t) => t.text == *kw, | 115 | Some(ref t) => t.text == *kw, |
142 | _ => false, | 116 | _ => false, |
143 | } | 117 | } |
@@ -155,7 +129,7 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
155 | let idx = closing as usize; | 129 | let idx = closing as usize; |
156 | let kind = kinds[idx]; | 130 | let kind = kinds[idx]; |
157 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; | 131 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; |
158 | TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) } | 132 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: SmolStr::new(text) } |
159 | } | 133 | } |
160 | 134 | ||
161 | fn convert_literal(l: &tt::Literal) -> TtToken { | 135 | fn convert_literal(l: &tt::Literal) -> TtToken { |
@@ -169,7 +143,7 @@ fn convert_literal(l: &tt::Literal) -> TtToken { | |||
169 | }) | 143 | }) |
170 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); | 144 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); |
171 | 145 | ||
172 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } | 146 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: l.text.clone() } |
173 | } | 147 | } |
174 | 148 | ||
175 | fn convert_ident(ident: &tt::Ident) -> TtToken { | 149 | fn convert_ident(ident: &tt::Ident) -> TtToken { |
@@ -180,7 +154,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken { | |||
180 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), | 154 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), |
181 | }; | 155 | }; |
182 | 156 | ||
183 | TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } | 157 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: ident.text.clone() } |
184 | } | 158 | } |
185 | 159 | ||
186 | fn convert_punct(p: tt::Punct) -> TtToken { | 160 | fn convert_punct(p: tt::Punct) -> TtToken { |
@@ -194,7 +168,7 @@ fn convert_punct(p: tt::Punct) -> TtToken { | |||
194 | let s: &str = p.char.encode_utf8(&mut buf); | 168 | let s: &str = p.char.encode_utf8(&mut buf); |
195 | SmolStr::new(s) | 169 | SmolStr::new(s) |
196 | }; | 170 | }; |
197 | TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text } | 171 | TtToken { tt: Token { kind, is_jointed_to_next: p.spacing == tt::Spacing::Joint }, text } |
198 | } | 172 | } |
199 | 173 | ||
200 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | 174 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { |
@@ -208,6 +182,7 @@ fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | |||
208 | #[cfg(test)] | 182 | #[cfg(test)] |
209 | mod tests { | 183 | mod tests { |
210 | use super::{convert_literal, TtToken}; | 184 | use super::{convert_literal, TtToken}; |
185 | use parser::Token; | ||
211 | use syntax::{SmolStr, SyntaxKind}; | 186 | use syntax::{SmolStr, SyntaxKind}; |
212 | 187 | ||
213 | #[test] | 188 | #[test] |
@@ -218,8 +193,7 @@ mod tests { | |||
218 | text: SmolStr::new("-42.0") | 193 | text: SmolStr::new("-42.0") |
219 | }), | 194 | }), |
220 | TtToken { | 195 | TtToken { |
221 | kind: SyntaxKind::FLOAT_NUMBER, | 196 | tt: Token { kind: SyntaxKind::FLOAT_NUMBER, is_jointed_to_next: false }, |
222 | is_joint_to_next: false, | ||
223 | text: SmolStr::new("-42.0") | 197 | text: SmolStr::new("-42.0") |
224 | } | 198 | } |
225 | ); | 199 | ); |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 265c0d63d..671036e1c 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -70,15 +70,12 @@ pub fn token_tree_to_syntax_node( | |||
70 | tt: &tt::Subtree, | 70 | tt: &tt::Subtree, |
71 | fragment_kind: FragmentKind, | 71 | fragment_kind: FragmentKind, |
72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { | 72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { |
73 | let tmp; | 73 | let buffer = match tt { |
74 | let tokens = match tt { | 74 | tt::Subtree { delimiter: None, token_trees } => { |
75 | tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(), | 75 | TokenBuffer::from_tokens(token_trees.as_slice()) |
76 | _ => { | ||
77 | tmp = [tt.clone().into()]; | ||
78 | &tmp[..] | ||
79 | } | 76 | } |
77 | _ => TokenBuffer::from_subtree(tt), | ||
80 | }; | 78 | }; |
81 | let buffer = TokenBuffer::new(&tokens); | ||
82 | let mut token_source = SubtreeTokenSource::new(&buffer); | 79 | let mut token_source = SubtreeTokenSource::new(&buffer); |
83 | let mut tree_sink = TtTreeSink::new(buffer.begin()); | 80 | let mut tree_sink = TtTreeSink::new(buffer.begin()); |
84 | parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); | 81 | parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); |
@@ -414,7 +411,7 @@ trait TokenConvertor { | |||
414 | fn id_alloc(&mut self) -> &mut TokenIdAlloc; | 411 | fn id_alloc(&mut self) -> &mut TokenIdAlloc; |
415 | } | 412 | } |
416 | 413 | ||
417 | impl<'a> SrcToken for (RawToken, &'a str) { | 414 | impl<'a> SrcToken for (&'a RawToken, &'a str) { |
418 | fn kind(&self) -> SyntaxKind { | 415 | fn kind(&self) -> SyntaxKind { |
419 | self.0.kind | 416 | self.0.kind |
420 | } | 417 | } |
@@ -431,7 +428,7 @@ impl<'a> SrcToken for (RawToken, &'a str) { | |||
431 | impl RawConvertor<'_> {} | 428 | impl RawConvertor<'_> {} |
432 | 429 | ||
433 | impl<'a> TokenConvertor for RawConvertor<'a> { | 430 | impl<'a> TokenConvertor for RawConvertor<'a> { |
434 | type Token = (RawToken, &'a str); | 431 | type Token = (&'a RawToken, &'a str); |
435 | 432 | ||
436 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> { | 433 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> { |
437 | convert_doc_comment(&doc_comment(token.1)) | 434 | convert_doc_comment(&doc_comment(token.1)) |
@@ -442,11 +439,11 @@ impl<'a> TokenConvertor for RawConvertor<'a> { | |||
442 | let range = TextRange::at(self.offset, token.len); | 439 | let range = TextRange::at(self.offset, token.len); |
443 | self.offset += token.len; | 440 | self.offset += token.len; |
444 | 441 | ||
445 | Some(((*token, &self.text[range]), range)) | 442 | Some(((token, &self.text[range]), range)) |
446 | } | 443 | } |
447 | 444 | ||
448 | fn peek(&self) -> Option<Self::Token> { | 445 | fn peek(&self) -> Option<Self::Token> { |
449 | let token = self.inner.as_slice().get(0).cloned(); | 446 | let token = self.inner.as_slice().get(0); |
450 | 447 | ||
451 | token.map(|it| { | 448 | token.map(|it| { |
452 | let range = TextRange::at(self.offset, it.len); | 449 | let range = TextRange::at(self.offset, it.len); |
@@ -601,17 +598,16 @@ impl<'a> TtTreeSink<'a> { | |||
601 | } | 598 | } |
602 | } | 599 | } |
603 | 600 | ||
604 | fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr { | 601 | fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> &'static str { |
605 | let texts = match d { | 602 | let texts = match d { |
606 | Some(tt::DelimiterKind::Parenthesis) => "()", | 603 | Some(tt::DelimiterKind::Parenthesis) => "()", |
607 | Some(tt::DelimiterKind::Brace) => "{}", | 604 | Some(tt::DelimiterKind::Brace) => "{}", |
608 | Some(tt::DelimiterKind::Bracket) => "[]", | 605 | Some(tt::DelimiterKind::Bracket) => "[]", |
609 | None => return "".into(), | 606 | None => return "", |
610 | }; | 607 | }; |
611 | 608 | ||
612 | let idx = closing as usize; | 609 | let idx = closing as usize; |
613 | let text = &texts[idx..texts.len() - (1 - idx)]; | 610 | &texts[idx..texts.len() - (1 - idx)] |
614 | text.into() | ||
615 | } | 611 | } |
616 | 612 | ||
617 | impl<'a> TreeSink for TtTreeSink<'a> { | 613 | impl<'a> TreeSink for TtTreeSink<'a> { |
@@ -626,29 +622,32 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
626 | 622 | ||
627 | let mut last = self.cursor; | 623 | let mut last = self.cursor; |
628 | for _ in 0..n_tokens { | 624 | for _ in 0..n_tokens { |
625 | let tmp_str: SmolStr; | ||
629 | if self.cursor.eof() { | 626 | if self.cursor.eof() { |
630 | break; | 627 | break; |
631 | } | 628 | } |
632 | last = self.cursor; | 629 | last = self.cursor; |
633 | let text: SmolStr = match self.cursor.token_tree() { | 630 | let text: &str = match self.cursor.token_tree() { |
634 | Some(tt::TokenTree::Leaf(leaf)) => { | 631 | Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { |
635 | // Mark the range if needed | 632 | // Mark the range if needed |
636 | let (text, id) = match leaf { | 633 | let (text, id) = match leaf { |
637 | tt::Leaf::Ident(ident) => (ident.text.clone(), ident.id), | 634 | tt::Leaf::Ident(ident) => (&ident.text, ident.id), |
638 | tt::Leaf::Punct(punct) => { | 635 | tt::Leaf::Punct(punct) => { |
639 | assert!(punct.char.is_ascii()); | 636 | assert!(punct.char.is_ascii()); |
640 | let char = &(punct.char as u8); | 637 | let char = &(punct.char as u8); |
641 | let text = std::str::from_utf8(std::slice::from_ref(char)).unwrap(); | 638 | tmp_str = SmolStr::new_inline( |
642 | (SmolStr::new_inline(text), punct.id) | 639 | std::str::from_utf8(std::slice::from_ref(char)).unwrap(), |
640 | ); | ||
641 | (&tmp_str, punct.id) | ||
643 | } | 642 | } |
644 | tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id), | 643 | tt::Leaf::Literal(lit) => (&lit.text, lit.id), |
645 | }; | 644 | }; |
646 | let range = TextRange::at(self.text_pos, TextSize::of(text.as_str())); | 645 | let range = TextRange::at(self.text_pos, TextSize::of(text.as_str())); |
647 | self.token_map.insert(id, range); | 646 | self.token_map.insert(id, range); |
648 | self.cursor = self.cursor.bump(); | 647 | self.cursor = self.cursor.bump(); |
649 | text | 648 | text |
650 | } | 649 | } |
651 | Some(tt::TokenTree::Subtree(subtree)) => { | 650 | Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { |
652 | self.cursor = self.cursor.subtree().unwrap(); | 651 | self.cursor = self.cursor.subtree().unwrap(); |
653 | if let Some(id) = subtree.delimiter.map(|it| it.id) { | 652 | if let Some(id) = subtree.delimiter.map(|it| it.id) { |
654 | self.open_delims.insert(id, self.text_pos); | 653 | self.open_delims.insert(id, self.text_pos); |
@@ -672,7 +671,7 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
672 | } | 671 | } |
673 | }; | 672 | }; |
674 | self.buf += &text; | 673 | self.buf += &text; |
675 | self.text_pos += TextSize::of(text.as_str()); | 674 | self.text_pos += TextSize::of(text); |
676 | } | 675 | } |
677 | 676 | ||
678 | let text = SmolStr::new(self.buf.as_str()); | 677 | let text = SmolStr::new(self.buf.as_str()); |
@@ -682,8 +681,8 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
682 | // Add whitespace between adjoint puncts | 681 | // Add whitespace between adjoint puncts |
683 | let next = last.bump(); | 682 | let next = last.bump(); |
684 | if let ( | 683 | if let ( |
685 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(curr))), | 684 | Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)), |
686 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(_))), | 685 | Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)), |
687 | ) = (last.token_tree(), next.token_tree()) | 686 | ) = (last.token_tree(), next.token_tree()) |
688 | { | 687 | { |
689 | // Note: We always assume the semi-colon would be the last token in | 688 | // Note: We always assume the semi-colon would be the last token in |
@@ -742,7 +741,7 @@ mod tests { | |||
742 | ) | 741 | ) |
743 | .expand_tt("literals!(foo);"); | 742 | .expand_tt("literals!(foo);"); |
744 | let tts = &[expansion.into()]; | 743 | let tts = &[expansion.into()]; |
745 | let buffer = tt::buffer::TokenBuffer::new(tts); | 744 | let buffer = tt::buffer::TokenBuffer::from_tokens(tts); |
746 | let mut tt_src = SubtreeTokenSource::new(&buffer); | 745 | let mut tt_src = SubtreeTokenSource::new(&buffer); |
747 | let mut tokens = vec![]; | 746 | let mut tokens = vec![]; |
748 | while tt_src.current().kind != EOF { | 747 | while tt_src.current().kind != EOF { |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 63cc90027..bb9ffea8b 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -66,6 +66,10 @@ pub(crate) mod fragments { | |||
66 | expressions::stmt(p, expressions::StmtWithSemi::No) | 66 | expressions::stmt(p, expressions::StmtWithSemi::No) |
67 | } | 67 | } |
68 | 68 | ||
69 | pub(crate) fn stmt_optional_semi(p: &mut Parser) { | ||
70 | expressions::stmt(p, expressions::StmtWithSemi::Optional) | ||
71 | } | ||
72 | |||
69 | pub(crate) fn opt_visibility(p: &mut Parser) { | 73 | pub(crate) fn opt_visibility(p: &mut Parser) { |
70 | let _ = super::opt_visibility(p); | 74 | let _ = super::opt_visibility(p); |
71 | } | 75 | } |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 811e740f9..9dfe63028 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs | |||
@@ -88,6 +88,7 @@ pub enum FragmentKind { | |||
88 | Path, | 88 | Path, |
89 | Expr, | 89 | Expr, |
90 | Statement, | 90 | Statement, |
91 | StatementOptionalSemi, | ||
91 | Type, | 92 | Type, |
92 | Pattern, | 93 | Pattern, |
93 | Item, | 94 | Item, |
@@ -118,6 +119,7 @@ pub fn parse_fragment( | |||
118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, | 119 | FragmentKind::Visibility => grammar::fragments::opt_visibility, |
119 | FragmentKind::MetaItem => grammar::fragments::meta_item, | 120 | FragmentKind::MetaItem => grammar::fragments::meta_item, |
120 | FragmentKind::Statement => grammar::fragments::stmt, | 121 | FragmentKind::Statement => grammar::fragments::stmt, |
122 | FragmentKind::StatementOptionalSemi => grammar::fragments::stmt_optional_semi, | ||
121 | FragmentKind::Items => grammar::fragments::macro_items, | 123 | FragmentKind::Items => grammar::fragments::macro_items, |
122 | FragmentKind::Statements => grammar::fragments::macro_stmts, | 124 | FragmentKind::Statements => grammar::fragments::macro_stmts, |
123 | FragmentKind::Attr => grammar::fragments::attr, | 125 | FragmentKind::Attr => grammar::fragments::attr, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 685a9fdf0..a5b1d90b1 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -777,9 +777,8 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String { | |||
777 | fields | 777 | fields |
778 | .iter() | 778 | .iter() |
779 | .map(|(field, _ty, doc, default)| { | 779 | .map(|(field, _ty, doc, default)| { |
780 | let name = field.replace("_", "."); | 780 | let name = format!("rust-analyzer.{}", field.replace("_", ".")); |
781 | let name = format!("rust-analyzer.{} (default: `{}`)", name, default); | 781 | format!("[[{}]]{} (default: `{}`)::\n{}\n", name, name, default, doc.join(" ")) |
782 | format!("{}::\n{}\n", name, doc.join(" ")) | ||
783 | }) | 782 | }) |
784 | .collect::<String>() | 783 | .collect::<String>() |
785 | } | 784 | } |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index dd486070b..c21ca044a 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -1648,7 +1648,7 @@ fn prepare_hover_actions( | |||
1648 | actions | 1648 | actions |
1649 | .iter() | 1649 | .iter() |
1650 | .filter_map(|it| match it { | 1650 | .filter_map(|it| match it { |
1651 | HoverAction::Implementaion(position) => show_impl_command_link(snap, position), | 1651 | HoverAction::Implementation(position) => show_impl_command_link(snap, position), |
1652 | HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), | 1652 | HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), |
1653 | HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), | 1653 | HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), |
1654 | }) | 1654 | }) |
diff --git a/crates/ssr/src/parsing.rs b/crates/ssr/src/parsing.rs index f3b084baf..3d5e4feb7 100644 --- a/crates/ssr/src/parsing.rs +++ b/crates/ssr/src/parsing.rs | |||
@@ -73,11 +73,18 @@ impl ParsedRule { | |||
73 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), | 73 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), |
74 | rules: Vec::new(), | 74 | rules: Vec::new(), |
75 | }; | 75 | }; |
76 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse)); | 76 | |
77 | let raw_template_stmt = raw_template.map(ast::Stmt::parse); | ||
78 | if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) { | ||
79 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr); | ||
80 | } else { | ||
81 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); | ||
82 | } | ||
77 | builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); | 83 | builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); |
78 | builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); | 84 | builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); |
79 | builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); | 85 | builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); |
80 | builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); | 86 | builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); |
87 | builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt); | ||
81 | builder.build() | 88 | builder.build() |
82 | } | 89 | } |
83 | } | 90 | } |
@@ -88,7 +95,11 @@ struct RuleBuilder { | |||
88 | } | 95 | } |
89 | 96 | ||
90 | impl RuleBuilder { | 97 | impl RuleBuilder { |
91 | fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) { | 98 | fn try_add<T: AstNode, T2: AstNode>( |
99 | &mut self, | ||
100 | pattern: Result<T, ()>, | ||
101 | template: Option<Result<T2, ()>>, | ||
102 | ) { | ||
92 | match (pattern, template) { | 103 | match (pattern, template) { |
93 | (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { | 104 | (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { |
94 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), | 105 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), |
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs index 63131f6ca..db9cb8ca1 100644 --- a/crates/ssr/src/tests.rs +++ b/crates/ssr/src/tests.rs | |||
@@ -160,6 +160,97 @@ fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expecte | |||
160 | } | 160 | } |
161 | 161 | ||
162 | #[test] | 162 | #[test] |
163 | fn ssr_let_stmt_in_macro_match() { | ||
164 | assert_matches( | ||
165 | "let a = 0", | ||
166 | r#" | ||
167 | macro_rules! m1 { ($a:stmt) => {$a}; } | ||
168 | fn f() {m1!{ let a = 0 };}"#, | ||
169 | // FIXME: Whitespace is not part of the matched block | ||
170 | &["leta=0"], | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn ssr_let_stmt_in_fn_match() { | ||
176 | assert_matches("let $a = 10;", "fn main() { let x = 10; x }", &["let x = 10;"]); | ||
177 | assert_matches("let $a = $b;", "fn main() { let x = 10; x }", &["let x = 10;"]); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn ssr_block_expr_match() { | ||
182 | assert_matches("{ let $a = $b; }", "fn main() { let x = 10; }", &["{ let x = 10; }"]); | ||
183 | assert_matches("{ let $a = $b; $c }", "fn main() { let x = 10; x }", &["{ let x = 10; x }"]); | ||
184 | } | ||
185 | |||
186 | #[test] | ||
187 | fn ssr_let_stmt_replace() { | ||
188 | // Pattern and template with trailing semicolon | ||
189 | assert_ssr_transform( | ||
190 | "let $a = $b; ==>> let $a = 11;", | ||
191 | "fn main() { let x = 10; x }", | ||
192 | expect![["fn main() { let x = 11; x }"]], | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn ssr_let_stmt_replace_expr() { | ||
198 | // Trailing semicolon should be dropped from the new expression | ||
199 | assert_ssr_transform( | ||
200 | "let $a = $b; ==>> $b", | ||
201 | "fn main() { let x = 10; }", | ||
202 | expect![["fn main() { 10 }"]], | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn ssr_blockexpr_replace_stmt_with_stmt() { | ||
208 | assert_ssr_transform( | ||
209 | "if $a() {$b;} ==>> $b;", | ||
210 | "{ | ||
211 | if foo() { | ||
212 | bar(); | ||
213 | } | ||
214 | Ok(()) | ||
215 | }", | ||
216 | expect![[r#"{ | ||
217 | bar(); | ||
218 | Ok(()) | ||
219 | }"#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn ssr_blockexpr_match_trailing_expr() { | ||
225 | assert_matches( | ||
226 | "if $a() {$b;}", | ||
227 | "{ | ||
228 | if foo() { | ||
229 | bar(); | ||
230 | } | ||
231 | }", | ||
232 | &["if foo() { | ||
233 | bar(); | ||
234 | }"], | ||
235 | ); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn ssr_blockexpr_replace_trailing_expr_with_stmt() { | ||
240 | assert_ssr_transform( | ||
241 | "if $a() {$b;} ==>> $b;", | ||
242 | "{ | ||
243 | if foo() { | ||
244 | bar(); | ||
245 | } | ||
246 | }", | ||
247 | expect![["{ | ||
248 | bar(); | ||
249 | }"]], | ||
250 | ); | ||
251 | } | ||
252 | |||
253 | #[test] | ||
163 | fn ssr_function_to_method() { | 254 | fn ssr_function_to_method() { |
164 | assert_ssr_transform( | 255 | assert_ssr_transform( |
165 | "my_function($a, $b) ==>> ($a).my_method($b)", | 256 | "my_function($a, $b) ==>> ($a).my_method($b)", |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 181077944..cfeaed9e6 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "697.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/lib.rs b/crates/syntax/src/lib.rs index 4d272f367..da151e328 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs | |||
@@ -212,6 +212,13 @@ impl ast::Attr { | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | impl ast::Stmt { | ||
216 | /// Returns `text`, parsed as statement, but only if it has no errors. | ||
217 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
218 | parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi) | ||
219 | } | ||
220 | } | ||
221 | |||
215 | /// Matches a `SyntaxNode` against an `ast` type. | 222 | /// Matches a `SyntaxNode` against an `ast` type. |
216 | /// | 223 | /// |
217 | /// # Example: | 224 | /// # Example: |
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index 8c217dfe0..9d3433c9d 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs | |||
@@ -103,6 +103,15 @@ fn type_parser_tests() { | |||
103 | } | 103 | } |
104 | 104 | ||
105 | #[test] | 105 | #[test] |
106 | fn stmt_parser_tests() { | ||
107 | fragment_parser_dir_test( | ||
108 | &["parser/fragments/stmt/ok"], | ||
109 | &["parser/fragments/stmt/err"], | ||
110 | crate::ast::Stmt::parse, | ||
111 | ); | ||
112 | } | ||
113 | |||
114 | #[test] | ||
106 | fn parser_fuzz_tests() { | 115 | fn parser_fuzz_tests() { |
107 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { | 116 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { |
108 | fuzz::check_parser(&text) | 117 | fuzz::check_parser(&text) |
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs new file mode 100644 index 000000000..988df0705 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs | |||
@@ -0,0 +1 @@ | |||
#[foo] | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs new file mode 100644 index 000000000..7e3b2fd49 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs | |||
@@ -0,0 +1 @@ | |||
a(); b(); c() | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs new file mode 100644 index 000000000..2d06f3766 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs | |||
@@ -0,0 +1 @@ | |||
( | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs new file mode 100644 index 000000000..092bc2b04 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs | |||
@@ -0,0 +1 @@ | |||
; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs new file mode 100644 index 000000000..ca49acb07 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs | |||
@@ -0,0 +1 @@ | |||
1 + | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast new file mode 100644 index 000000000..274fdf16d --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast | |||
@@ -0,0 +1,9 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] "1" | ||
5 | [email protected] " " | ||
6 | [email protected] "+" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "1" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs new file mode 100644 index 000000000..8d2f0971e --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs | |||
@@ -0,0 +1 @@ | |||
1 + 1 | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast new file mode 100644 index 000000000..6c946091f --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast | |||
@@ -0,0 +1,69 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "{" | ||
4 | [email protected] "\n " | ||
5 | [email protected] | ||
6 | [email protected] "let" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] | ||
10 | [email protected] "x" | ||
11 | [email protected] " " | ||
12 | [email protected] "=" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "foo" | ||
20 | [email protected] | ||
21 | [email protected] "(" | ||
22 | [email protected] ")" | ||
23 | [email protected] ";" | ||
24 | [email protected] "\n " | ||
25 | [email protected] | ||
26 | [email protected] "let" | ||
27 | [email protected] " " | ||
28 | [email protected] | ||
29 | [email protected] | ||
30 | [email protected] "y" | ||
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] "bar" | ||
40 | [email protected] | ||
41 | [email protected] "(" | ||
42 | [email protected] ")" | ||
43 | [email protected] ";" | ||
44 | [email protected] "\n " | ||
45 | [email protected] | ||
46 | [email protected] | ||
47 | [email protected] | ||
48 | [email protected] | ||
49 | [email protected] | ||
50 | [email protected] "Ok" | ||
51 | [email protected] | ||
52 | [email protected] "(" | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] | ||
56 | [email protected] | ||
57 | [email protected] | ||
58 | [email protected] "x" | ||
59 | [email protected] " " | ||
60 | [email protected] "+" | ||
61 | [email protected] " " | ||
62 | [email protected] | ||
63 | [email protected] | ||
64 | [email protected] | ||
65 | [email protected] | ||
66 | [email protected] "y" | ||
67 | [email protected] ")" | ||
68 | [email protected] "\n" | ||
69 | [email protected] "}" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs new file mode 100644 index 000000000..ffa5c1e66 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | { | ||
2 | let x = foo(); | ||
3 | let y = bar(); | ||
4 | Ok(x + y) | ||
5 | } | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast new file mode 100644 index 000000000..8c186da93 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast | |||
@@ -0,0 +1,11 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] "foo" | ||
8 | [email protected] | ||
9 | [email protected] "(" | ||
10 | [email protected] ")" | ||
11 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs new file mode 100644 index 000000000..a280f9a5c --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs | |||
@@ -0,0 +1 @@ | |||
foo(); | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast new file mode 100644 index 000000000..8ab38da21 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast | |||
@@ -0,0 +1,12 @@ | |||
1 | [email protected] | ||
2 | [email protected] "let" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "x" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "10" | ||
12 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs new file mode 100644 index 000000000..de8a7f1fc --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
let x = 10; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast new file mode 100644 index 000000000..81d6df29a --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast | |||
@@ -0,0 +1,21 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "m1" | ||
7 | [email protected] "!" | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] " " | ||
11 | [email protected] "let" | ||
12 | [email protected] " " | ||
13 | [email protected] "a" | ||
14 | [email protected] " " | ||
15 | [email protected] "=" | ||
16 | [email protected] " " | ||
17 | [email protected] "0" | ||
18 | [email protected] ";" | ||
19 | [email protected] " " | ||
20 | [email protected] "}" | ||
21 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs new file mode 100644 index 000000000..075f30159 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
m1!{ let a = 0; }; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast new file mode 100644 index 000000000..81d6df29a --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast | |||
@@ -0,0 +1,21 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "m1" | ||
7 | [email protected] "!" | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] " " | ||
11 | [email protected] "let" | ||
12 | [email protected] " " | ||
13 | [email protected] "a" | ||
14 | [email protected] " " | ||
15 | [email protected] "=" | ||
16 | [email protected] " " | ||
17 | [email protected] "0" | ||
18 | [email protected] ";" | ||
19 | [email protected] " " | ||
20 | [email protected] "}" | ||
21 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs new file mode 100644 index 000000000..075f30159 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
m1!{ let a = 0; }; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast new file mode 100644 index 000000000..64c5d2969 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast | |||
@@ -0,0 +1,22 @@ | |||
1 | [email protected] | ||
2 | [email protected] "struct" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] "Foo" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "{" | ||
9 | [email protected] "\n " | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] "bar" | ||
13 | [email protected] ":" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "u32" | ||
20 | [email protected] "," | ||
21 | [email protected] "\n" | ||
22 | [email protected] "}" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs new file mode 100644 index 000000000..e5473e3ac --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | struct Foo { | ||
2 | bar: u32, | ||
3 | } | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast new file mode 100644 index 000000000..9089906bc --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast | |||
@@ -0,0 +1,10 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] "foo" | ||
8 | [email protected] | ||
9 | [email protected] "(" | ||
10 | [email protected] ")" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs new file mode 100644 index 000000000..eb28ef440 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs | |||
@@ -0,0 +1 @@ | |||
foo() | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast new file mode 100644 index 000000000..37663671f --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast | |||
@@ -0,0 +1,11 @@ | |||
1 | [email protected] | ||
2 | [email protected] "let" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "x" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "10" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs new file mode 100644 index 000000000..78364b2a9 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
let x = 10 | |||
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs index 02c771f70..3606c887d 100644 --- a/crates/tt/src/buffer.rs +++ b/crates/tt/src/buffer.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::{Subtree, TokenTree}; | 3 | use crate::{Leaf, Subtree, TokenTree}; |
4 | 4 | ||
5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
6 | struct EntryId(usize); | 6 | struct EntryId(usize); |
@@ -13,7 +13,7 @@ struct EntryPtr(EntryId, usize); | |||
13 | #[derive(Debug)] | 13 | #[derive(Debug)] |
14 | enum Entry<'t> { | 14 | enum Entry<'t> { |
15 | // Mimicking types from proc-macro. | 15 | // Mimicking types from proc-macro. |
16 | Subtree(&'t TokenTree, EntryId), | 16 | Subtree(Option<&'t TokenTree>, &'t Subtree, EntryId), |
17 | Leaf(&'t TokenTree), | 17 | Leaf(&'t TokenTree), |
18 | // End entries contain a pointer to the entry from the containing | 18 | // End entries contain a pointer to the entry from the containing |
19 | // token tree, or None if this is the outermost level. | 19 | // token tree, or None if this is the outermost level. |
@@ -27,37 +27,64 @@ pub struct TokenBuffer<'t> { | |||
27 | buffers: Vec<Box<[Entry<'t>]>>, | 27 | buffers: Vec<Box<[Entry<'t>]>>, |
28 | } | 28 | } |
29 | 29 | ||
30 | impl<'t> TokenBuffer<'t> { | 30 | trait TokenList<'a> { |
31 | pub fn new(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { | 31 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>); |
32 | let mut buffers = vec![]; | 32 | } |
33 | |||
34 | let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); | ||
35 | assert_eq!(idx, 0); | ||
36 | |||
37 | TokenBuffer { buffers } | ||
38 | } | ||
39 | 33 | ||
40 | fn new_inner( | 34 | impl<'a> TokenList<'a> for &'a [TokenTree] { |
41 | tokens: &'t [TokenTree], | 35 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) { |
42 | buffers: &mut Vec<Box<[Entry<'t>]>>, | ||
43 | next: Option<EntryPtr>, | ||
44 | ) -> usize { | ||
45 | // Must contain everything in tokens and then the Entry::End | 36 | // Must contain everything in tokens and then the Entry::End |
46 | let start_capacity = tokens.len() + 1; | 37 | let start_capacity = self.len() + 1; |
47 | let mut entries = Vec::with_capacity(start_capacity); | 38 | let mut entries = Vec::with_capacity(start_capacity); |
48 | let mut children = vec![]; | 39 | let mut children = vec![]; |
49 | 40 | for (idx, tt) in self.iter().enumerate() { | |
50 | for (idx, tt) in tokens.iter().enumerate() { | ||
51 | match tt { | 41 | match tt { |
52 | TokenTree::Leaf(_) => { | 42 | TokenTree::Leaf(_) => { |
53 | entries.push(Entry::Leaf(tt)); | 43 | entries.push(Entry::Leaf(tt)); |
54 | } | 44 | } |
55 | TokenTree::Subtree(subtree) => { | 45 | TokenTree::Subtree(subtree) => { |
56 | entries.push(Entry::End(None)); | 46 | entries.push(Entry::End(None)); |
57 | children.push((idx, (subtree, tt))); | 47 | children.push((idx, (subtree, Some(tt)))); |
58 | } | 48 | } |
59 | } | 49 | } |
60 | } | 50 | } |
51 | (children, entries) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl<'a> TokenList<'a> for &'a Subtree { | ||
56 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) { | ||
57 | // Must contain everything in tokens and then the Entry::End | ||
58 | let mut entries = vec![]; | ||
59 | let mut children = vec![]; | ||
60 | entries.push(Entry::End(None)); | ||
61 | children.push((0usize, (*self, None))); | ||
62 | (children, entries) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl<'t> TokenBuffer<'t> { | ||
67 | pub fn from_tokens(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { | ||
68 | Self::new(tokens) | ||
69 | } | ||
70 | |||
71 | pub fn from_subtree(subtree: &'t Subtree) -> TokenBuffer<'t> { | ||
72 | Self::new(subtree) | ||
73 | } | ||
74 | |||
75 | fn new<T: TokenList<'t>>(tokens: T) -> TokenBuffer<'t> { | ||
76 | let mut buffers = vec![]; | ||
77 | let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); | ||
78 | assert_eq!(idx, 0); | ||
79 | TokenBuffer { buffers } | ||
80 | } | ||
81 | |||
82 | fn new_inner<T: TokenList<'t>>( | ||
83 | tokens: T, | ||
84 | buffers: &mut Vec<Box<[Entry<'t>]>>, | ||
85 | next: Option<EntryPtr>, | ||
86 | ) -> usize { | ||
87 | let (children, mut entries) = tokens.entries(); | ||
61 | 88 | ||
62 | entries.push(Entry::End(next)); | 89 | entries.push(Entry::End(next)); |
63 | let res = buffers.len(); | 90 | let res = buffers.len(); |
@@ -65,11 +92,11 @@ impl<'t> TokenBuffer<'t> { | |||
65 | 92 | ||
66 | for (child_idx, (subtree, tt)) in children { | 93 | for (child_idx, (subtree, tt)) in children { |
67 | let idx = TokenBuffer::new_inner( | 94 | let idx = TokenBuffer::new_inner( |
68 | &subtree.token_trees, | 95 | subtree.token_trees.as_slice(), |
69 | buffers, | 96 | buffers, |
70 | Some(EntryPtr(EntryId(res), child_idx + 1)), | 97 | Some(EntryPtr(EntryId(res), child_idx + 1)), |
71 | ); | 98 | ); |
72 | buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, EntryId(idx)); | 99 | buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, subtree, EntryId(idx)); |
73 | } | 100 | } |
74 | 101 | ||
75 | res | 102 | res |
@@ -87,6 +114,24 @@ impl<'t> TokenBuffer<'t> { | |||
87 | } | 114 | } |
88 | } | 115 | } |
89 | 116 | ||
117 | #[derive(Debug)] | ||
118 | pub enum TokenTreeRef<'a> { | ||
119 | Subtree(&'a Subtree, Option<&'a TokenTree>), | ||
120 | Leaf(&'a Leaf, &'a TokenTree), | ||
121 | } | ||
122 | |||
123 | impl<'a> TokenTreeRef<'a> { | ||
124 | pub fn cloned(&self) -> TokenTree { | ||
125 | match &self { | ||
126 | TokenTreeRef::Subtree(subtree, tt) => match tt { | ||
127 | Some(it) => (*it).clone(), | ||
128 | None => (*subtree).clone().into(), | ||
129 | }, | ||
130 | TokenTreeRef::Leaf(_, tt) => (*tt).clone(), | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
90 | /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125 | 135 | /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125 |
91 | #[derive(Copy, Clone, Debug)] | 136 | #[derive(Copy, Clone, Debug)] |
92 | pub struct Cursor<'a> { | 137 | pub struct Cursor<'a> { |
@@ -114,12 +159,11 @@ impl<'a> Cursor<'a> { | |||
114 | match self.entry() { | 159 | match self.entry() { |
115 | Some(Entry::End(Some(ptr))) => { | 160 | Some(Entry::End(Some(ptr))) => { |
116 | let idx = ptr.1; | 161 | let idx = ptr.1; |
117 | if let Some(Entry::Subtree(TokenTree::Subtree(subtree), _)) = | 162 | if let Some(Entry::Subtree(_, subtree, _)) = |
118 | self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) | 163 | self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) |
119 | { | 164 | { |
120 | return Some(subtree); | 165 | return Some(subtree); |
121 | } | 166 | } |
122 | |||
123 | None | 167 | None |
124 | } | 168 | } |
125 | _ => None, | 169 | _ => None, |
@@ -134,7 +178,7 @@ impl<'a> Cursor<'a> { | |||
134 | /// a cursor into that subtree | 178 | /// a cursor into that subtree |
135 | pub fn subtree(self) -> Option<Cursor<'a>> { | 179 | pub fn subtree(self) -> Option<Cursor<'a>> { |
136 | match self.entry() { | 180 | match self.entry() { |
137 | Some(Entry::Subtree(_, entry_id)) => { | 181 | Some(Entry::Subtree(_, _, entry_id)) => { |
138 | Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) | 182 | Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) |
139 | } | 183 | } |
140 | _ => None, | 184 | _ => None, |
@@ -142,10 +186,13 @@ impl<'a> Cursor<'a> { | |||
142 | } | 186 | } |
143 | 187 | ||
144 | /// If the cursor is pointing at a `TokenTree`, returns it | 188 | /// If the cursor is pointing at a `TokenTree`, returns it |
145 | pub fn token_tree(self) -> Option<&'a TokenTree> { | 189 | pub fn token_tree(self) -> Option<TokenTreeRef<'a>> { |
146 | match self.entry() { | 190 | match self.entry() { |
147 | Some(Entry::Leaf(tt)) => Some(tt), | 191 | Some(Entry::Leaf(tt)) => match tt { |
148 | Some(Entry::Subtree(tt, _)) => Some(tt), | 192 | TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, *tt)), |
193 | TokenTree::Subtree(subtree) => Some(TokenTreeRef::Subtree(subtree, Some(tt))), | ||
194 | }, | ||
195 | Some(Entry::Subtree(tt, subtree, _)) => Some(TokenTreeRef::Subtree(subtree, *tt)), | ||
149 | Some(Entry::End(_)) => None, | 196 | Some(Entry::End(_)) => None, |
150 | None => None, | 197 | None => None, |
151 | } | 198 | } |
@@ -172,7 +219,7 @@ impl<'a> Cursor<'a> { | |||
172 | /// a cursor into that subtree | 219 | /// a cursor into that subtree |
173 | pub fn bump_subtree(self) -> Cursor<'a> { | 220 | pub fn bump_subtree(self) -> Cursor<'a> { |
174 | match self.entry() { | 221 | match self.entry() { |
175 | Some(Entry::Subtree(_, _)) => self.subtree().unwrap(), | 222 | Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(), |
176 | _ => self.bump(), | 223 | _ => self.bump(), |
177 | } | 224 | } |
178 | } | 225 | } |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 3025dc8d6..e109f2b01 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -1,106 +1,106 @@ | |||
1 | rust-analyzer.assist.importMergeBehaviour (default: `"full"`):: | 1 | [[rust-analyzer.assist.importMergeBehaviour]]rust-analyzer.assist.importMergeBehaviour (default: `"full"`):: |
2 | The strategy to use when inserting new imports or merging imports. | 2 | The strategy to use when inserting new imports or merging imports. |
3 | rust-analyzer.assist.importPrefix (default: `"plain"`):: | 3 | [[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`):: |
4 | The path structure for newly inserted paths to use. | 4 | The path structure for newly inserted paths to use. |
5 | rust-analyzer.callInfo.full (default: `true`):: | 5 | [[rust-analyzer.callInfo.full]]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]]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]]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]]rust-analyzer.cargo.features (default: `[]`):: |
12 | List of features to activate. | 12 | List of features to activate. |
13 | rust-analyzer.cargo.loadOutDirsFromCheck (default: `false`):: | 13 | [[rust-analyzer.cargo.loadOutDirsFromCheck]]rust-analyzer.cargo.loadOutDirsFromCheck (default: `false`):: |
14 | Run `cargo check` on startup to get the correct value for package OUT_DIRs. | 14 | Run `cargo check` on startup to get the correct value for package OUT_DIRs. |
15 | rust-analyzer.cargo.noDefaultFeatures (default: `false`):: | 15 | [[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`):: |
16 | Do not activate the `default` feature. | 16 | Do not activate the `default` feature. |
17 | rust-analyzer.cargo.target (default: `null`):: | 17 | [[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`):: |
18 | Compilation target (target triple). | 18 | Compilation target (target triple). |
19 | rust-analyzer.cargo.noSysroot (default: `false`):: | 19 | [[rust-analyzer.cargo.noSysroot]]rust-analyzer.cargo.noSysroot (default: `false`):: |
20 | Internal config for debugging, disables loading of sysroot crates. | 20 | Internal config for debugging, disables loading of sysroot crates. |
21 | rust-analyzer.checkOnSave.enable (default: `true`):: | 21 | [[rust-analyzer.checkOnSave.enable]]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]]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]]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]]rust-analyzer.checkOnSave.command (default: `"check"`):: |
28 | Cargo command to use for `cargo check`. | 28 | Cargo command to use for `cargo check`. |
29 | rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: | 29 | [[rust-analyzer.checkOnSave.noDefaultFeatures]]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]]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]]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]]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]]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]]rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: |
40 | Whether to add argument snippets when completing functions. | 40 | Whether to add argument snippets when completing functions. |
41 | rust-analyzer.completion.addCallParenthesis (default: `true`):: | 41 | [[rust-analyzer.completion.addCallParenthesis]]rust-analyzer.completion.addCallParenthesis (default: `true`):: |
42 | Whether to add parenthesis when completing functions. | 42 | Whether to add parenthesis when completing functions. |
43 | rust-analyzer.completion.postfix.enable (default: `true`):: | 43 | [[rust-analyzer.completion.postfix.enable]]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]]rust-analyzer.completion.autoimport.enable (default: `true`):: |
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. | 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]]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]]rust-analyzer.diagnostics.enableExperimental (default: `true`):: |
50 | Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual. | 50 | Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual. |
51 | rust-analyzer.diagnostics.disabled (default: `[]`):: | 51 | [[rust-analyzer.diagnostics.disabled]]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]]rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: |
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`. | 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]]rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: |
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`. | 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]]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]]rust-analyzer.hoverActions.debug (default: `true`):: |
60 | Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. | 60 | Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. |
61 | rust-analyzer.hoverActions.enable (default: `true`):: | 61 | [[rust-analyzer.hoverActions.enable]]rust-analyzer.hoverActions.enable (default: `true`):: |
62 | Whether to show HoverActions in Rust files. | 62 | Whether to show HoverActions in Rust files. |
63 | rust-analyzer.hoverActions.gotoTypeDef (default: `true`):: | 63 | [[rust-analyzer.hoverActions.gotoTypeDef]]rust-analyzer.hoverActions.gotoTypeDef (default: `true`):: |
64 | Whether to show `Go to Type Definition` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. | 64 | Whether to show `Go to Type Definition` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. |
65 | rust-analyzer.hoverActions.implementations (default: `true`):: | 65 | [[rust-analyzer.hoverActions.implementations]]rust-analyzer.hoverActions.implementations (default: `true`):: |
66 | Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. | 66 | Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. |
67 | rust-analyzer.hoverActions.run (default: `true`):: | 67 | [[rust-analyzer.hoverActions.run]]rust-analyzer.hoverActions.run (default: `true`):: |
68 | Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. | 68 | Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set. |
69 | rust-analyzer.hoverActions.linksInHover (default: `true`):: | 69 | [[rust-analyzer.hoverActions.linksInHover]]rust-analyzer.hoverActions.linksInHover (default: `true`):: |
70 | Use markdown syntax for links in hover. | 70 | Use markdown syntax for links in hover. |
71 | rust-analyzer.inlayHints.chainingHints (default: `true`):: | 71 | [[rust-analyzer.inlayHints.chainingHints]]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]]rust-analyzer.inlayHints.maxLength (default: `null`):: |
74 | Maximum length for inlay hints. Default is unlimited. | 74 | Maximum length for inlay hints. Default is unlimited. |
75 | rust-analyzer.inlayHints.parameterHints (default: `true`):: | 75 | [[rust-analyzer.inlayHints.parameterHints]]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]]rust-analyzer.inlayHints.typeHints (default: `true`):: |
78 | Whether to show inlay type hints for variables. | 78 | Whether to show inlay type hints for variables. |
79 | rust-analyzer.lens.debug (default: `true`):: | 79 | [[rust-analyzer.lens.debug]]rust-analyzer.lens.debug (default: `true`):: |
80 | Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set. | 80 | Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set. |
81 | rust-analyzer.lens.enable (default: `true`):: | 81 | [[rust-analyzer.lens.enable]]rust-analyzer.lens.enable (default: `true`):: |
82 | Whether to show CodeLens in Rust files. | 82 | Whether to show CodeLens in Rust files. |
83 | rust-analyzer.lens.implementations (default: `true`):: | 83 | [[rust-analyzer.lens.implementations]]rust-analyzer.lens.implementations (default: `true`):: |
84 | Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set. | 84 | Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set. |
85 | rust-analyzer.lens.run (default: `true`):: | 85 | [[rust-analyzer.lens.run]]rust-analyzer.lens.run (default: `true`):: |
86 | Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set. | 86 | Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set. |
87 | rust-analyzer.lens.methodReferences (default: `false`):: | 87 | [[rust-analyzer.lens.methodReferences]]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]]rust-analyzer.linkedProjects (default: `[]`):: |
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. | 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]]rust-analyzer.lruCapacity (default: `null`):: |
92 | Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. | 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]]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]]rust-analyzer.procMacro.enable (default: `false`):: |
96 | Enable Proc macro support, `#rust-analyzer.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]]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]]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]]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]]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]]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/editors/code/package.json b/editors/code/package.json index 3e55a3523..63db87064 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -280,7 +280,7 @@ | |||
280 | "default": true, | 280 | "default": true, |
281 | "description": "Whether to ask for permission before downloading any files from the Internet." | 281 | "description": "Whether to ask for permission before downloading any files from the Internet." |
282 | }, | 282 | }, |
283 | "rust-analyzer.serverPath": { | 283 | "rust-analyzer.server.path": { |
284 | "type": [ | 284 | "type": [ |
285 | "null", | 285 | "null", |
286 | "string" | 286 | "string" |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index fe9f3b4a8..ebe4de1ea 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -93,7 +93,9 @@ export class Config { | |||
93 | return this.cfg.get<T>(path)!; | 93 | return this.cfg.get<T>(path)!; |
94 | } | 94 | } |
95 | 95 | ||
96 | get serverPath() { return this.get<null | string>("serverPath"); } | 96 | get serverPath() { |
97 | return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath"); | ||
98 | } | ||
97 | get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; } | 99 | get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; } |
98 | get channel() { return this.get<UpdatesChannel>("updates.channel"); } | 100 | get channel() { return this.get<UpdatesChannel>("updates.channel"); } |
99 | get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } | 101 | get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 60907dfd4..4c132cabe 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -287,16 +287,15 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
287 | }; | 287 | }; |
288 | if (config.package.releaseTag === null) return "rust-analyzer"; | 288 | if (config.package.releaseTag === null) return "rust-analyzer"; |
289 | 289 | ||
290 | let platform: string | undefined; | 290 | const platforms: { [key: string]: string } = { |
291 | if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") { | 291 | "ia32 win32": "x86_64-pc-windows-msvc", |
292 | platform = "x86_64-pc-windows-msvc"; | 292 | "x64 win32": "x86_64-pc-windows-msvc", |
293 | } else if (process.arch === "x64" && process.platform === "linux") { | 293 | "x64 linux": "x86_64-unknown-linux-gnu", |
294 | platform = "x86_64-unknown-linux-gnu"; | 294 | "x64 darwin": "x86_64-apple-darwin", |
295 | } else if (process.arch === "x64" && process.platform === "darwin") { | 295 | "arm64 win32": "aarch64-pc-windows-msvc", |
296 | platform = "x86_64-apple-darwin"; | 296 | "arm64 darwin": "aarch64-apple-darwin", |
297 | } else if (process.arch === "arm64" && process.platform === "darwin") { | 297 | }; |
298 | platform = "aarch64-apple-darwin"; | 298 | const platform = platforms[`${process.arch} ${process.platform}`]; |
299 | } | ||
300 | if (platform === undefined) { | 299 | if (platform === undefined) { |
301 | vscode.window.showErrorMessage( | 300 | vscode.window.showErrorMessage( |
302 | "Unfortunately we don't ship binaries for your platform yet. " + | 301 | "Unfortunately we don't ship binaries for your platform yet. " + |