diff options
95 files changed, 1907 insertions, 1018 deletions
diff --git a/Cargo.lock b/Cargo.lock index a99a221d2..901784bec 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -26,9 +26,9 @@ dependencies = [ | |||
26 | 26 | ||
27 | [[package]] | 27 | [[package]] |
28 | name = "anyhow" | 28 | name = "anyhow" |
29 | version = "1.0.37" | 29 | version = "1.0.38" |
30 | source = "registry+https://github.com/rust-lang/crates.io-index" | 30 | source = "registry+https://github.com/rust-lang/crates.io-index" |
31 | checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" | 31 | checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" |
32 | 32 | ||
33 | [[package]] | 33 | [[package]] |
34 | name = "anymap" | 34 | name = "anymap" |
@@ -118,9 +118,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | |||
118 | 118 | ||
119 | [[package]] | 119 | [[package]] |
120 | name = "byteorder" | 120 | name = "byteorder" |
121 | version = "1.3.4" | 121 | version = "1.4.2" |
122 | source = "registry+https://github.com/rust-lang/crates.io-index" | 122 | source = "registry+https://github.com/rust-lang/crates.io-index" |
123 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | 123 | checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" |
124 | 124 | ||
125 | [[package]] | 125 | [[package]] |
126 | name = "cargo-platform" | 126 | name = "cargo-platform" |
@@ -133,9 +133,9 @@ dependencies = [ | |||
133 | 133 | ||
134 | [[package]] | 134 | [[package]] |
135 | name = "cargo_metadata" | 135 | name = "cargo_metadata" |
136 | version = "0.12.2" | 136 | version = "0.12.3" |
137 | source = "registry+https://github.com/rust-lang/crates.io-index" | 137 | source = "registry+https://github.com/rust-lang/crates.io-index" |
138 | checksum = "11a47b6286279a9998588ef7050d1ebc2500c69892a557c90fe5d071c64415dc" | 138 | checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" |
139 | dependencies = [ | 139 | dependencies = [ |
140 | "cargo-platform", | 140 | "cargo-platform", |
141 | "semver", | 141 | "semver", |
@@ -269,9 +269,9 @@ dependencies = [ | |||
269 | 269 | ||
270 | [[package]] | 270 | [[package]] |
271 | name = "const_fn" | 271 | name = "const_fn" |
272 | version = "0.4.4" | 272 | version = "0.4.5" |
273 | source = "registry+https://github.com/rust-lang/crates.io-index" | 273 | source = "registry+https://github.com/rust-lang/crates.io-index" |
274 | checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" | 274 | checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" |
275 | 275 | ||
276 | [[package]] | 276 | [[package]] |
277 | name = "crc32fast" | 277 | name = "crc32fast" |
@@ -449,6 +449,12 @@ dependencies = [ | |||
449 | ] | 449 | ] |
450 | 450 | ||
451 | [[package]] | 451 | [[package]] |
452 | name = "fs_extra" | ||
453 | version = "1.2.0" | ||
454 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
455 | checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" | ||
456 | |||
457 | [[package]] | ||
452 | name = "fsevent" | 458 | name = "fsevent" |
453 | version = "2.0.2" | 459 | version = "2.0.2" |
454 | source = "registry+https://github.com/rust-lang/crates.io-index" | 460 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -502,12 +508,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
502 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" | 508 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" |
503 | 509 | ||
504 | [[package]] | 510 | [[package]] |
505 | name = "hashbrown" | ||
506 | version = "0.10.0" | ||
507 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
508 | checksum = "2140e9c963869f01789fa4fef4805211081ec794af5fc77c0d5b377906118853" | ||
509 | |||
510 | [[package]] | ||
511 | name = "heck" | 511 | name = "heck" |
512 | version = "0.3.2" | 512 | version = "0.3.2" |
513 | source = "registry+https://github.com/rust-lang/crates.io-index" | 513 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -518,9 +518,9 @@ dependencies = [ | |||
518 | 518 | ||
519 | [[package]] | 519 | [[package]] |
520 | name = "hermit-abi" | 520 | name = "hermit-abi" |
521 | version = "0.1.17" | 521 | version = "0.1.18" |
522 | source = "registry+https://github.com/rust-lang/crates.io-index" | 522 | source = "registry+https://github.com/rust-lang/crates.io-index" |
523 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" | 523 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" |
524 | dependencies = [ | 524 | dependencies = [ |
525 | "libc", | 525 | "libc", |
526 | ] | 526 | ] |
@@ -692,7 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
692 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" | 692 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" |
693 | dependencies = [ | 693 | dependencies = [ |
694 | "autocfg", | 694 | "autocfg", |
695 | "hashbrown 0.9.1", | 695 | "hashbrown", |
696 | ] | 696 | ] |
697 | 697 | ||
698 | [[package]] | 698 | [[package]] |
@@ -708,9 +708,9 @@ dependencies = [ | |||
708 | 708 | ||
709 | [[package]] | 709 | [[package]] |
710 | name = "inotify-sys" | 710 | name = "inotify-sys" |
711 | version = "0.1.4" | 711 | version = "0.1.5" |
712 | source = "registry+https://github.com/rust-lang/crates.io-index" | 712 | source = "registry+https://github.com/rust-lang/crates.io-index" |
713 | checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55" | 713 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" |
714 | dependencies = [ | 714 | dependencies = [ |
715 | "libc", | 715 | "libc", |
716 | ] | 716 | ] |
@@ -758,6 +758,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
758 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" | 758 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" |
759 | 759 | ||
760 | [[package]] | 760 | [[package]] |
761 | name = "jemalloc-ctl" | ||
762 | version = "0.3.3" | ||
763 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
764 | checksum = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7" | ||
765 | dependencies = [ | ||
766 | "jemalloc-sys", | ||
767 | "libc", | ||
768 | "paste", | ||
769 | ] | ||
770 | |||
771 | [[package]] | ||
772 | name = "jemalloc-sys" | ||
773 | version = "0.3.2" | ||
774 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
775 | checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45" | ||
776 | dependencies = [ | ||
777 | "cc", | ||
778 | "fs_extra", | ||
779 | "libc", | ||
780 | ] | ||
781 | |||
782 | [[package]] | ||
783 | name = "jemallocator" | ||
784 | version = "0.3.2" | ||
785 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
786 | checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69" | ||
787 | dependencies = [ | ||
788 | "jemalloc-sys", | ||
789 | "libc", | ||
790 | ] | ||
791 | |||
792 | [[package]] | ||
761 | name = "jod-thread" | 793 | name = "jod-thread" |
762 | version = "0.1.2" | 794 | version = "0.1.2" |
763 | source = "registry+https://github.com/rust-lang/crates.io-index" | 795 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -791,15 +823,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" | |||
791 | 823 | ||
792 | [[package]] | 824 | [[package]] |
793 | name = "libc" | 825 | name = "libc" |
794 | version = "0.2.81" | 826 | version = "0.2.82" |
795 | source = "registry+https://github.com/rust-lang/crates.io-index" | 827 | source = "registry+https://github.com/rust-lang/crates.io-index" |
796 | checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" | 828 | checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" |
797 | 829 | ||
798 | [[package]] | 830 | [[package]] |
799 | name = "libloading" | 831 | name = "libloading" |
800 | version = "0.6.6" | 832 | version = "0.6.7" |
801 | source = "registry+https://github.com/rust-lang/crates.io-index" | 833 | source = "registry+https://github.com/rust-lang/crates.io-index" |
802 | checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc" | 834 | checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" |
803 | dependencies = [ | 835 | dependencies = [ |
804 | "cfg-if 1.0.0", | 836 | "cfg-if 1.0.0", |
805 | "winapi 0.3.9", | 837 | "winapi 0.3.9", |
@@ -825,9 +857,9 @@ dependencies = [ | |||
825 | 857 | ||
826 | [[package]] | 858 | [[package]] |
827 | name = "log" | 859 | name = "log" |
828 | version = "0.4.11" | 860 | version = "0.4.13" |
829 | source = "registry+https://github.com/rust-lang/crates.io-index" | 861 | source = "registry+https://github.com/rust-lang/crates.io-index" |
830 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" | 862 | checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" |
831 | dependencies = [ | 863 | dependencies = [ |
832 | "cfg-if 0.1.10", | 864 | "cfg-if 0.1.10", |
833 | ] | 865 | ] |
@@ -1105,6 +1137,25 @@ dependencies = [ | |||
1105 | ] | 1137 | ] |
1106 | 1138 | ||
1107 | [[package]] | 1139 | [[package]] |
1140 | name = "paste" | ||
1141 | version = "0.1.18" | ||
1142 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1143 | checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" | ||
1144 | dependencies = [ | ||
1145 | "paste-impl", | ||
1146 | "proc-macro-hack", | ||
1147 | ] | ||
1148 | |||
1149 | [[package]] | ||
1150 | name = "paste-impl" | ||
1151 | version = "0.1.18" | ||
1152 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1153 | checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" | ||
1154 | dependencies = [ | ||
1155 | "proc-macro-hack", | ||
1156 | ] | ||
1157 | |||
1158 | [[package]] | ||
1108 | name = "paths" | 1159 | name = "paths" |
1109 | version = "0.0.0" | 1160 | version = "0.0.0" |
1110 | 1161 | ||
@@ -1160,9 +1211,15 @@ checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1" | |||
1160 | 1211 | ||
1161 | [[package]] | 1212 | [[package]] |
1162 | name = "pin-project-lite" | 1213 | name = "pin-project-lite" |
1163 | version = "0.2.0" | 1214 | version = "0.2.4" |
1164 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1165 | checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" | 1216 | checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" |
1217 | |||
1218 | [[package]] | ||
1219 | name = "proc-macro-hack" | ||
1220 | version = "0.5.19" | ||
1221 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1222 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" | ||
1166 | 1223 | ||
1167 | [[package]] | 1224 | [[package]] |
1168 | name = "proc-macro2" | 1225 | name = "proc-macro2" |
@@ -1212,6 +1269,7 @@ name = "profile" | |||
1212 | version = "0.0.0" | 1269 | version = "0.0.0" |
1213 | dependencies = [ | 1270 | dependencies = [ |
1214 | "cfg-if 1.0.0", | 1271 | "cfg-if 1.0.0", |
1272 | "jemalloc-ctl", | ||
1215 | "la-arena", | 1273 | "la-arena", |
1216 | "libc", | 1274 | "libc", |
1217 | "once_cell", | 1275 | "once_cell", |
@@ -1231,6 +1289,7 @@ dependencies = [ | |||
1231 | "log", | 1289 | "log", |
1232 | "paths", | 1290 | "paths", |
1233 | "proc_macro_api", | 1291 | "proc_macro_api", |
1292 | "profile", | ||
1234 | "rustc-hash", | 1293 | "rustc-hash", |
1235 | "serde", | 1294 | "serde", |
1236 | "serde_json", | 1295 | "serde_json", |
@@ -1300,9 +1359,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" | |||
1300 | 1359 | ||
1301 | [[package]] | 1360 | [[package]] |
1302 | name = "regex" | 1361 | name = "regex" |
1303 | version = "1.4.2" | 1362 | version = "1.4.3" |
1304 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1305 | checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" | 1364 | checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" |
1306 | dependencies = [ | 1365 | dependencies = [ |
1307 | "regex-syntax", | 1366 | "regex-syntax", |
1308 | ] | 1367 | ] |
@@ -1319,17 +1378,17 @@ dependencies = [ | |||
1319 | 1378 | ||
1320 | [[package]] | 1379 | [[package]] |
1321 | name = "regex-syntax" | 1380 | name = "regex-syntax" |
1322 | version = "0.6.21" | 1381 | version = "0.6.22" |
1323 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1324 | checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" | 1383 | checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" |
1325 | 1384 | ||
1326 | [[package]] | 1385 | [[package]] |
1327 | name = "rowan" | 1386 | name = "rowan" |
1328 | version = "0.10.4" | 1387 | version = "0.10.6" |
1329 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1330 | checksum = "98815aeea8062a9e022803220f388a8d55842ed53d587b69d71c454670167c99" | 1389 | checksum = "8a0734142c18710f7214dc21908e2f054e973b908dbb1a602a3e6691615aaaae" |
1331 | dependencies = [ | 1390 | dependencies = [ |
1332 | "hashbrown 0.10.0", | 1391 | "hashbrown", |
1333 | "rustc-hash", | 1392 | "rustc-hash", |
1334 | "smol_str", | 1393 | "smol_str", |
1335 | "text-size", | 1394 | "text-size", |
@@ -1353,6 +1412,7 @@ dependencies = [ | |||
1353 | "ide", | 1412 | "ide", |
1354 | "ide_db", | 1413 | "ide_db", |
1355 | "itertools 0.10.0", | 1414 | "itertools 0.10.0", |
1415 | "jemallocator", | ||
1356 | "jod-thread", | 1416 | "jod-thread", |
1357 | "log", | 1417 | "log", |
1358 | "lsp-server", | 1418 | "lsp-server", |
@@ -1484,18 +1544,18 @@ dependencies = [ | |||
1484 | 1544 | ||
1485 | [[package]] | 1545 | [[package]] |
1486 | name = "serde" | 1546 | name = "serde" |
1487 | version = "1.0.118" | 1547 | version = "1.0.119" |
1488 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1489 | checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" | 1549 | checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" |
1490 | dependencies = [ | 1550 | dependencies = [ |
1491 | "serde_derive", | 1551 | "serde_derive", |
1492 | ] | 1552 | ] |
1493 | 1553 | ||
1494 | [[package]] | 1554 | [[package]] |
1495 | name = "serde_derive" | 1555 | name = "serde_derive" |
1496 | version = "1.0.118" | 1556 | version = "1.0.119" |
1497 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1498 | checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" | 1558 | checksum = "552954ce79a059ddd5fd68c271592374bd15cab2274970380c000118aeffe1cd" |
1499 | dependencies = [ | 1559 | dependencies = [ |
1500 | "proc-macro2", | 1560 | "proc-macro2", |
1501 | "quote", | 1561 | "quote", |
@@ -1551,9 +1611,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | |||
1551 | 1611 | ||
1552 | [[package]] | 1612 | [[package]] |
1553 | name = "smallvec" | 1613 | name = "smallvec" |
1554 | version = "1.6.0" | 1614 | version = "1.6.1" |
1555 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1556 | checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" | 1616 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" |
1557 | 1617 | ||
1558 | [[package]] | 1618 | [[package]] |
1559 | name = "smol_str" | 1619 | name = "smol_str" |
@@ -1593,9 +1653,9 @@ dependencies = [ | |||
1593 | 1653 | ||
1594 | [[package]] | 1654 | [[package]] |
1595 | name = "syn" | 1655 | name = "syn" |
1596 | version = "1.0.57" | 1656 | version = "1.0.58" |
1597 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1657 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1598 | checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6" | 1658 | checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" |
1599 | dependencies = [ | 1659 | dependencies = [ |
1600 | "proc-macro2", | 1660 | "proc-macro2", |
1601 | "quote", | 1661 | "quote", |
@@ -1672,9 +1732,9 @@ dependencies = [ | |||
1672 | 1732 | ||
1673 | [[package]] | 1733 | [[package]] |
1674 | name = "thread_local" | 1734 | name = "thread_local" |
1675 | version = "1.0.1" | 1735 | version = "1.1.0" |
1676 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1677 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" | 1737 | checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" |
1678 | dependencies = [ | 1738 | dependencies = [ |
1679 | "lazy_static", | 1739 | "lazy_static", |
1680 | ] | 1740 | ] |
@@ -1838,9 +1898,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" | |||
1838 | 1898 | ||
1839 | [[package]] | 1899 | [[package]] |
1840 | name = "ungrammar" | 1900 | name = "ungrammar" |
1841 | version = "1.8.0" | 1901 | version = "1.9.3" |
1842 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1843 | checksum = "e33a2183403af89252547c4219a06a6cc8aef6302fee67e10e8431866af3ee72" | 1903 | checksum = "f5901372c0f3a6a1a9d880aef134c8eaf5e54409343637508c0a344270b42d7b" |
1844 | 1904 | ||
1845 | [[package]] | 1905 | [[package]] |
1846 | name = "unicase" | 1906 | name = "unicase" |
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 4e2a4fcd9..e93901cb3 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -3,7 +3,7 @@ use ide_db::helpers::{ | |||
3 | insert_use::{insert_use, ImportScope}, | 3 | insert_use::{insert_use, ImportScope}, |
4 | mod_path_to_ast, | 4 | mod_path_to_ast, |
5 | }; | 5 | }; |
6 | use syntax::ast; | 6 | use syntax::{ast, AstNode, SyntaxNode}; |
7 | 7 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
9 | 9 | ||
@@ -82,25 +82,16 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | |||
82 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 82 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
83 | // ``` | 83 | // ``` |
84 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 84 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
85 | let import_assets = | 85 | let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; |
86 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { | 86 | let proposed_imports = |
87 | ImportAssets::for_regular_path(path_under_caret, &ctx.sema) | 87 | import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind); |
88 | } else if let Some(method_under_caret) = | ||
89 | ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>() | ||
90 | { | ||
91 | ImportAssets::for_method_call(method_under_caret, &ctx.sema) | ||
92 | } else { | ||
93 | None | ||
94 | }?; | ||
95 | let proposed_imports = import_assets.search_for_imports(&ctx.sema, &ctx.config.insert_use); | ||
96 | if proposed_imports.is_empty() { | 88 | if proposed_imports.is_empty() { |
97 | return None; | 89 | return None; |
98 | } | 90 | } |
99 | 91 | ||
100 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 92 | let range = ctx.sema.original_range(&syntax_under_caret).range; |
101 | let group = import_group_message(import_assets.import_candidate()); | 93 | let group = import_group_message(import_assets.import_candidate()); |
102 | let scope = | 94 | let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; |
103 | ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?; | ||
104 | for (import, _) in proposed_imports { | 95 | for (import, _) in proposed_imports { |
105 | acc.add_group( | 96 | acc.add_group( |
106 | &group, | 97 | &group, |
@@ -117,14 +108,28 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
117 | Some(()) | 108 | Some(()) |
118 | } | 109 | } |
119 | 110 | ||
111 | pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> { | ||
112 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { | ||
113 | ImportAssets::for_exact_path(&path_under_caret, &ctx.sema) | ||
114 | .zip(Some(path_under_caret.syntax().clone())) | ||
115 | } else if let Some(method_under_caret) = | ||
116 | ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>() | ||
117 | { | ||
118 | ImportAssets::for_method_call(&method_under_caret, &ctx.sema) | ||
119 | .zip(Some(method_under_caret.syntax().clone())) | ||
120 | } else { | ||
121 | None | ||
122 | } | ||
123 | } | ||
124 | |||
120 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | 125 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { |
121 | let name = match import_candidate { | 126 | let name = match import_candidate { |
122 | ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name), | 127 | ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), |
123 | ImportCandidate::TraitAssocItem(candidate) => { | 128 | ImportCandidate::TraitAssocItem(candidate) => { |
124 | format!("Import a trait for item {}", &candidate.name) | 129 | format!("Import a trait for item {}", candidate.name.text()) |
125 | } | 130 | } |
126 | ImportCandidate::TraitMethod(candidate) => { | 131 | ImportCandidate::TraitMethod(candidate) => { |
127 | format!("Import a trait for method {}", &candidate.name) | 132 | format!("Import a trait for method {}", candidate.name.text()) |
128 | } | 133 | } |
129 | }; | 134 | }; |
130 | GroupLabel(name) | 135 | GroupLabel(name) |
diff --git a/crates/assists/src/handlers/introduce_named_lifetime.rs b/crates/assists/src/handlers/introduce_named_lifetime.rs index 3f5f44d69..02782eb6d 100644 --- a/crates/assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -61,7 +61,7 @@ fn generate_fn_def_assist( | |||
61 | // compute the location which implicitly has the same lifetime as the anonymous lifetime | 61 | // compute the location which implicitly has the same lifetime as the anonymous lifetime |
62 | let loc_needing_lifetime = if let Some(self_param) = self_param { | 62 | let loc_needing_lifetime = if let Some(self_param) = self_param { |
63 | // if we have a self reference, use that | 63 | // if we have a self reference, use that |
64 | Some(self_param.self_token()?.text_range().start()) | 64 | Some(self_param.name()?.syntax().text_range().start()) |
65 | } else { | 65 | } else { |
66 | // otherwise, if there's a single reference parameter without a named liftime, use that | 66 | // otherwise, if there's a single reference parameter without a named liftime, use that |
67 | let fn_params_without_lifetime: Vec<_> = param_list | 67 | let fn_params_without_lifetime: Vec<_> = param_list |
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index a7d9fd4dc..b0b0d31b4 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -1,10 +1,7 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::{AsAssocItem, AsName}; |
4 | use ide_db::helpers::{ | 4 | use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast}; |
5 | import_assets::{ImportAssets, ImportCandidate}, | ||
6 | mod_path_to_ast, | ||
7 | }; | ||
8 | use ide_db::RootDatabase; | 5 | use ide_db::RootDatabase; |
9 | use syntax::{ | 6 | use syntax::{ |
10 | ast, | 7 | ast, |
@@ -18,6 +15,8 @@ use crate::{ | |||
18 | AssistId, AssistKind, GroupLabel, | 15 | AssistId, AssistKind, GroupLabel, |
19 | }; | 16 | }; |
20 | 17 | ||
18 | use super::auto_import::find_importable_node; | ||
19 | |||
21 | // Assist: qualify_path | 20 | // Assist: qualify_path |
22 | // | 21 | // |
23 | // If the name is unresolved, provides all possible qualified paths for it. | 22 | // If the name is unresolved, provides all possible qualified paths for it. |
@@ -36,47 +35,38 @@ use crate::{ | |||
36 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 35 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
37 | // ``` | 36 | // ``` |
38 | pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 37 | pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
39 | let import_assets = | 38 | let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; |
40 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { | ||
41 | ImportAssets::for_regular_path(path_under_caret, &ctx.sema) | ||
42 | } else if let Some(method_under_caret) = | ||
43 | ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>() | ||
44 | { | ||
45 | ImportAssets::for_method_call(method_under_caret, &ctx.sema) | ||
46 | } else { | ||
47 | None | ||
48 | }?; | ||
49 | let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema); | 39 | let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema); |
50 | if proposed_imports.is_empty() { | 40 | if proposed_imports.is_empty() { |
51 | return None; | 41 | return None; |
52 | } | 42 | } |
53 | 43 | ||
54 | let candidate = import_assets.import_candidate(); | 44 | let candidate = import_assets.import_candidate(); |
55 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 45 | let range = ctx.sema.original_range(&syntax_under_caret).range; |
56 | 46 | ||
57 | let qualify_candidate = match candidate { | 47 | let qualify_candidate = match candidate { |
58 | ImportCandidate::Path(candidate) => { | 48 | ImportCandidate::Path(candidate) => { |
59 | if candidate.qualifier.is_some() { | 49 | if candidate.qualifier.is_some() { |
60 | mark::hit!(qualify_path_qualifier_start); | 50 | mark::hit!(qualify_path_qualifier_start); |
61 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 51 | let path = ast::Path::cast(syntax_under_caret)?; |
62 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); | 52 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); |
63 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) | 53 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) |
64 | } else { | 54 | } else { |
65 | mark::hit!(qualify_path_unqualified_name); | 55 | mark::hit!(qualify_path_unqualified_name); |
66 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 56 | let path = ast::Path::cast(syntax_under_caret)?; |
67 | let generics = path.segment()?.generic_arg_list(); | 57 | let generics = path.segment()?.generic_arg_list(); |
68 | QualifyCandidate::UnqualifiedName(generics) | 58 | QualifyCandidate::UnqualifiedName(generics) |
69 | } | 59 | } |
70 | } | 60 | } |
71 | ImportCandidate::TraitAssocItem(_) => { | 61 | ImportCandidate::TraitAssocItem(_) => { |
72 | mark::hit!(qualify_path_trait_assoc_item); | 62 | mark::hit!(qualify_path_trait_assoc_item); |
73 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 63 | let path = ast::Path::cast(syntax_under_caret)?; |
74 | let (qualifier, segment) = (path.qualifier()?, path.segment()?); | 64 | let (qualifier, segment) = (path.qualifier()?, path.segment()?); |
75 | QualifyCandidate::TraitAssocItem(qualifier, segment) | 65 | QualifyCandidate::TraitAssocItem(qualifier, segment) |
76 | } | 66 | } |
77 | ImportCandidate::TraitMethod(_) => { | 67 | ImportCandidate::TraitMethod(_) => { |
78 | mark::hit!(qualify_path_trait_method); | 68 | mark::hit!(qualify_path_trait_method); |
79 | let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?; | 69 | let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; |
80 | QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) | 70 | QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) |
81 | } | 71 | } |
82 | }; | 72 | }; |
@@ -140,7 +130,7 @@ impl QualifyCandidate<'_> { | |||
140 | let generics = | 130 | let generics = |
141 | mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string); | 131 | mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string); |
142 | let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args()); | 132 | let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args()); |
143 | let trait_ = item_as_trait(item)?; | 133 | let trait_ = item_as_trait(db, item)?; |
144 | let method = find_trait_method(db, trait_, &trait_method_name)?; | 134 | let method = find_trait_method(db, trait_, &trait_method_name)?; |
145 | if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) { | 135 | if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) { |
146 | let receiver = match self_access { | 136 | let receiver = match self_access { |
@@ -179,11 +169,13 @@ fn find_trait_method( | |||
179 | } | 169 | } |
180 | } | 170 | } |
181 | 171 | ||
182 | fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> { | 172 | fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> { |
183 | if let hir::ModuleDef::Trait(trait_) = hir::ModuleDef::from(item.as_module_def_id()?) { | 173 | let item_module_def = hir::ModuleDef::from(item.as_module_def_id()?); |
174 | |||
175 | if let hir::ModuleDef::Trait(trait_) = item_module_def { | ||
184 | Some(trait_) | 176 | Some(trait_) |
185 | } else { | 177 | } else { |
186 | None | 178 | item_module_def.as_assoc_item(db)?.containing_trait(db) |
187 | } | 179 | } |
188 | } | 180 | } |
189 | 181 | ||
@@ -191,7 +183,8 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { | |||
191 | let name = match candidate { | 183 | let name = match candidate { |
192 | ImportCandidate::Path(it) => &it.name, | 184 | ImportCandidate::Path(it) => &it.name, |
193 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, | 185 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, |
194 | }; | 186 | } |
187 | .text(); | ||
195 | GroupLabel(format!("Qualify {}", name)) | 188 | GroupLabel(format!("Qualify {}", name)) |
196 | } | 189 | } |
197 | 190 | ||
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 2dd8fbe67..b5f7e4200 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -178,7 +178,7 @@ pub struct CrateData { | |||
178 | pub root_file_id: FileId, | 178 | pub root_file_id: FileId, |
179 | pub edition: Edition, | 179 | pub edition: Edition, |
180 | /// A name used in the package's project declaration: for Cargo projects, | 180 | /// A name used in the package's project declaration: for Cargo projects, |
181 | /// it's [package].name, can be different for other project types or even | 181 | /// its `[package].name` can be different for other project types or even |
182 | /// absent (a dummy crate for the code snippet, for example). | 182 | /// absent (a dummy crate for the code snippet, for example). |
183 | /// | 183 | /// |
184 | /// For purposes of analysis, crates are anonymous (only names in | 184 | /// For purposes of analysis, crates are anonymous (only names in |
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs index e5522980d..ab25a8c58 100644 --- a/crates/completion/src/completions/attribute.rs +++ b/crates/completion/src/completions/attribute.rs | |||
@@ -99,13 +99,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
99 | Some("export_name"), | 99 | Some("export_name"), |
100 | Some(r#"export_name = "${0:exported_symbol_name}""#), | 100 | Some(r#"export_name = "${0:exported_symbol_name}""#), |
101 | ), | 101 | ), |
102 | attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)), | ||
102 | attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), | 103 | attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), |
103 | attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), | 104 | attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), |
104 | attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), | 105 | attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), |
105 | // FIXME: resolve through macro resolution? | 106 | // FIXME: resolve through macro resolution? |
106 | attr("global_allocator", None, None).prefer_inner(), | 107 | attr("global_allocator", None, None).prefer_inner(), |
107 | attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), | 108 | attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), |
108 | attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), | 109 | attr("inline", Some("inline"), Some("inline")), |
109 | attr("link", None, None), | 110 | attr("link", None, None), |
110 | attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), | 111 | attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), |
111 | attr( | 112 | attr( |
@@ -468,10 +469,11 @@ struct Test {} | |||
468 | at deprecated | 469 | at deprecated |
469 | at derive(…) | 470 | at derive(…) |
470 | at export_name = "…" | 471 | at export_name = "…" |
472 | at doc(alias = "…") | ||
471 | at doc = "…" | 473 | at doc = "…" |
472 | at forbid(…) | 474 | at forbid(…) |
473 | at ignore = "…" | 475 | at ignore = "…" |
474 | at inline(…) | 476 | at inline |
475 | at link | 477 | at link |
476 | at link_name = "…" | 478 | at link_name = "…" |
477 | at link_section = "…" | 479 | at link_section = "…" |
@@ -515,12 +517,13 @@ struct Test {} | |||
515 | at deprecated | 517 | at deprecated |
516 | at derive(…) | 518 | at derive(…) |
517 | at export_name = "…" | 519 | at export_name = "…" |
520 | at doc(alias = "…") | ||
518 | at doc = "…" | 521 | at doc = "…" |
519 | at feature(…) | 522 | at feature(…) |
520 | at forbid(…) | 523 | at forbid(…) |
521 | at global_allocator | 524 | at global_allocator |
522 | at ignore = "…" | 525 | at ignore = "…" |
523 | at inline(…) | 526 | at inline |
524 | at link | 527 | at link |
525 | at link_name = "…" | 528 | at link_name = "…" |
526 | at link_section = "…" | 529 | at link_section = "…" |
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs index 222809638..dc0b38a16 100644 --- a/crates/completion/src/completions/flyimport.rs +++ b/crates/completion/src/completions/flyimport.rs | |||
@@ -20,11 +20,14 @@ | |||
20 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } | 20 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } |
21 | //! ``` | 21 | //! ``` |
22 | //! | 22 | //! |
23 | //! Also completes associated items, that require trait imports. | ||
24 | //! | ||
23 | //! .Fuzzy search details | 25 | //! .Fuzzy search details |
24 | //! | 26 | //! |
25 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | 27 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only |
26 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). | 28 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). |
27 | //! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | 29 | //! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols |
30 | //! (but shows all associated items for any input length). | ||
28 | //! | 31 | //! |
29 | //! .Import configuration | 32 | //! .Import configuration |
30 | //! | 33 | //! |
@@ -45,10 +48,12 @@ | |||
45 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 48 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding |
46 | //! capability enabled. | 49 | //! capability enabled. |
47 | 50 | ||
48 | use either::Either; | 51 | use hir::{AsAssocItem, ModPath, ScopeDef}; |
49 | use hir::{ModPath, ScopeDef}; | 52 | use ide_db::helpers::{ |
50 | use ide_db::{helpers::insert_use::ImportScope, imports_locator}; | 53 | import_assets::{ImportAssets, ImportCandidate}, |
51 | use syntax::AstNode; | 54 | insert_use::ImportScope, |
55 | }; | ||
56 | use syntax::{AstNode, SyntaxNode, T}; | ||
52 | use test_utils::mark; | 57 | use test_utils::mark; |
53 | 58 | ||
54 | use crate::{ | 59 | use crate::{ |
@@ -60,58 +65,108 @@ use crate::{ | |||
60 | use super::Completions; | 65 | use super::Completions; |
61 | 66 | ||
62 | pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 67 | pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
63 | if !ctx.config.enable_autoimport_completions { | 68 | if !ctx.config.enable_imports_on_the_fly { |
64 | return None; | 69 | return None; |
65 | } | 70 | } |
66 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { | 71 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { |
67 | return None; | 72 | return None; |
68 | } | 73 | } |
69 | let potential_import_name = ctx.token.to_string(); | 74 | let potential_import_name = { |
70 | if potential_import_name.len() < 2 { | 75 | let token_kind = ctx.token.kind(); |
71 | return None; | 76 | if matches!(token_kind, T![.] | T![::]) { |
72 | } | 77 | String::new() |
73 | let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); | 78 | } else { |
79 | ctx.token.to_string() | ||
80 | } | ||
81 | }; | ||
74 | 82 | ||
75 | let current_module = ctx.scope.module()?; | 83 | let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); |
76 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
77 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
78 | 84 | ||
79 | let user_input_lowercased = potential_import_name.to_lowercase(); | 85 | let user_input_lowercased = potential_import_name.to_lowercase(); |
80 | let mut all_mod_paths = imports_locator::find_similar_imports( | 86 | let import_assets = import_assets(ctx, potential_import_name)?; |
87 | let import_scope = ImportScope::find_insert_use_container( | ||
88 | position_for_import(ctx, Some(import_assets.import_candidate()))?, | ||
81 | &ctx.sema, | 89 | &ctx.sema, |
82 | ctx.krate?, | 90 | )?; |
83 | Some(40), | 91 | let mut all_mod_paths = import_assets |
84 | potential_import_name, | 92 | .search_for_relative_paths(&ctx.sema) |
85 | true, | 93 | .into_iter() |
86 | true, | 94 | .map(|(mod_path, item_in_ns)| { |
87 | ) | 95 | let scope_item = match item_in_ns { |
88 | .filter_map(|import_candidate| { | 96 | hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), |
89 | Some(match import_candidate { | 97 | hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), |
90 | Either::Left(module_def) => { | 98 | hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), |
91 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | 99 | }; |
92 | } | 100 | (mod_path, scope_item) |
93 | Either::Right(macro_def) => { | ||
94 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
95 | } | ||
96 | }) | 101 | }) |
97 | }) | 102 | .collect::<Vec<_>>(); |
98 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
99 | .collect::<Vec<_>>(); | ||
100 | |||
101 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | 103 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { |
102 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | 104 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) |
103 | }); | 105 | }); |
104 | 106 | ||
105 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { | 107 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { |
106 | render_resolution_with_import( | 108 | let import_for_trait_assoc_item = match definition { |
107 | RenderContext::new(ctx), | 109 | ScopeDef::ModuleDef(module_def) => module_def |
108 | ImportEdit { import_path, import_scope: import_scope.clone() }, | 110 | .as_assoc_item(ctx.db) |
109 | &definition, | 111 | .and_then(|assoc| assoc.containing_trait(ctx.db)) |
110 | ) | 112 | .is_some(), |
113 | _ => false, | ||
114 | }; | ||
115 | let import_edit = ImportEdit { | ||
116 | import_path, | ||
117 | import_scope: import_scope.clone(), | ||
118 | import_for_trait_assoc_item, | ||
119 | }; | ||
120 | render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition) | ||
111 | })); | 121 | })); |
112 | Some(()) | 122 | Some(()) |
113 | } | 123 | } |
114 | 124 | ||
125 | pub(crate) fn position_for_import<'a>( | ||
126 | ctx: &'a CompletionContext, | ||
127 | import_candidate: Option<&ImportCandidate>, | ||
128 | ) -> Option<&'a SyntaxNode> { | ||
129 | Some(match import_candidate { | ||
130 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), | ||
131 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), | ||
132 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(), | ||
133 | None => ctx | ||
134 | .name_ref_syntax | ||
135 | .as_ref() | ||
136 | .map(|name_ref| name_ref.syntax()) | ||
137 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) | ||
138 | .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?, | ||
139 | }) | ||
140 | } | ||
141 | |||
142 | fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> { | ||
143 | let current_module = ctx.scope.module()?; | ||
144 | if let Some(dot_receiver) = &ctx.dot_receiver { | ||
145 | ImportAssets::for_fuzzy_method_call( | ||
146 | current_module, | ||
147 | ctx.sema.type_of_expr(dot_receiver)?, | ||
148 | fuzzy_name, | ||
149 | ) | ||
150 | } else { | ||
151 | let fuzzy_name_length = fuzzy_name.len(); | ||
152 | let assets_for_path = ImportAssets::for_fuzzy_path( | ||
153 | current_module, | ||
154 | ctx.path_qual.clone(), | ||
155 | fuzzy_name, | ||
156 | &ctx.sema, | ||
157 | ); | ||
158 | |||
159 | if matches!(assets_for_path.as_ref()?.import_candidate(), ImportCandidate::Path(_)) | ||
160 | && fuzzy_name_length < 2 | ||
161 | { | ||
162 | mark::hit!(ignore_short_input_for_path); | ||
163 | None | ||
164 | } else { | ||
165 | assets_for_path | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
115 | fn compute_fuzzy_completion_order_key( | 170 | fn compute_fuzzy_completion_order_key( |
116 | proposed_mod_path: &ModPath, | 171 | proposed_mod_path: &ModPath, |
117 | user_input_lowercased: &str, | 172 | user_input_lowercased: &str, |
@@ -224,6 +279,30 @@ fn main() { | |||
224 | } | 279 | } |
225 | 280 | ||
226 | #[test] | 281 | #[test] |
282 | fn short_paths_are_ignored() { | ||
283 | mark::check!(ignore_short_input_for_path); | ||
284 | |||
285 | check( | ||
286 | r#" | ||
287 | //- /lib.rs crate:dep | ||
288 | pub struct FirstStruct; | ||
289 | pub mod some_module { | ||
290 | pub struct SecondStruct; | ||
291 | pub struct ThirdStruct; | ||
292 | } | ||
293 | |||
294 | //- /main.rs crate:main deps:dep | ||
295 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
296 | |||
297 | fn main() { | ||
298 | t$0 | ||
299 | } | ||
300 | "#, | ||
301 | expect![[r#""#]], | ||
302 | ); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
227 | fn fuzzy_completions_come_in_specific_order() { | 306 | fn fuzzy_completions_come_in_specific_order() { |
228 | mark::check!(certain_fuzzy_order_test); | 307 | mark::check!(certain_fuzzy_order_test); |
229 | check( | 308 | check( |
@@ -259,6 +338,176 @@ fn main() { | |||
259 | } | 338 | } |
260 | 339 | ||
261 | #[test] | 340 | #[test] |
341 | fn trait_function_fuzzy_completion() { | ||
342 | let fixture = r#" | ||
343 | //- /lib.rs crate:dep | ||
344 | pub mod test_mod { | ||
345 | pub trait TestTrait { | ||
346 | const SPECIAL_CONST: u8; | ||
347 | type HumbleType; | ||
348 | fn weird_function(); | ||
349 | fn random_method(&self); | ||
350 | } | ||
351 | pub struct TestStruct {} | ||
352 | impl TestTrait for TestStruct { | ||
353 | const SPECIAL_CONST: u8 = 42; | ||
354 | type HumbleType = (); | ||
355 | fn weird_function() {} | ||
356 | fn random_method(&self) {} | ||
357 | } | ||
358 | } | ||
359 | |||
360 | //- /main.rs crate:main deps:dep | ||
361 | fn main() { | ||
362 | dep::test_mod::TestStruct::wei$0 | ||
363 | } | ||
364 | "#; | ||
365 | |||
366 | check( | ||
367 | fixture, | ||
368 | expect![[r#" | ||
369 | fn weird_function() (dep::test_mod::TestTrait) fn weird_function() | ||
370 | "#]], | ||
371 | ); | ||
372 | |||
373 | check_edit( | ||
374 | "weird_function", | ||
375 | fixture, | ||
376 | r#" | ||
377 | use dep::test_mod::TestTrait; | ||
378 | |||
379 | fn main() { | ||
380 | dep::test_mod::TestStruct::weird_function()$0 | ||
381 | } | ||
382 | "#, | ||
383 | ); | ||
384 | } | ||
385 | |||
386 | #[test] | ||
387 | fn trait_const_fuzzy_completion() { | ||
388 | let fixture = r#" | ||
389 | //- /lib.rs crate:dep | ||
390 | pub mod test_mod { | ||
391 | pub trait TestTrait { | ||
392 | const SPECIAL_CONST: u8; | ||
393 | type HumbleType; | ||
394 | fn weird_function(); | ||
395 | fn random_method(&self); | ||
396 | } | ||
397 | pub struct TestStruct {} | ||
398 | impl TestTrait for TestStruct { | ||
399 | const SPECIAL_CONST: u8 = 42; | ||
400 | type HumbleType = (); | ||
401 | fn weird_function() {} | ||
402 | fn random_method(&self) {} | ||
403 | } | ||
404 | } | ||
405 | |||
406 | //- /main.rs crate:main deps:dep | ||
407 | fn main() { | ||
408 | dep::test_mod::TestStruct::spe$0 | ||
409 | } | ||
410 | "#; | ||
411 | |||
412 | check( | ||
413 | fixture, | ||
414 | expect![[r#" | ||
415 | ct SPECIAL_CONST (dep::test_mod::TestTrait) | ||
416 | "#]], | ||
417 | ); | ||
418 | |||
419 | check_edit( | ||
420 | "SPECIAL_CONST", | ||
421 | fixture, | ||
422 | r#" | ||
423 | use dep::test_mod::TestTrait; | ||
424 | |||
425 | fn main() { | ||
426 | dep::test_mod::TestStruct::SPECIAL_CONST | ||
427 | } | ||
428 | "#, | ||
429 | ); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn trait_method_fuzzy_completion() { | ||
434 | let fixture = r#" | ||
435 | //- /lib.rs crate:dep | ||
436 | pub mod test_mod { | ||
437 | pub trait TestTrait { | ||
438 | const SPECIAL_CONST: u8; | ||
439 | type HumbleType; | ||
440 | fn weird_function(); | ||
441 | fn random_method(&self); | ||
442 | } | ||
443 | pub struct TestStruct {} | ||
444 | impl TestTrait for TestStruct { | ||
445 | const SPECIAL_CONST: u8 = 42; | ||
446 | type HumbleType = (); | ||
447 | fn weird_function() {} | ||
448 | fn random_method(&self) {} | ||
449 | } | ||
450 | } | ||
451 | |||
452 | //- /main.rs crate:main deps:dep | ||
453 | fn main() { | ||
454 | let test_struct = dep::test_mod::TestStruct {}; | ||
455 | test_struct.ran$0 | ||
456 | } | ||
457 | "#; | ||
458 | |||
459 | check( | ||
460 | fixture, | ||
461 | expect![[r#" | ||
462 | me random_method() (dep::test_mod::TestTrait) fn random_method(&self) | ||
463 | "#]], | ||
464 | ); | ||
465 | |||
466 | check_edit( | ||
467 | "random_method", | ||
468 | fixture, | ||
469 | r#" | ||
470 | use dep::test_mod::TestTrait; | ||
471 | |||
472 | fn main() { | ||
473 | let test_struct = dep::test_mod::TestStruct {}; | ||
474 | test_struct.random_method()$0 | ||
475 | } | ||
476 | "#, | ||
477 | ); | ||
478 | } | ||
479 | |||
480 | #[test] | ||
481 | fn no_trait_type_fuzzy_completion() { | ||
482 | check( | ||
483 | r#" | ||
484 | //- /lib.rs crate:dep | ||
485 | pub mod test_mod { | ||
486 | pub trait TestTrait { | ||
487 | const SPECIAL_CONST: u8; | ||
488 | type HumbleType; | ||
489 | fn weird_function(); | ||
490 | fn random_method(&self); | ||
491 | } | ||
492 | pub struct TestStruct {} | ||
493 | impl TestTrait for TestStruct { | ||
494 | const SPECIAL_CONST: u8 = 42; | ||
495 | type HumbleType = (); | ||
496 | fn weird_function() {} | ||
497 | fn random_method(&self) {} | ||
498 | } | ||
499 | } | ||
500 | |||
501 | //- /main.rs crate:main deps:dep | ||
502 | fn main() { | ||
503 | dep::test_mod::TestStruct::hum$0 | ||
504 | } | ||
505 | "#, | ||
506 | expect![[r#""#]], | ||
507 | ); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
262 | fn does_not_propose_names_in_scope() { | 511 | fn does_not_propose_names_in_scope() { |
263 | check( | 512 | check( |
264 | r#" | 513 | r#" |
@@ -288,4 +537,131 @@ fn main() { | |||
288 | expect![[r#""#]], | 537 | expect![[r#""#]], |
289 | ); | 538 | ); |
290 | } | 539 | } |
540 | |||
541 | #[test] | ||
542 | fn does_not_propose_traits_in_scope() { | ||
543 | check( | ||
544 | r#" | ||
545 | //- /lib.rs crate:dep | ||
546 | pub mod test_mod { | ||
547 | pub trait TestTrait { | ||
548 | const SPECIAL_CONST: u8; | ||
549 | type HumbleType; | ||
550 | fn weird_function(); | ||
551 | fn random_method(&self); | ||
552 | } | ||
553 | pub struct TestStruct {} | ||
554 | impl TestTrait for TestStruct { | ||
555 | const SPECIAL_CONST: u8 = 42; | ||
556 | type HumbleType = (); | ||
557 | fn weird_function() {} | ||
558 | fn random_method(&self) {} | ||
559 | } | ||
560 | } | ||
561 | |||
562 | //- /main.rs crate:main deps:dep | ||
563 | use dep::test_mod::{TestStruct, TestTrait}; | ||
564 | fn main() { | ||
565 | dep::test_mod::TestStruct::hum$0 | ||
566 | } | ||
567 | "#, | ||
568 | expect![[r#""#]], | ||
569 | ); | ||
570 | } | ||
571 | |||
572 | #[test] | ||
573 | fn blanket_trait_impl_import() { | ||
574 | check_edit( | ||
575 | "another_function", | ||
576 | r#" | ||
577 | //- /lib.rs crate:dep | ||
578 | pub mod test_mod { | ||
579 | pub struct TestStruct {} | ||
580 | pub trait TestTrait { | ||
581 | fn another_function(); | ||
582 | } | ||
583 | impl<T> TestTrait for T { | ||
584 | fn another_function() {} | ||
585 | } | ||
586 | } | ||
587 | |||
588 | //- /main.rs crate:main deps:dep | ||
589 | fn main() { | ||
590 | dep::test_mod::TestStruct::ano$0 | ||
591 | } | ||
592 | "#, | ||
593 | r#" | ||
594 | use dep::test_mod::TestTrait; | ||
595 | |||
596 | fn main() { | ||
597 | dep::test_mod::TestStruct::another_function()$0 | ||
598 | } | ||
599 | "#, | ||
600 | ); | ||
601 | } | ||
602 | |||
603 | #[test] | ||
604 | fn zero_input_deprecated_assoc_item_completion() { | ||
605 | check( | ||
606 | r#" | ||
607 | //- /lib.rs crate:dep | ||
608 | pub mod test_mod { | ||
609 | #[deprecated] | ||
610 | pub trait TestTrait { | ||
611 | const SPECIAL_CONST: u8; | ||
612 | type HumbleType; | ||
613 | fn weird_function(); | ||
614 | fn random_method(&self); | ||
615 | } | ||
616 | pub struct TestStruct {} | ||
617 | impl TestTrait for TestStruct { | ||
618 | const SPECIAL_CONST: u8 = 42; | ||
619 | type HumbleType = (); | ||
620 | fn weird_function() {} | ||
621 | fn random_method(&self) {} | ||
622 | } | ||
623 | } | ||
624 | |||
625 | //- /main.rs crate:main deps:dep | ||
626 | fn main() { | ||
627 | let test_struct = dep::test_mod::TestStruct {}; | ||
628 | test_struct.$0 | ||
629 | } | ||
630 | "#, | ||
631 | expect![[r#" | ||
632 | me random_method() (dep::test_mod::TestTrait) fn random_method(&self) DEPRECATED | ||
633 | "#]], | ||
634 | ); | ||
635 | |||
636 | check( | ||
637 | r#" | ||
638 | //- /lib.rs crate:dep | ||
639 | pub mod test_mod { | ||
640 | #[deprecated] | ||
641 | pub trait TestTrait { | ||
642 | const SPECIAL_CONST: u8; | ||
643 | type HumbleType; | ||
644 | fn weird_function(); | ||
645 | fn random_method(&self); | ||
646 | } | ||
647 | pub struct TestStruct {} | ||
648 | impl TestTrait for TestStruct { | ||
649 | const SPECIAL_CONST: u8 = 42; | ||
650 | type HumbleType = (); | ||
651 | fn weird_function() {} | ||
652 | fn random_method(&self) {} | ||
653 | } | ||
654 | } | ||
655 | |||
656 | //- /main.rs crate:main deps:dep | ||
657 | fn main() { | ||
658 | dep::test_mod::TestStruct::$0 | ||
659 | } | ||
660 | "#, | ||
661 | expect![[r#" | ||
662 | ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED | ||
663 | fn weird_function() (dep::test_mod::TestTrait) fn weird_function() DEPRECATED | ||
664 | "#]], | ||
665 | ); | ||
666 | } | ||
291 | } | 667 | } |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index 58fc700f3..d70ed6c1c 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -9,7 +9,7 @@ use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; | |||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
11 | pub enable_postfix_completions: bool, | 11 | pub enable_postfix_completions: bool, |
12 | pub enable_autoimport_completions: bool, | 12 | pub enable_imports_on_the_fly: bool, |
13 | pub add_call_parenthesis: bool, | 13 | pub add_call_parenthesis: bool, |
14 | pub add_call_argument_snippets: bool, | 14 | pub add_call_argument_snippets: bool, |
15 | pub snippet_cap: Option<SnippetCap>, | 15 | pub snippet_cap: Option<SnippetCap>, |
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 0134ff219..4147853e7 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -270,6 +270,7 @@ impl CompletionItem { | |||
270 | pub struct ImportEdit { | 270 | pub struct ImportEdit { |
271 | pub import_path: ModPath, | 271 | pub import_path: ModPath, |
272 | pub import_scope: ImportScope, | 272 | pub import_scope: ImportScope, |
273 | pub import_for_trait_assoc_item: bool, | ||
273 | } | 274 | } |
274 | 275 | ||
275 | impl ImportEdit { | 276 | impl ImportEdit { |
@@ -321,17 +322,19 @@ impl Builder { | |||
321 | let mut insert_text = self.insert_text; | 322 | let mut insert_text = self.insert_text; |
322 | 323 | ||
323 | if let Some(import_to_add) = self.import_to_add.as_ref() { | 324 | if let Some(import_to_add) = self.import_to_add.as_ref() { |
324 | let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); | 325 | if import_to_add.import_for_trait_assoc_item { |
325 | let _ = import_path_without_last_segment.segments.pop(); | 326 | lookup = lookup.or_else(|| Some(label.clone())); |
326 | 327 | insert_text = insert_text.or_else(|| Some(label.clone())); | |
327 | if !import_path_without_last_segment.segments.is_empty() { | 328 | label = format!("{} ({})", label, import_to_add.import_path); |
328 | if lookup.is_none() { | 329 | } else { |
329 | lookup = Some(label.clone()); | 330 | let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); |
330 | } | 331 | let _ = import_path_without_last_segment.segments.pop(); |
331 | if insert_text.is_none() { | 332 | |
332 | insert_text = Some(label.clone()); | 333 | if !import_path_without_last_segment.segments.is_empty() { |
334 | lookup = lookup.or_else(|| Some(label.clone())); | ||
335 | insert_text = insert_text.or_else(|| Some(label.clone())); | ||
336 | label = format!("{}::{}", import_path_without_last_segment, label); | ||
333 | } | 337 | } |
334 | label = format!("{}::{}", import_path_without_last_segment, label); | ||
335 | } | 338 | } |
336 | } | 339 | } |
337 | 340 | ||
@@ -398,7 +401,9 @@ impl Builder { | |||
398 | pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { | 401 | pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { |
399 | self.detail = detail.map(Into::into); | 402 | self.detail = detail.map(Into::into); |
400 | if let Some(detail) = &self.detail { | 403 | if let Some(detail) = &self.detail { |
401 | assert_never!(detail.contains('\n'), "multiline detail: {}", detail); | 404 | if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) { |
405 | self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); | ||
406 | } | ||
402 | } | 407 | } |
403 | self | 408 | self |
404 | } | 409 | } |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index ee1b822e7..2c4e54524 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -11,10 +11,10 @@ mod render; | |||
11 | 11 | ||
12 | mod completions; | 12 | mod completions; |
13 | 13 | ||
14 | use completions::flyimport::position_for_import; | ||
14 | use ide_db::{ | 15 | use ide_db::{ |
15 | base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, | 16 | base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, |
16 | }; | 17 | }; |
17 | use syntax::AstNode; | ||
18 | use text_edit::TextEdit; | 18 | use text_edit::TextEdit; |
19 | 19 | ||
20 | use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; | 20 | use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; |
@@ -139,12 +139,13 @@ pub fn resolve_completion_edits( | |||
139 | position: FilePosition, | 139 | position: FilePosition, |
140 | full_import_path: &str, | 140 | full_import_path: &str, |
141 | imported_name: String, | 141 | imported_name: String, |
142 | import_for_trait_assoc_item: bool, | ||
142 | ) -> Option<Vec<TextEdit>> { | 143 | ) -> Option<Vec<TextEdit>> { |
143 | let ctx = CompletionContext::new(db, position, config)?; | 144 | let ctx = CompletionContext::new(db, position, config)?; |
144 | let anchor = ctx.name_ref_syntax.as_ref()?; | 145 | let position_for_import = position_for_import(&ctx, None)?; |
145 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | 146 | let import_scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?; |
146 | 147 | ||
147 | let current_module = ctx.sema.scope(anchor.syntax()).module()?; | 148 | let current_module = ctx.sema.scope(position_for_import).module()?; |
148 | let current_crate = current_module.krate(); | 149 | let current_crate = current_module.krate(); |
149 | 150 | ||
150 | let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) | 151 | let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) |
@@ -154,7 +155,7 @@ pub fn resolve_completion_edits( | |||
154 | }) | 155 | }) |
155 | .find(|mod_path| mod_path.to_string() == full_import_path)?; | 156 | .find(|mod_path| mod_path.to_string() == full_import_path)?; |
156 | 157 | ||
157 | ImportEdit { import_path, import_scope } | 158 | ImportEdit { import_path, import_scope, import_for_trait_assoc_item } |
158 | .to_text_edit(config.insert_use.merge) | 159 | .to_text_edit(config.insert_use.merge) |
159 | .map(|edit| vec![edit]) | 160 | .map(|edit| vec![edit]) |
160 | } | 161 | } |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 820dd01d1..4f622d28a 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -10,7 +10,9 @@ pub(crate) mod type_alias; | |||
10 | 10 | ||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; | 13 | use hir::{ |
14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, | ||
15 | }; | ||
14 | use ide_db::{helpers::SnippetCap, RootDatabase}; | 16 | use ide_db::{helpers::SnippetCap, RootDatabase}; |
15 | use syntax::TextRange; | 17 | use syntax::TextRange; |
16 | use test_utils::mark; | 18 | use test_utils::mark; |
@@ -51,16 +53,16 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
51 | import_edit: ImportEdit, | 53 | import_edit: ImportEdit, |
52 | resolution: &ScopeDef, | 54 | resolution: &ScopeDef, |
53 | ) -> Option<CompletionItem> { | 55 | ) -> Option<CompletionItem> { |
54 | Render::new(ctx) | 56 | let local_name = match resolution { |
55 | .render_resolution( | 57 | ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), |
56 | import_edit.import_path.segments.last()?.to_string(), | 58 | ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), |
57 | Some(import_edit), | 59 | ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), |
58 | resolution, | 60 | _ => import_edit.import_path.segments.last()?.to_string(), |
59 | ) | 61 | }; |
60 | .map(|mut item| { | 62 | Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { |
61 | item.completion_kind = CompletionKind::Magic; | 63 | item.completion_kind = CompletionKind::Magic; |
62 | item | 64 | item |
63 | }) | 65 | }) |
64 | } | 66 | } |
65 | 67 | ||
66 | /// Interface for data and methods required for items rendering. | 68 | /// Interface for data and methods required for items rendering. |
@@ -87,7 +89,24 @@ impl<'a> RenderContext<'a> { | |||
87 | } | 89 | } |
88 | 90 | ||
89 | fn is_deprecated(&self, node: impl HasAttrs) -> bool { | 91 | fn is_deprecated(&self, node: impl HasAttrs) -> bool { |
90 | node.attrs(self.db()).by_key("deprecated").exists() | 92 | let attrs = node.attrs(self.db()); |
93 | attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists() | ||
94 | } | ||
95 | |||
96 | fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool { | ||
97 | let db = self.db(); | ||
98 | let assoc = match as_assoc_item.as_assoc_item(db) { | ||
99 | Some(assoc) => assoc, | ||
100 | None => return false, | ||
101 | }; | ||
102 | |||
103 | let is_assoc_deprecated = match assoc { | ||
104 | hir::AssocItem::Function(it) => self.is_deprecated(it), | ||
105 | hir::AssocItem::Const(it) => self.is_deprecated(it), | ||
106 | hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), | ||
107 | }; | ||
108 | is_assoc_deprecated | ||
109 | || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) | ||
91 | } | 110 | } |
92 | 111 | ||
93 | fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { | 112 | fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { |
@@ -206,8 +225,6 @@ impl<'a> Render<'a> { | |||
206 | } | 225 | } |
207 | }; | 226 | }; |
208 | 227 | ||
209 | let docs = self.docs(resolution); | ||
210 | |||
211 | let mut item = | 228 | let mut item = |
212 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); | 229 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); |
213 | if let ScopeDef::Local(local) = resolution { | 230 | if let ScopeDef::Local(local) = resolution { |
@@ -253,13 +270,14 @@ impl<'a> Render<'a> { | |||
253 | } | 270 | } |
254 | } | 271 | } |
255 | 272 | ||
256 | let item = item | 273 | Some( |
257 | .kind(kind) | 274 | item.kind(kind) |
258 | .add_import(import_to_add) | 275 | .add_import(import_to_add) |
259 | .set_documentation(docs) | 276 | .set_ref_match(ref_match) |
260 | .set_ref_match(ref_match) | 277 | .set_documentation(self.docs(resolution)) |
261 | .build(); | 278 | .set_deprecated(self.is_deprecated(resolution)) |
262 | Some(item) | 279 | .build(), |
280 | ) | ||
263 | } | 281 | } |
264 | 282 | ||
265 | fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { | 283 | fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { |
@@ -275,6 +293,16 @@ impl<'a> Render<'a> { | |||
275 | _ => None, | 293 | _ => None, |
276 | } | 294 | } |
277 | } | 295 | } |
296 | |||
297 | fn is_deprecated(&self, resolution: &ScopeDef) -> bool { | ||
298 | match resolution { | ||
299 | ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), | ||
300 | ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), | ||
301 | ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), | ||
302 | ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), | ||
303 | _ => false, | ||
304 | } | ||
305 | } | ||
278 | } | 306 | } |
279 | 307 | ||
280 | fn compute_score_from_active( | 308 | fn compute_score_from_active( |
@@ -485,7 +513,7 @@ fn main() { let _: m::Spam = S$0 } | |||
485 | r#" | 513 | r#" |
486 | #[deprecated] | 514 | #[deprecated] |
487 | fn something_deprecated() {} | 515 | fn something_deprecated() {} |
488 | #[deprecated(since = "1.0.0")] | 516 | #[rustc_deprecated(since = "1.0.0")] |
489 | fn something_else_deprecated() {} | 517 | fn something_else_deprecated() {} |
490 | 518 | ||
491 | fn main() { som$0 } | 519 | fn main() { som$0 } |
@@ -494,8 +522,8 @@ fn main() { som$0 } | |||
494 | [ | 522 | [ |
495 | CompletionItem { | 523 | CompletionItem { |
496 | label: "main()", | 524 | label: "main()", |
497 | source_range: 121..124, | 525 | source_range: 127..130, |
498 | delete: 121..124, | 526 | delete: 127..130, |
499 | insert: "main()$0", | 527 | insert: "main()$0", |
500 | kind: Function, | 528 | kind: Function, |
501 | lookup: "main", | 529 | lookup: "main", |
@@ -503,8 +531,8 @@ fn main() { som$0 } | |||
503 | }, | 531 | }, |
504 | CompletionItem { | 532 | CompletionItem { |
505 | label: "something_deprecated()", | 533 | label: "something_deprecated()", |
506 | source_range: 121..124, | 534 | source_range: 127..130, |
507 | delete: 121..124, | 535 | delete: 127..130, |
508 | insert: "something_deprecated()$0", | 536 | insert: "something_deprecated()$0", |
509 | kind: Function, | 537 | kind: Function, |
510 | lookup: "something_deprecated", | 538 | lookup: "something_deprecated", |
@@ -513,8 +541,8 @@ fn main() { som$0 } | |||
513 | }, | 541 | }, |
514 | CompletionItem { | 542 | CompletionItem { |
515 | label: "something_else_deprecated()", | 543 | label: "something_else_deprecated()", |
516 | source_range: 121..124, | 544 | source_range: 127..130, |
517 | delete: 121..124, | 545 | delete: 127..130, |
518 | insert: "something_else_deprecated()$0", | 546 | insert: "something_else_deprecated()$0", |
519 | kind: Function, | 547 | kind: Function, |
520 | lookup: "something_else_deprecated", | 548 | lookup: "something_else_deprecated", |
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs index ce924f309..e46452d4e 100644 --- a/crates/completion/src/render/const_.rs +++ b/crates/completion/src/render/const_.rs | |||
@@ -38,7 +38,10 @@ impl<'a> ConstRender<'a> { | |||
38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) | 38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) |
39 | .kind(CompletionItemKind::Const) | 39 | .kind(CompletionItemKind::Const) |
40 | .set_documentation(self.ctx.docs(self.const_)) | 40 | .set_documentation(self.ctx.docs(self.const_)) |
41 | .set_deprecated(self.ctx.is_deprecated(self.const_)) | 41 | .set_deprecated( |
42 | self.ctx.is_deprecated(self.const_) | ||
43 | || self.ctx.is_deprecated_assoc_item(self.const_), | ||
44 | ) | ||
42 | .detail(detail) | 45 | .detail(detail) |
43 | .build(); | 46 | .build(); |
44 | 47 | ||
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index f5b0ce3e3..8f4c66211 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -44,7 +44,9 @@ impl<'a> FunctionRender<'a> { | |||
44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
45 | .kind(self.kind()) | 45 | .kind(self.kind()) |
46 | .set_documentation(self.ctx.docs(self.func)) | 46 | .set_documentation(self.ctx.docs(self.func)) |
47 | .set_deprecated(self.ctx.is_deprecated(self.func)) | 47 | .set_deprecated( |
48 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), | ||
49 | ) | ||
48 | .detail(self.detail()) | 50 | .detail(self.detail()) |
49 | .add_call_parens(self.ctx.completion, self.name, params) | 51 | .add_call_parens(self.ctx.completion, self.name, params) |
50 | .add_import(import_to_add) | 52 | .add_import(import_to_add) |
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs index 69b445b9c..29287143a 100644 --- a/crates/completion/src/render/type_alias.rs +++ b/crates/completion/src/render/type_alias.rs | |||
@@ -38,7 +38,10 @@ impl<'a> TypeAliasRender<'a> { | |||
38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) | 38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) |
39 | .kind(CompletionItemKind::TypeAlias) | 39 | .kind(CompletionItemKind::TypeAlias) |
40 | .set_documentation(self.ctx.docs(self.type_alias)) | 40 | .set_documentation(self.ctx.docs(self.type_alias)) |
41 | .set_deprecated(self.ctx.is_deprecated(self.type_alias)) | 41 | .set_deprecated( |
42 | self.ctx.is_deprecated(self.type_alias) | ||
43 | || self.ctx.is_deprecated_assoc_item(self.type_alias), | ||
44 | ) | ||
42 | .detail(detail) | 45 | .detail(detail) |
43 | .build(); | 46 | .build(); |
44 | 47 | ||
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs index 6ea6da989..baff83305 100644 --- a/crates/completion/src/test_utils.rs +++ b/crates/completion/src/test_utils.rs | |||
@@ -18,7 +18,7 @@ use crate::{item::CompletionKind, CompletionConfig, CompletionItem}; | |||
18 | 18 | ||
19 | pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | 19 | pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { |
20 | enable_postfix_completions: true, | 20 | enable_postfix_completions: true, |
21 | enable_autoimport_completions: true, | 21 | enable_imports_on_the_fly: true, |
22 | add_call_parenthesis: true, | 22 | add_call_parenthesis: true, |
23 | add_call_argument_snippets: true, | 23 | add_call_argument_snippets: true, |
24 | snippet_cap: SnippetCap::new(true), | 24 | snippet_cap: SnippetCap::new(true), |
@@ -83,6 +83,9 @@ pub(crate) fn completion_list_with_config( | |||
83 | let width = label_width.saturating_sub(monospace_width(it.label())); | 83 | let width = label_width.saturating_sub(monospace_width(it.label())); |
84 | format_to!(buf, "{:width$} {}", "", detail, width = width); | 84 | format_to!(buf, "{:width$} {}", "", detail, width = width); |
85 | } | 85 | } |
86 | if it.deprecated() { | ||
87 | format_to!(buf, " DEPRECATED"); | ||
88 | } | ||
86 | format_to!(buf, "\n"); | 89 | format_to!(buf, "\n"); |
87 | buf | 90 | buf |
88 | }) | 91 | }) |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 6cbf5cecf..5a4c27906 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -1051,6 +1051,16 @@ impl AsAssocItem for TypeAlias { | |||
1051 | as_assoc_item(db, AssocItem::TypeAlias, self.id) | 1051 | as_assoc_item(db, AssocItem::TypeAlias, self.id) |
1052 | } | 1052 | } |
1053 | } | 1053 | } |
1054 | impl AsAssocItem for ModuleDef { | ||
1055 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1056 | match self { | ||
1057 | ModuleDef::Function(it) => it.as_assoc_item(db), | ||
1058 | ModuleDef::Const(it) => it.as_assoc_item(db), | ||
1059 | ModuleDef::TypeAlias(it) => it.as_assoc_item(db), | ||
1060 | _ => None, | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1054 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> | 1064 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> |
1055 | where | 1065 | where |
1056 | ID: Lookup<Data = AssocItemLoc<AST>>, | 1066 | ID: Lookup<Data = AssocItemLoc<AST>>, |
@@ -1091,6 +1101,13 @@ impl AssocItem { | |||
1091 | AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), | 1101 | AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), |
1092 | } | 1102 | } |
1093 | } | 1103 | } |
1104 | |||
1105 | pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1106 | match self.container(db) { | ||
1107 | AssocItemContainer::Trait(t) => Some(t), | ||
1108 | _ => None, | ||
1109 | } | ||
1110 | } | ||
1094 | } | 1111 | } |
1095 | 1112 | ||
1096 | impl HasVisibility for AssocItem { | 1113 | impl HasVisibility for AssocItem { |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 344f0b6c0..3b2dd0f6e 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -29,7 +29,7 @@ use crate::{ | |||
29 | expr::{Expr, ExprId, Label, LabelId, Pat, PatId}, | 29 | expr::{Expr, ExprId, Label, LabelId, Pat, PatId}, |
30 | item_scope::BuiltinShadowMode, | 30 | item_scope::BuiltinShadowMode, |
31 | item_scope::ItemScope, | 31 | item_scope::ItemScope, |
32 | nameres::CrateDefMap, | 32 | nameres::DefMap, |
33 | path::{ModPath, Path}, | 33 | path::{ModPath, Path}, |
34 | src::HasSource, | 34 | src::HasSource, |
35 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 35 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
@@ -45,7 +45,7 @@ pub(crate) struct CfgExpander { | |||
45 | 45 | ||
46 | pub(crate) struct Expander { | 46 | pub(crate) struct Expander { |
47 | cfg_expander: CfgExpander, | 47 | cfg_expander: CfgExpander, |
48 | crate_def_map: Arc<CrateDefMap>, | 48 | crate_def_map: Arc<DefMap>, |
49 | current_file_id: HirFileId, | 49 | current_file_id: HirFileId, |
50 | ast_id_map: Arc<AstIdMap>, | 50 | ast_id_map: Arc<AstIdMap>, |
51 | module: ModuleId, | 51 | module: ModuleId, |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 6ef9fe790..91c8d45cd 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | import_map::ImportMap, | 15 | import_map::ImportMap, |
16 | item_tree::ItemTree, | 16 | item_tree::ItemTree, |
17 | lang_item::{LangItemTarget, LangItems}, | 17 | lang_item::{LangItemTarget, LangItems}, |
18 | nameres::CrateDefMap, | 18 | nameres::DefMap, |
19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
20 | GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, | 20 | GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, |
21 | StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, | 21 | StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, |
@@ -50,10 +50,10 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
50 | 50 | ||
51 | #[salsa::invoke(crate_def_map_wait)] | 51 | #[salsa::invoke(crate_def_map_wait)] |
52 | #[salsa::transparent] | 52 | #[salsa::transparent] |
53 | fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; | 53 | fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>; |
54 | 54 | ||
55 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | 55 | #[salsa::invoke(DefMap::crate_def_map_query)] |
56 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<CrateDefMap>; | 56 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>; |
57 | 57 | ||
58 | #[salsa::invoke(StructData::struct_data_query)] | 58 | #[salsa::invoke(StructData::struct_data_query)] |
59 | fn struct_data(&self, id: StructId) -> Arc<StructData>; | 59 | fn struct_data(&self, id: StructId) -> Arc<StructData>; |
@@ -112,7 +112,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
112 | fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; | 112 | fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; |
113 | } | 113 | } |
114 | 114 | ||
115 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 115 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<DefMap> { |
116 | let _p = profile::span("crate_def_map:wait"); | 116 | let _p = profile::span("crate_def_map:wait"); |
117 | db.crate_def_map_query(krate) | 117 | db.crate_def_map_query(krate) |
118 | } | 118 | } |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index 4a212d291..422a6eeb4 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -4,7 +4,7 @@ use hir_expand::name::{known, AsName, Name}; | |||
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use test_utils::mark; | 5 | use test_utils::mark; |
6 | 6 | ||
7 | use crate::nameres::CrateDefMap; | 7 | use crate::nameres::DefMap; |
8 | use crate::{ | 8 | use crate::{ |
9 | db::DefDatabase, | 9 | db::DefDatabase, |
10 | item_scope::ItemInNs, | 10 | item_scope::ItemInNs, |
@@ -47,7 +47,7 @@ impl ModPath { | |||
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | fn check_self_super(def_map: &CrateDefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 50 | fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
51 | if item == ItemInNs::Types(from.into()) { | 51 | if item == ItemInNs::Types(from.into()) { |
52 | // - if the item is the module we're in, use `self` | 52 | // - if the item is the module we're in, use `self` |
53 | Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) | 53 | Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index e5368b293..fac0de90c 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -263,6 +263,7 @@ pub enum ImportKind { | |||
263 | Trait, | 263 | Trait, |
264 | TypeAlias, | 264 | TypeAlias, |
265 | BuiltinType, | 265 | BuiltinType, |
266 | AssociatedItem, | ||
266 | } | 267 | } |
267 | 268 | ||
268 | /// A way to match import map contents against the search query. | 269 | /// A way to match import map contents against the search query. |
@@ -282,6 +283,7 @@ pub struct Query { | |||
282 | query: String, | 283 | query: String, |
283 | lowercased: String, | 284 | lowercased: String, |
284 | name_only: bool, | 285 | name_only: bool, |
286 | assoc_items_only: bool, | ||
285 | search_mode: SearchMode, | 287 | search_mode: SearchMode, |
286 | case_sensitive: bool, | 288 | case_sensitive: bool, |
287 | limit: usize, | 289 | limit: usize, |
@@ -295,6 +297,7 @@ impl Query { | |||
295 | query, | 297 | query, |
296 | lowercased, | 298 | lowercased, |
297 | name_only: false, | 299 | name_only: false, |
300 | assoc_items_only: false, | ||
298 | search_mode: SearchMode::Contains, | 301 | search_mode: SearchMode::Contains, |
299 | case_sensitive: false, | 302 | case_sensitive: false, |
300 | limit: usize::max_value(), | 303 | limit: usize::max_value(), |
@@ -309,6 +312,11 @@ impl Query { | |||
309 | Self { name_only: true, ..self } | 312 | Self { name_only: true, ..self } |
310 | } | 313 | } |
311 | 314 | ||
315 | /// Matches only the entries that are associated items, ignoring the rest. | ||
316 | pub fn assoc_items_only(self) -> Self { | ||
317 | Self { assoc_items_only: true, ..self } | ||
318 | } | ||
319 | |||
312 | /// Specifies the way to search for the entries using the query. | 320 | /// Specifies the way to search for the entries using the query. |
313 | pub fn search_mode(self, search_mode: SearchMode) -> Self { | 321 | pub fn search_mode(self, search_mode: SearchMode) -> Self { |
314 | Self { search_mode, ..self } | 322 | Self { search_mode, ..self } |
@@ -331,6 +339,14 @@ impl Query { | |||
331 | } | 339 | } |
332 | 340 | ||
333 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { | 341 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { |
342 | if import.is_trait_assoc_item { | ||
343 | if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { | ||
344 | return false; | ||
345 | } | ||
346 | } else if self.assoc_items_only { | ||
347 | return false; | ||
348 | } | ||
349 | |||
334 | let mut input = if import.is_trait_assoc_item || self.name_only { | 350 | let mut input = if import.is_trait_assoc_item || self.name_only { |
335 | import.path.segments.last().unwrap().to_string() | 351 | import.path.segments.last().unwrap().to_string() |
336 | } else { | 352 | } else { |
@@ -814,6 +830,56 @@ mod tests { | |||
814 | } | 830 | } |
815 | 831 | ||
816 | #[test] | 832 | #[test] |
833 | fn assoc_items_filtering() { | ||
834 | let ra_fixture = r#" | ||
835 | //- /main.rs crate:main deps:dep | ||
836 | //- /dep.rs crate:dep | ||
837 | pub mod fmt { | ||
838 | pub trait Display { | ||
839 | type FmtTypeAlias; | ||
840 | const FMT_CONST: bool; | ||
841 | |||
842 | fn format_function(); | ||
843 | fn format_method(&self); | ||
844 | } | ||
845 | } | ||
846 | "#; | ||
847 | |||
848 | check_search( | ||
849 | ra_fixture, | ||
850 | "main", | ||
851 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(), | ||
852 | expect![[r#" | ||
853 | dep::fmt::Display::FMT_CONST (a) | ||
854 | dep::fmt::Display::format_function (a) | ||
855 | dep::fmt::Display::format_method (a) | ||
856 | "#]], | ||
857 | ); | ||
858 | |||
859 | check_search( | ||
860 | ra_fixture, | ||
861 | "main", | ||
862 | Query::new("fmt".to_string()) | ||
863 | .search_mode(SearchMode::Fuzzy) | ||
864 | .exclude_import_kind(ImportKind::AssociatedItem), | ||
865 | expect![[r#" | ||
866 | dep::fmt (t) | ||
867 | dep::fmt::Display (t) | ||
868 | "#]], | ||
869 | ); | ||
870 | |||
871 | check_search( | ||
872 | ra_fixture, | ||
873 | "main", | ||
874 | Query::new("fmt".to_string()) | ||
875 | .search_mode(SearchMode::Fuzzy) | ||
876 | .assoc_items_only() | ||
877 | .exclude_import_kind(ImportKind::AssociatedItem), | ||
878 | expect![[r#""#]], | ||
879 | ); | ||
880 | } | ||
881 | |||
882 | #[test] | ||
817 | fn search_mode() { | 883 | fn search_mode() { |
818 | let ra_fixture = r#" | 884 | let ra_fixture = r#" |
819 | //- /main.rs crate:main deps:dep | 885 | //- /main.rs crate:main deps:dep |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 9a433b61c..ff62928df 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -145,7 +145,6 @@ impl ItemTree { | |||
145 | macro_calls, | 145 | macro_calls, |
146 | macro_rules, | 146 | macro_rules, |
147 | macro_defs, | 147 | macro_defs, |
148 | exprs, | ||
149 | vis, | 148 | vis, |
150 | generics, | 149 | generics, |
151 | } = &mut **data; | 150 | } = &mut **data; |
@@ -167,7 +166,6 @@ impl ItemTree { | |||
167 | macro_calls.shrink_to_fit(); | 166 | macro_calls.shrink_to_fit(); |
168 | macro_rules.shrink_to_fit(); | 167 | macro_rules.shrink_to_fit(); |
169 | macro_defs.shrink_to_fit(); | 168 | macro_defs.shrink_to_fit(); |
170 | exprs.shrink_to_fit(); | ||
171 | 169 | ||
172 | vis.arena.shrink_to_fit(); | 170 | vis.arena.shrink_to_fit(); |
173 | generics.arena.shrink_to_fit(); | 171 | generics.arena.shrink_to_fit(); |
@@ -296,7 +294,6 @@ struct ItemTreeData { | |||
296 | macro_calls: Arena<MacroCall>, | 294 | macro_calls: Arena<MacroCall>, |
297 | macro_rules: Arena<MacroRules>, | 295 | macro_rules: Arena<MacroRules>, |
298 | macro_defs: Arena<MacroDef>, | 296 | macro_defs: Arena<MacroDef>, |
299 | exprs: Arena<Expr>, | ||
300 | 297 | ||
301 | vis: ItemVisibilities, | 298 | vis: ItemVisibilities, |
302 | generics: GenericParamsStorage, | 299 | generics: GenericParamsStorage, |
@@ -461,7 +458,7 @@ macro_rules! impl_index { | |||
461 | }; | 458 | }; |
462 | } | 459 | } |
463 | 460 | ||
464 | impl_index!(fields: Field, variants: Variant, exprs: Expr); | 461 | impl_index!(fields: Field, variants: Variant); |
465 | 462 | ||
466 | impl Index<RawVisibilityId> for ItemTree { | 463 | impl Index<RawVisibilityId> for ItemTree { |
467 | type Output = RawVisibility; | 464 | type Output = RawVisibility; |
@@ -664,11 +661,6 @@ pub struct MacroDef { | |||
664 | pub ast_id: FileAstId<ast::MacroDef>, | 661 | pub ast_id: FileAstId<ast::MacroDef>, |
665 | } | 662 | } |
666 | 663 | ||
667 | // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array | ||
668 | // lengths, but we don't do much with them yet. | ||
669 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
670 | pub struct Expr; | ||
671 | |||
672 | macro_rules! impl_froms { | 664 | macro_rules! impl_froms { |
673 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | 665 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { |
674 | $( | 666 | $( |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 50acc3f54..769a557ad 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -74,7 +74,7 @@ use crate::{ | |||
74 | 74 | ||
75 | /// Contains all top-level defs from a macro-expanded crate | 75 | /// Contains all top-level defs from a macro-expanded crate |
76 | #[derive(Debug, PartialEq, Eq)] | 76 | #[derive(Debug, PartialEq, Eq)] |
77 | pub struct CrateDefMap { | 77 | pub struct DefMap { |
78 | pub root: LocalModuleId, | 78 | pub root: LocalModuleId, |
79 | pub modules: Arena<ModuleData>, | 79 | pub modules: Arena<ModuleData>, |
80 | pub(crate) krate: CrateId, | 80 | pub(crate) krate: CrateId, |
@@ -88,7 +88,7 @@ pub struct CrateDefMap { | |||
88 | diagnostics: Vec<DefDiagnostic>, | 88 | diagnostics: Vec<DefDiagnostic>, |
89 | } | 89 | } |
90 | 90 | ||
91 | impl std::ops::Index<LocalModuleId> for CrateDefMap { | 91 | impl std::ops::Index<LocalModuleId> for DefMap { |
92 | type Output = ModuleData; | 92 | type Output = ModuleData; |
93 | fn index(&self, id: LocalModuleId) -> &ModuleData { | 93 | fn index(&self, id: LocalModuleId) -> &ModuleData { |
94 | &self.modules[id] | 94 | &self.modules[id] |
@@ -169,8 +169,8 @@ pub struct ModuleData { | |||
169 | pub origin: ModuleOrigin, | 169 | pub origin: ModuleOrigin, |
170 | } | 170 | } |
171 | 171 | ||
172 | impl CrateDefMap { | 172 | impl DefMap { |
173 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 173 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { |
174 | let _p = profile::span("crate_def_map_query").detail(|| { | 174 | let _p = profile::span("crate_def_map_query").detail(|| { |
175 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() | 175 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() |
176 | }); | 176 | }); |
@@ -178,7 +178,7 @@ impl CrateDefMap { | |||
178 | let edition = db.crate_graph()[krate].edition; | 178 | let edition = db.crate_graph()[krate].edition; |
179 | let mut modules: Arena<ModuleData> = Arena::default(); | 179 | let mut modules: Arena<ModuleData> = Arena::default(); |
180 | let root = modules.alloc(ModuleData::default()); | 180 | let root = modules.alloc(ModuleData::default()); |
181 | CrateDefMap { | 181 | DefMap { |
182 | krate, | 182 | krate, |
183 | edition, | 183 | edition, |
184 | extern_prelude: FxHashMap::default(), | 184 | extern_prelude: FxHashMap::default(), |
@@ -227,7 +227,7 @@ impl CrateDefMap { | |||
227 | go(&mut buf, self, "crate", self.root); | 227 | go(&mut buf, self, "crate", self.root); |
228 | return buf; | 228 | return buf; |
229 | 229 | ||
230 | fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { | 230 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { |
231 | format_to!(buf, "{}\n", path); | 231 | format_to!(buf, "{}\n", path); |
232 | 232 | ||
233 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); | 233 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 0cd61698c..61da56340 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | }, | 31 | }, |
32 | nameres::{ | 32 | nameres::{ |
33 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 33 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
34 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, | 34 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, |
35 | }, | 35 | }, |
36 | path::{ImportAlias, ModPath, PathKind}, | 36 | path::{ImportAlias, ModPath, PathKind}, |
37 | per_ns::PerNs, | 37 | per_ns::PerNs, |
@@ -45,7 +45,7 @@ const GLOB_RECURSION_LIMIT: usize = 100; | |||
45 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 45 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
46 | const FIXED_POINT_LIMIT: usize = 8192; | 46 | const FIXED_POINT_LIMIT: usize = 8192; |
47 | 47 | ||
48 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 48 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap { |
49 | let crate_graph = db.crate_graph(); | 49 | let crate_graph = db.crate_graph(); |
50 | 50 | ||
51 | // populate external prelude | 51 | // populate external prelude |
@@ -210,7 +210,7 @@ struct DefData<'a> { | |||
210 | /// Walks the tree of module recursively | 210 | /// Walks the tree of module recursively |
211 | struct DefCollector<'a> { | 211 | struct DefCollector<'a> { |
212 | db: &'a dyn DefDatabase, | 212 | db: &'a dyn DefDatabase, |
213 | def_map: CrateDefMap, | 213 | def_map: DefMap, |
214 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, | 214 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, |
215 | unresolved_imports: Vec<ImportDirective>, | 215 | unresolved_imports: Vec<ImportDirective>, |
216 | resolved_imports: Vec<ImportDirective>, | 216 | resolved_imports: Vec<ImportDirective>, |
@@ -859,7 +859,7 @@ impl DefCollector<'_> { | |||
859 | .collect(item_tree.top_level_items()); | 859 | .collect(item_tree.top_level_items()); |
860 | } | 860 | } |
861 | 861 | ||
862 | fn finish(mut self) -> CrateDefMap { | 862 | fn finish(mut self) -> DefMap { |
863 | // Emit diagnostics for all remaining unexpanded macros. | 863 | // Emit diagnostics for all remaining unexpanded macros. |
864 | 864 | ||
865 | for directive in &self.unexpanded_macros { | 865 | for directive in &self.unexpanded_macros { |
@@ -1474,7 +1474,7 @@ mod tests { | |||
1474 | 1474 | ||
1475 | use super::*; | 1475 | use super::*; |
1476 | 1476 | ||
1477 | fn do_collect_defs(db: &dyn DefDatabase, def_map: CrateDefMap) -> CrateDefMap { | 1477 | fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap { |
1478 | let mut collector = DefCollector { | 1478 | let mut collector = DefCollector { |
1479 | db, | 1479 | db, |
1480 | def_map, | 1480 | def_map, |
@@ -1493,7 +1493,7 @@ mod tests { | |||
1493 | collector.def_map | 1493 | collector.def_map |
1494 | } | 1494 | } |
1495 | 1495 | ||
1496 | fn do_resolve(code: &str) -> CrateDefMap { | 1496 | fn do_resolve(code: &str) -> DefMap { |
1497 | let (db, _file_id) = TestDB::with_single_file(&code); | 1497 | let (db, _file_id) = TestDB::with_single_file(&code); |
1498 | let krate = db.test_crate(); | 1498 | let krate = db.test_crate(); |
1499 | 1499 | ||
@@ -1501,7 +1501,7 @@ mod tests { | |||
1501 | let edition = db.crate_graph()[krate].edition; | 1501 | let edition = db.crate_graph()[krate].edition; |
1502 | let mut modules: Arena<ModuleData> = Arena::default(); | 1502 | let mut modules: Arena<ModuleData> = Arena::default(); |
1503 | let root = modules.alloc(ModuleData::default()); | 1503 | let root = modules.alloc(ModuleData::default()); |
1504 | CrateDefMap { | 1504 | DefMap { |
1505 | krate, | 1505 | krate, |
1506 | edition, | 1506 | edition, |
1507 | extern_prelude: FxHashMap::default(), | 1507 | extern_prelude: FxHashMap::default(), |
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index 88e10574e..096a7d0ac 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -19,7 +19,7 @@ use test_utils::mark; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | db::DefDatabase, | 20 | db::DefDatabase, |
21 | item_scope::BUILTIN_SCOPE, | 21 | item_scope::BUILTIN_SCOPE, |
22 | nameres::{BuiltinShadowMode, CrateDefMap}, | 22 | nameres::{BuiltinShadowMode, DefMap}, |
23 | path::{ModPath, PathKind}, | 23 | path::{ModPath, PathKind}, |
24 | per_ns::PerNs, | 24 | per_ns::PerNs, |
25 | visibility::{RawVisibility, Visibility}, | 25 | visibility::{RawVisibility, Visibility}, |
@@ -61,7 +61,7 @@ impl ResolvePathResult { | |||
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
64 | impl CrateDefMap { | 64 | impl DefMap { |
65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | 65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { |
66 | self.extern_prelude | 66 | self.extern_prelude |
67 | .get(name) | 67 | .get(name) |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index c459fa66d..723481c36 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -13,7 +13,7 @@ use test_utils::mark; | |||
13 | 13 | ||
14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; |
15 | 15 | ||
16 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<CrateDefMap> { | 16 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { |
17 | let db = TestDB::with_files(ra_fixture); | 17 | let db = TestDB::with_files(ra_fixture); |
18 | let krate = db.crate_graph().iter().next().unwrap(); | 18 | let krate = db.crate_graph().iter().next().unwrap(); |
19 | db.crate_def_map(krate) | 19 | db.crate_def_map(krate) |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 3dd7c3cbb..e34cd7f2f 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -87,7 +87,7 @@ impl ModPath { | |||
87 | 87 | ||
88 | /// If this path is a single identifier, like `foo`, return its name. | 88 | /// If this path is a single identifier, like `foo`, return its name. |
89 | pub fn as_ident(&self) -> Option<&Name> { | 89 | pub fn as_ident(&self) -> Option<&Name> { |
90 | if self.kind != PathKind::Plain || self.segments.len() > 1 { | 90 | if !self.is_ident() { |
91 | return None; | 91 | return None; |
92 | } | 92 | } |
93 | self.segments.first() | 93 | self.segments.first() |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 85ddc2c47..e7e92c72d 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | expr::{ExprId, PatId}, | 16 | expr::{ExprId, PatId}, |
17 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, | 18 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, |
19 | nameres::CrateDefMap, | 19 | nameres::DefMap, |
20 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 21 | per_ns::PerNs, |
22 | visibility::{RawVisibility, Visibility}, | 22 | visibility::{RawVisibility, Visibility}, |
@@ -34,7 +34,7 @@ pub struct Resolver { | |||
34 | // FIXME how to store these best | 34 | // FIXME how to store these best |
35 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone)] |
36 | struct ModuleItemMap { | 36 | struct ModuleItemMap { |
37 | crate_def_map: Arc<CrateDefMap>, | 37 | crate_def_map: Arc<DefMap>, |
38 | module_id: LocalModuleId, | 38 | module_id: LocalModuleId, |
39 | } | 39 | } |
40 | 40 | ||
@@ -425,7 +425,7 @@ impl Resolver { | |||
425 | traits | 425 | traits |
426 | } | 426 | } |
427 | 427 | ||
428 | fn module_scope(&self) -> Option<(&CrateDefMap, LocalModuleId)> { | 428 | fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> { |
429 | self.scopes.iter().rev().find_map(|scope| match scope { | 429 | self.scopes.iter().rev().find_map(|scope| match scope { |
430 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), | 430 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), |
431 | 431 | ||
@@ -588,11 +588,7 @@ impl Resolver { | |||
588 | self.push_scope(Scope::ImplDefScope(impl_def)) | 588 | self.push_scope(Scope::ImplDefScope(impl_def)) |
589 | } | 589 | } |
590 | 590 | ||
591 | fn push_module_scope( | 591 | fn push_module_scope(self, crate_def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver { |
592 | self, | ||
593 | crate_def_map: Arc<CrateDefMap>, | ||
594 | module_id: LocalModuleId, | ||
595 | ) -> Resolver { | ||
596 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) | 592 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) |
597 | } | 593 | } |
598 | 594 | ||
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index ae93d0d10..049b2e462 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -159,6 +159,8 @@ impl TypeRef { | |||
159 | ast::Type::DynTraitType(inner) => { | 159 | ast::Type::DynTraitType(inner) => { |
160 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) | 160 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
161 | } | 161 | } |
162 | // FIXME: Macros in type position are not yet supported. | ||
163 | ast::Type::MacroType(_) => TypeRef::Error, | ||
162 | } | 164 | } |
163 | } | 165 | } |
164 | 166 | ||
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index f3bc9d680..3134fa43d 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -5,7 +5,7 @@ use syntax::ast; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | nameres::CrateDefMap, | 8 | nameres::DefMap, |
9 | path::{ModPath, PathKind}, | 9 | path::{ModPath, PathKind}, |
10 | ModuleId, | 10 | ModuleId, |
11 | }; | 11 | }; |
@@ -116,7 +116,7 @@ impl Visibility { | |||
116 | 116 | ||
117 | pub(crate) fn is_visible_from_def_map( | 117 | pub(crate) fn is_visible_from_def_map( |
118 | self, | 118 | self, |
119 | def_map: &CrateDefMap, | 119 | def_map: &DefMap, |
120 | from_module: crate::LocalModuleId, | 120 | from_module: crate::LocalModuleId, |
121 | ) -> bool { | 121 | ) -> bool { |
122 | let to_module = match self { | 122 | let to_module = match self { |
@@ -135,7 +135,7 @@ impl Visibility { | |||
135 | /// | 135 | /// |
136 | /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only | 136 | /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only |
137 | /// visible in unrelated modules). | 137 | /// visible in unrelated modules). |
138 | pub(crate) fn max(self, other: Visibility, def_map: &CrateDefMap) -> Option<Visibility> { | 138 | pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { |
139 | match (self, other) { | 139 | match (self, other) { |
140 | (Visibility::Module(_), Visibility::Public) | 140 | (Visibility::Module(_), Visibility::Public) |
141 | | (Visibility::Public, Visibility::Module(_)) | 141 | | (Visibility::Public, Visibility::Module(_)) |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 8db581b77..c8ea81210 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -76,6 +76,8 @@ pub struct HygieneFrame { | |||
76 | 76 | ||
77 | impl HygieneFrames { | 77 | impl HygieneFrames { |
78 | fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { | 78 | fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { |
79 | // Note that this intentionally avoids the `hygiene_frame` query to avoid blowing up memory | ||
80 | // usage. The query is only helpful for nested `HygieneFrame`s as it avoids redundant work. | ||
79 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) | 81 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) |
80 | } | 82 | } |
81 | 83 | ||
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 1923daca5..75e950816 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -135,7 +135,6 @@ mod tests { | |||
135 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); | 135 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); |
136 | 136 | ||
137 | assert_eq_text!( | 137 | assert_eq_text!( |
138 | &result, | ||
139 | r#" | 138 | r#" |
140 | SUBTREE $ | 139 | SUBTREE $ |
141 | PUNCH # [alone] 0 | 140 | PUNCH # [alone] 0 |
@@ -150,7 +149,8 @@ SUBTREE $ | |||
150 | PUNCH : [alone] 19 | 149 | PUNCH : [alone] 19 |
151 | IDENT u32 20 | 150 | IDENT u32 20 |
152 | "# | 151 | "# |
153 | .trim() | 152 | .trim(), |
153 | &result | ||
154 | ); | 154 | ); |
155 | } | 155 | } |
156 | } | 156 | } |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 3b1675f0b..4a3fcea8d 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -18,7 +18,7 @@ use hir_def::{ | |||
18 | db::DefDatabase, | 18 | db::DefDatabase, |
19 | item_scope::ItemScope, | 19 | item_scope::ItemScope, |
20 | keys, | 20 | keys, |
21 | nameres::CrateDefMap, | 21 | nameres::DefMap, |
22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
23 | }; | 23 | }; |
24 | use hir_expand::{db::AstDatabase, InFile}; | 24 | use hir_expand::{db::AstDatabase, InFile}; |
@@ -26,7 +26,7 @@ use once_cell::race::OnceBool; | |||
26 | use stdx::format_to; | 26 | use stdx::format_to; |
27 | use syntax::{ | 27 | use syntax::{ |
28 | algo, | 28 | algo, |
29 | ast::{self, AstNode}, | 29 | ast::{self, AstNode, NameOwner}, |
30 | SyntaxNode, | 30 | SyntaxNode, |
31 | }; | 31 | }; |
32 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | 32 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; |
@@ -153,7 +153,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
153 | }); | 153 | }); |
154 | for (node, ty) in &types { | 154 | for (node, ty) in &types { |
155 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { | 155 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { |
156 | (self_param.self_token().unwrap().text_range(), "self".to_string()) | 156 | (self_param.name().unwrap().syntax().text_range(), "self".to_string()) |
157 | } else { | 157 | } else { |
158 | (node.value.text_range(), node.value.text().to_string().replace("\n", " ")) | 158 | (node.value.text_range(), node.value.text().to_string().replace("\n", " ")) |
159 | }; | 159 | }; |
@@ -221,7 +221,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
221 | 221 | ||
222 | fn visit_module( | 222 | fn visit_module( |
223 | db: &TestDB, | 223 | db: &TestDB, |
224 | crate_def_map: &CrateDefMap, | 224 | crate_def_map: &DefMap, |
225 | module_id: LocalModuleId, | 225 | module_id: LocalModuleId, |
226 | cb: &mut dyn FnMut(DefWithBodyId), | 226 | cb: &mut dyn FnMut(DefWithBodyId), |
227 | ) { | 227 | ) { |
@@ -249,7 +249,7 @@ fn visit_module( | |||
249 | 249 | ||
250 | fn visit_scope( | 250 | fn visit_scope( |
251 | db: &TestDB, | 251 | db: &TestDB, |
252 | crate_def_map: &CrateDefMap, | 252 | crate_def_map: &DefMap, |
253 | scope: &ItemScope, | 253 | scope: &ItemScope, |
254 | cb: &mut dyn FnMut(DefWithBodyId), | 254 | cb: &mut dyn FnMut(DefWithBodyId), |
255 | ) { | 255 | ) { |
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index e8999a7f3..b10a0a78b 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -47,7 +47,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
47 | 47 | ||
48 | let mut calls = CallLocations::default(); | 48 | let mut calls = CallLocations::default(); |
49 | 49 | ||
50 | for (&file_id, references) in refs.info.references().iter() { | 50 | for (&file_id, references) in refs.references().iter() { |
51 | let file = sema.parse(file_id); | 51 | let file = sema.parse(file_id); |
52 | let file = file.syntax(); | 52 | let file = file.syntax(); |
53 | for reference in references { | 53 | for reference in references { |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index e4335119b..579d5a308 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -140,7 +140,7 @@ impl DiagnosticWithFix for IncorrectCase { | |||
140 | rename_with_semantics(sema, file_position, &self.suggested_text).ok()?; | 140 | rename_with_semantics(sema, file_position, &self.suggested_text).ok()?; |
141 | 141 | ||
142 | let label = format!("Rename to {}", self.suggested_text); | 142 | let label = format!("Rename to {}", self.suggested_text); |
143 | Some(Fix::new(&label, rename_changes.info, rename_changes.range)) | 143 | Some(Fix::new(&label, rename_changes, frange.range)) |
144 | } | 144 | } |
145 | } | 145 | } |
146 | 146 | ||
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 685052e7f..00e601244 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -400,15 +400,13 @@ impl TryToNav for hir::GenericParam { | |||
400 | impl ToNav for hir::Local { | 400 | impl ToNav for hir::Local { |
401 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 401 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
402 | let src = self.source(db); | 402 | let src = self.source(db); |
403 | let (node, focus_range) = match &src.value { | 403 | let (node, name) = match &src.value { |
404 | Either::Left(bind_pat) => ( | 404 | Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()), |
405 | bind_pat.syntax().clone(), | 405 | Either::Right(it) => (it.syntax().clone(), it.name()), |
406 | bind_pat | ||
407 | .name() | ||
408 | .map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range), | ||
409 | ), | ||
410 | Either::Right(it) => (it.syntax().clone(), it.self_token().map(|it| it.text_range())), | ||
411 | }; | 406 | }; |
407 | let focus_range = | ||
408 | name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range); | ||
409 | |||
412 | let full_range = src.with_value(&node).original_file_range(db); | 410 | let full_range = src.with_value(&node).original_file_range(db); |
413 | let name = match self.name(db) { | 411 | let name = match self.name(db) { |
414 | Some(it) => it.to_string().into(), | 412 | Some(it) => it.to_string().into(), |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index de10406bc..1f08d7810 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -438,10 +438,10 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem) | |||
438 | FieldOrAssocItem::Field(field) => format!("#structfield.{}", field.name(db)), | 438 | FieldOrAssocItem::Field(field) => format!("#structfield.{}", field.name(db)), |
439 | FieldOrAssocItem::AssocItem(assoc) => match assoc { | 439 | FieldOrAssocItem::AssocItem(assoc) => match assoc { |
440 | AssocItem::Function(function) => { | 440 | AssocItem::Function(function) => { |
441 | let is_trait_method = matches!( | 441 | let is_trait_method = function |
442 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), | 442 | .as_assoc_item(db) |
443 | Some(AssocItemContainer::Trait(..)) | 443 | .and_then(|assoc| assoc.containing_trait(db)) |
444 | ); | 444 | .is_some(); |
445 | // This distinction may get more complicated when specialization is available. | 445 | // This distinction may get more complicated when specialization is available. |
446 | // Rustdoc makes this decision based on whether a method 'has defaultness'. | 446 | // Rustdoc makes this decision based on whether a method 'has defaultness'. |
447 | // Currently this is only the case for provided trait methods. | 447 | // Currently this is only the case for provided trait methods. |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 988a5668f..a1d2bce1d 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -55,11 +55,6 @@ pub(crate) fn goto_definition( | |||
55 | } else { | 55 | } else { |
56 | reference_definition(&sema, Either::Left(<)).to_vec() | 56 | reference_definition(&sema, Either::Left(<)).to_vec() |
57 | }, | 57 | }, |
58 | ast::SelfParam(self_param) => { | ||
59 | let def = NameClass::classify_self_param(&sema, &self_param)?.referenced_or_defined(sema.db); | ||
60 | let nav = def.try_to_nav(sema.db)?; | ||
61 | vec![nav] | ||
62 | }, | ||
63 | _ => return None, | 58 | _ => return None, |
64 | } | 59 | } |
65 | }; | 60 | }; |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index ac2d7727e..44ebdbd35 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -98,7 +98,6 @@ pub(crate) fn hover( | |||
98 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 98 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
99 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | 99 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) |
100 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | 100 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), |
101 | ast::SelfParam(self_param) => NameClass::classify_self_param(&sema, &self_param).and_then(|d| d.defined(sema.db)), | ||
102 | _ => None, | 101 | _ => None, |
103 | } | 102 | } |
104 | }; | 103 | }; |
@@ -3218,7 +3217,7 @@ impl Foo { | |||
3218 | } | 3217 | } |
3219 | "#, | 3218 | "#, |
3220 | expect![[r#" | 3219 | expect![[r#" |
3221 | *&self* | 3220 | *self* |
3222 | 3221 | ||
3223 | ```rust | 3222 | ```rust |
3224 | &Foo | 3223 | &Foo |
@@ -3238,7 +3237,7 @@ impl Foo { | |||
3238 | } | 3237 | } |
3239 | "#, | 3238 | "#, |
3240 | expect![[r#" | 3239 | expect![[r#" |
3241 | *self: Arc<Foo>* | 3240 | *self* |
3242 | 3241 | ||
3243 | ```rust | 3242 | ```rust |
3244 | Arc<Foo> | 3243 | Arc<Foo> |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index f8d69382e..567b8117e 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -86,18 +86,15 @@ pub use completion::{ | |||
86 | InsertTextFormat, | 86 | InsertTextFormat, |
87 | }; | 87 | }; |
88 | pub use hir::{Documentation, Semantics}; | 88 | pub use hir::{Documentation, Semantics}; |
89 | pub use ide_db::base_db::{ | ||
90 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, | ||
91 | SourceRootId, | ||
92 | }; | ||
93 | pub use ide_db::{ | 89 | pub use ide_db::{ |
90 | base_db::{ | ||
91 | Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, | ||
92 | SourceRoot, SourceRootId, | ||
93 | }, | ||
94 | call_info::CallInfo, | 94 | call_info::CallInfo, |
95 | search::{FileReference, ReferenceAccess, ReferenceKind}, | ||
96 | }; | ||
97 | pub use ide_db::{ | ||
98 | label::Label, | 95 | label::Label, |
99 | line_index::{LineCol, LineIndex}, | 96 | line_index::{LineCol, LineIndex}, |
100 | search::SearchScope, | 97 | search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope}, |
101 | source_change::{FileSystemEdit, SourceChange}, | 98 | source_change::{FileSystemEdit, SourceChange}, |
102 | symbol_index::Query, | 99 | symbol_index::Query, |
103 | RootDatabase, | 100 | RootDatabase, |
@@ -372,9 +369,7 @@ impl Analysis { | |||
372 | position: FilePosition, | 369 | position: FilePosition, |
373 | search_scope: Option<SearchScope>, | 370 | search_scope: Option<SearchScope>, |
374 | ) -> Cancelable<Option<ReferenceSearchResult>> { | 371 | ) -> Cancelable<Option<ReferenceSearchResult>> { |
375 | self.with_db(|db| { | 372 | self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope)) |
376 | references::find_all_refs(&Semantics::new(db), position, search_scope).map(|it| it.info) | ||
377 | }) | ||
378 | } | 373 | } |
379 | 374 | ||
380 | /// Finds all methods and free functions for the file. Does not return tests! | 375 | /// Finds all methods and free functions for the file. Does not return tests! |
@@ -481,6 +476,7 @@ impl Analysis { | |||
481 | position: FilePosition, | 476 | position: FilePosition, |
482 | full_import_path: &str, | 477 | full_import_path: &str, |
483 | imported_name: String, | 478 | imported_name: String, |
479 | import_for_trait_assoc_item: bool, | ||
484 | ) -> Cancelable<Vec<TextEdit>> { | 480 | ) -> Cancelable<Vec<TextEdit>> { |
485 | Ok(self | 481 | Ok(self |
486 | .with_db(|db| { | 482 | .with_db(|db| { |
@@ -490,6 +486,7 @@ impl Analysis { | |||
490 | position, | 486 | position, |
491 | full_import_path, | 487 | full_import_path, |
492 | imported_name, | 488 | imported_name, |
489 | import_for_trait_assoc_item, | ||
493 | ) | 490 | ) |
494 | })? | 491 | })? |
495 | .unwrap_or_default()) | 492 | .unwrap_or_default()) |
@@ -523,7 +520,7 @@ impl Analysis { | |||
523 | &self, | 520 | &self, |
524 | position: FilePosition, | 521 | position: FilePosition, |
525 | new_name: &str, | 522 | new_name: &str, |
526 | ) -> Cancelable<Result<RangeInfo<SourceChange>, RenameError>> { | 523 | ) -> Cancelable<Result<SourceChange, RenameError>> { |
527 | self.with_db(|db| references::rename::rename(db, position, new_name)) | 524 | self.with_db(|db| references::rename::rename(db, position, new_name)) |
528 | } | 525 | } |
529 | 526 | ||
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 51a2f4327..3a4f4d80b 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -25,7 +25,7 @@ use syntax::{ | |||
25 | AstNode, SyntaxNode, TextRange, TokenAtOffset, T, | 25 | AstNode, SyntaxNode, TextRange, TokenAtOffset, T, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 28 | use crate::{display::TryToNav, FilePosition, NavigationTarget}; |
29 | 29 | ||
30 | #[derive(Debug, Clone)] | 30 | #[derive(Debug, Clone)] |
31 | pub struct ReferenceSearchResult { | 31 | pub struct ReferenceSearchResult { |
@@ -41,14 +41,6 @@ pub struct Declaration { | |||
41 | } | 41 | } |
42 | 42 | ||
43 | impl ReferenceSearchResult { | 43 | impl ReferenceSearchResult { |
44 | pub fn declaration(&self) -> &Declaration { | ||
45 | &self.declaration | ||
46 | } | ||
47 | |||
48 | pub fn decl_target(&self) -> &NavigationTarget { | ||
49 | &self.declaration.nav | ||
50 | } | ||
51 | |||
52 | pub fn references(&self) -> &UsageSearchResult { | 44 | pub fn references(&self) -> &UsageSearchResult { |
53 | &self.references | 45 | &self.references |
54 | } | 46 | } |
@@ -87,7 +79,7 @@ pub(crate) fn find_all_refs( | |||
87 | sema: &Semantics<RootDatabase>, | 79 | sema: &Semantics<RootDatabase>, |
88 | position: FilePosition, | 80 | position: FilePosition, |
89 | search_scope: Option<SearchScope>, | 81 | search_scope: Option<SearchScope>, |
90 | ) -> Option<RangeInfo<ReferenceSearchResult>> { | 82 | ) -> Option<ReferenceSearchResult> { |
91 | let _p = profile::span("find_all_refs"); | 83 | let _p = profile::span("find_all_refs"); |
92 | let syntax = sema.parse(position.file_id).syntax().clone(); | 84 | let syntax = sema.parse(position.file_id).syntax().clone(); |
93 | 85 | ||
@@ -105,7 +97,7 @@ pub(crate) fn find_all_refs( | |||
105 | ) | 97 | ) |
106 | }; | 98 | }; |
107 | 99 | ||
108 | let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; | 100 | let def = find_name(&sema, &syntax, position, opt_name)?; |
109 | 101 | ||
110 | let mut usages = def.usages(sema).set_scope(search_scope).all(); | 102 | let mut usages = def.usages(sema).set_scope(search_scope).all(); |
111 | usages | 103 | usages |
@@ -139,7 +131,7 @@ pub(crate) fn find_all_refs( | |||
139 | 131 | ||
140 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; | 132 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; |
141 | 133 | ||
142 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages })) | 134 | Some(ReferenceSearchResult { declaration, references: usages }) |
143 | } | 135 | } |
144 | 136 | ||
145 | fn find_name( | 137 | fn find_name( |
@@ -147,35 +139,27 @@ fn find_name( | |||
147 | syntax: &SyntaxNode, | 139 | syntax: &SyntaxNode, |
148 | position: FilePosition, | 140 | position: FilePosition, |
149 | opt_name: Option<ast::Name>, | 141 | opt_name: Option<ast::Name>, |
150 | ) -> Option<RangeInfo<Definition>> { | 142 | ) -> Option<Definition> { |
151 | if let Some(name) = opt_name { | 143 | let def = if let Some(name) = opt_name { |
152 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); | 144 | NameClass::classify(sema, &name)?.referenced_or_defined(sema.db) |
153 | let FileRange { range, .. } = sema.original_range(name.syntax()); | 145 | } else if let Some(lifetime) = |
154 | return Some(RangeInfo::new(range, def)); | ||
155 | } | ||
156 | |||
157 | let (FileRange { range, .. }, def) = if let Some(lifetime) = | ||
158 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) | 146 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) |
159 | { | 147 | { |
160 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) | 148 | if let Some(def) = |
161 | .map(|class| NameRefClass::referenced(class, sema.db)) | 149 | NameRefClass::classify_lifetime(sema, &lifetime).map(|class| class.referenced(sema.db)) |
162 | { | 150 | { |
163 | (sema.original_range(lifetime.syntax()), def) | 151 | def |
164 | } else { | 152 | } else { |
165 | ( | 153 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db) |
166 | sema.original_range(lifetime.syntax()), | ||
167 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), | ||
168 | ) | ||
169 | } | 154 | } |
155 | } else if let Some(name_ref) = | ||
156 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset) | ||
157 | { | ||
158 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db) | ||
170 | } else { | 159 | } else { |
171 | let name_ref = | 160 | return None; |
172 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; | ||
173 | ( | ||
174 | sema.original_range(name_ref.syntax()), | ||
175 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | ||
176 | ) | ||
177 | }; | 161 | }; |
178 | Some(RangeInfo::new(range, def)) | 162 | Some(def) |
179 | } | 163 | } |
180 | 164 | ||
181 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { | 165 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { |
@@ -930,6 +914,26 @@ impl Foo { | |||
930 | ); | 914 | ); |
931 | } | 915 | } |
932 | 916 | ||
917 | #[test] | ||
918 | fn test_find_self_refs_decl() { | ||
919 | check( | ||
920 | r#" | ||
921 | struct Foo { bar: i32 } | ||
922 | |||
923 | impl Foo { | ||
924 | fn foo(self$0) { | ||
925 | self; | ||
926 | } | ||
927 | } | ||
928 | "#, | ||
929 | expect![[r#" | ||
930 | self SelfParam FileId(0) 47..51 47..51 SelfParam | ||
931 | |||
932 | FileId(0) 63..67 Other Read | ||
933 | "#]], | ||
934 | ); | ||
935 | } | ||
936 | |||
933 | fn check(ra_fixture: &str, expect: Expect) { | 937 | fn check(ra_fixture: &str, expect: Expect) { |
934 | check_with_scope(ra_fixture, None, expect) | 938 | check_with_scope(ra_fixture, None, expect) |
935 | } | 939 | } |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 9ac4af026..c25bcce50 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -1,27 +1,25 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::{ | 2 | use std::fmt::{self, Display}; |
3 | convert::TryInto, | ||
4 | fmt::{self, Display}, | ||
5 | }; | ||
6 | 3 | ||
7 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 4 | use either::Either; |
5 | use hir::{HasSource, InFile, Module, ModuleDef, ModuleSource, Semantics}; | ||
8 | use ide_db::{ | 6 | use ide_db::{ |
9 | base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, | 7 | base_db::{AnchoredPathBuf, FileId, FileRange}, |
10 | defs::{Definition, NameClass, NameRefClass}, | 8 | defs::{Definition, NameClass, NameRefClass}, |
11 | search::FileReference, | 9 | search::FileReference, |
12 | RootDatabase, | 10 | RootDatabase, |
13 | }; | 11 | }; |
12 | use stdx::assert_never; | ||
14 | use syntax::{ | 13 | use syntax::{ |
15 | algo::find_node_at_offset, | ||
16 | ast::{self, NameOwner}, | 14 | ast::{self, NameOwner}, |
17 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T, | 15 | lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, |
18 | }; | 16 | }; |
19 | use test_utils::mark; | 17 | use test_utils::mark; |
20 | use text_edit::TextEdit; | 18 | use text_edit::TextEdit; |
21 | 19 | ||
22 | use crate::{ | 20 | use crate::{ |
23 | FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, | 21 | display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, SourceChange, |
24 | TextRange, TextSize, | 22 | TextRange, |
25 | }; | 23 | }; |
26 | 24 | ||
27 | type RenameResult<T> = Result<T, RenameError>; | 25 | type RenameResult<T> = Result<T, RenameError>; |
@@ -50,24 +48,22 @@ pub(crate) fn prepare_rename( | |||
50 | let sema = Semantics::new(db); | 48 | let sema = Semantics::new(db); |
51 | let source_file = sema.parse(position.file_id); | 49 | let source_file = sema.parse(position.file_id); |
52 | let syntax = source_file.syntax(); | 50 | let syntax = source_file.syntax(); |
53 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { | 51 | let range = match &find_name_like(&sema, &syntax, position) |
54 | rename_mod(&sema, position, module, "dummy") | 52 | .ok_or_else(|| format_err!("No references found at position"))? |
55 | } else if let Some(self_token) = | ||
56 | syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self]) | ||
57 | { | 53 | { |
58 | rename_self_to_param(&sema, position, self_token, "dummy") | 54 | NameLike::Name(it) => it.syntax(), |
59 | } else { | 55 | NameLike::NameRef(it) => it.syntax(), |
60 | let RangeInfo { range, .. } = find_all_refs(&sema, position)?; | 56 | NameLike::Lifetime(it) => it.syntax(), |
61 | Ok(RangeInfo::new(range, SourceChange::default())) | ||
62 | } | 57 | } |
63 | .map(|info| RangeInfo::new(info.range, ())) | 58 | .text_range(); |
59 | Ok(RangeInfo::new(range, ())) | ||
64 | } | 60 | } |
65 | 61 | ||
66 | pub(crate) fn rename( | 62 | pub(crate) fn rename( |
67 | db: &RootDatabase, | 63 | db: &RootDatabase, |
68 | position: FilePosition, | 64 | position: FilePosition, |
69 | new_name: &str, | 65 | new_name: &str, |
70 | ) -> RenameResult<RangeInfo<SourceChange>> { | 66 | ) -> RenameResult<SourceChange> { |
71 | let sema = Semantics::new(db); | 67 | let sema = Semantics::new(db); |
72 | rename_with_semantics(&sema, position, new_name) | 68 | rename_with_semantics(&sema, position, new_name) |
73 | } | 69 | } |
@@ -76,18 +72,15 @@ pub(crate) fn rename_with_semantics( | |||
76 | sema: &Semantics<RootDatabase>, | 72 | sema: &Semantics<RootDatabase>, |
77 | position: FilePosition, | 73 | position: FilePosition, |
78 | new_name: &str, | 74 | new_name: &str, |
79 | ) -> RenameResult<RangeInfo<SourceChange>> { | 75 | ) -> RenameResult<SourceChange> { |
80 | let source_file = sema.parse(position.file_id); | 76 | let source_file = sema.parse(position.file_id); |
81 | let syntax = source_file.syntax(); | 77 | let syntax = source_file.syntax(); |
82 | 78 | ||
83 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { | 79 | let def = find_definition(sema, syntax, position) |
84 | rename_mod(&sema, position, module, new_name) | 80 | .ok_or_else(|| format_err!("No references found at position"))?; |
85 | } else if let Some(self_token) = | 81 | match def { |
86 | syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self]) | 82 | Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(&sema, module, new_name), |
87 | { | 83 | def => rename_reference(sema, def, new_name), |
88 | rename_self_to_param(&sema, position, self_token, new_name) | ||
89 | } else { | ||
90 | rename_reference(&sema, position, new_name) | ||
91 | } | 84 | } |
92 | } | 85 | } |
93 | 86 | ||
@@ -98,17 +91,12 @@ pub(crate) fn will_rename_file( | |||
98 | ) -> Option<SourceChange> { | 91 | ) -> Option<SourceChange> { |
99 | let sema = Semantics::new(db); | 92 | let sema = Semantics::new(db); |
100 | let module = sema.to_module_def(file_id)?; | 93 | let module = sema.to_module_def(file_id)?; |
101 | 94 | let mut change = rename_mod(&sema, module, new_name_stem).ok()?; | |
102 | let decl = module.declaration_source(db)?; | ||
103 | let range = decl.value.name()?.syntax().text_range(); | ||
104 | |||
105 | let position = FilePosition { file_id: decl.file_id.original_file(db), offset: range.start() }; | ||
106 | let mut change = rename_mod(&sema, position, module, new_name_stem).ok()?.info; | ||
107 | change.file_system_edits.clear(); | 95 | change.file_system_edits.clear(); |
108 | Some(change) | 96 | Some(change) |
109 | } | 97 | } |
110 | 98 | ||
111 | #[derive(Debug, PartialEq)] | 99 | #[derive(Copy, Clone, Debug, PartialEq)] |
112 | enum IdentifierKind { | 100 | enum IdentifierKind { |
113 | Ident, | 101 | Ident, |
114 | Lifetime, | 102 | Lifetime, |
@@ -135,40 +123,51 @@ fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> { | |||
135 | } | 123 | } |
136 | } | 124 | } |
137 | 125 | ||
138 | fn find_module_at_offset( | 126 | enum NameLike { |
127 | Name(ast::Name), | ||
128 | NameRef(ast::NameRef), | ||
129 | Lifetime(ast::Lifetime), | ||
130 | } | ||
131 | |||
132 | fn find_name_like( | ||
139 | sema: &Semantics<RootDatabase>, | 133 | sema: &Semantics<RootDatabase>, |
140 | position: FilePosition, | ||
141 | syntax: &SyntaxNode, | 134 | syntax: &SyntaxNode, |
142 | ) -> Option<Module> { | 135 | position: FilePosition, |
143 | let ident = syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::IDENT)?; | 136 | ) -> Option<NameLike> { |
144 | 137 | let namelike = if let Some(name_ref) = | |
145 | let module = match_ast! { | 138 | sema.find_node_at_offset_with_descend::<ast::NameRef>(syntax, position.offset) |
146 | match (ident.parent()) { | 139 | { |
147 | ast::NameRef(name_ref) => { | 140 | NameLike::NameRef(name_ref) |
148 | match NameRefClass::classify(sema, &name_ref)? { | 141 | } else if let Some(name) = |
149 | NameRefClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module, | 142 | sema.find_node_at_offset_with_descend::<ast::Name>(syntax, position.offset) |
150 | _ => return None, | 143 | { |
151 | } | 144 | NameLike::Name(name) |
152 | }, | 145 | } else if let Some(lifetime) = |
153 | ast::Name(name) => { | 146 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(syntax, position.offset) |
154 | match NameClass::classify(&sema, &name)? { | 147 | { |
155 | NameClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module, | 148 | NameLike::Lifetime(lifetime) |
156 | _ => return None, | 149 | } else { |
157 | } | 150 | return None; |
158 | }, | ||
159 | _ => return None, | ||
160 | } | ||
161 | }; | 151 | }; |
162 | 152 | Some(namelike) | |
163 | Some(module) | ||
164 | } | 153 | } |
165 | 154 | ||
166 | fn find_all_refs( | 155 | fn find_definition( |
167 | sema: &Semantics<RootDatabase>, | 156 | sema: &Semantics<RootDatabase>, |
157 | syntax: &SyntaxNode, | ||
168 | position: FilePosition, | 158 | position: FilePosition, |
169 | ) -> RenameResult<RangeInfo<ReferenceSearchResult>> { | 159 | ) -> Option<Definition> { |
170 | crate::references::find_all_refs(sema, position, None) | 160 | let def = match find_name_like(sema, syntax, position)? { |
171 | .ok_or_else(|| format_err!("No references found at position")) | 161 | NameLike::Name(name) => NameClass::classify(sema, &name)?.referenced_or_defined(sema.db), |
162 | NameLike::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | ||
163 | NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) | ||
164 | .map(|class| NameRefClass::referenced(class, sema.db)) | ||
165 | .or_else(|| { | ||
166 | NameClass::classify_lifetime(sema, &lifetime) | ||
167 | .map(|it| it.referenced_or_defined(sema.db)) | ||
168 | })?, | ||
169 | }; | ||
170 | Some(def) | ||
172 | } | 171 | } |
173 | 172 | ||
174 | fn source_edit_from_references( | 173 | fn source_edit_from_references( |
@@ -242,72 +241,84 @@ fn edit_text_range_for_record_field_expr_or_pat( | |||
242 | 241 | ||
243 | fn rename_mod( | 242 | fn rename_mod( |
244 | sema: &Semantics<RootDatabase>, | 243 | sema: &Semantics<RootDatabase>, |
245 | position: FilePosition, | ||
246 | module: Module, | 244 | module: Module, |
247 | new_name: &str, | 245 | new_name: &str, |
248 | ) -> RenameResult<RangeInfo<SourceChange>> { | 246 | ) -> RenameResult<SourceChange> { |
249 | if IdentifierKind::Ident != check_identifier(new_name)? { | 247 | if IdentifierKind::Ident != check_identifier(new_name)? { |
250 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | 248 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); |
251 | } | 249 | } |
252 | 250 | ||
253 | let mut source_change = SourceChange::default(); | 251 | let mut source_change = SourceChange::default(); |
254 | 252 | ||
255 | let src = module.definition_source(sema.db); | 253 | let InFile { file_id, value: def_source } = module.definition_source(sema.db); |
256 | let file_id = src.file_id.original_file(sema.db); | 254 | let file_id = file_id.original_file(sema.db); |
257 | match src.value { | 255 | if let ModuleSource::SourceFile(..) = def_source { |
258 | ModuleSource::SourceFile(..) => { | 256 | // mod is defined in path/to/dir/mod.rs |
259 | // mod is defined in path/to/dir/mod.rs | 257 | let path = if module.is_mod_rs(sema.db) { |
260 | let path = if module.is_mod_rs(sema.db) { | 258 | format!("../{}/mod.rs", new_name) |
261 | format!("../{}/mod.rs", new_name) | 259 | } else { |
262 | } else { | 260 | format!("{}.rs", new_name) |
263 | format!("{}.rs", new_name) | 261 | }; |
264 | }; | 262 | let dst = AnchoredPathBuf { anchor: file_id, path }; |
265 | let dst = AnchoredPathBuf { anchor: file_id, path }; | 263 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; |
266 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | 264 | source_change.push_file_system_edit(move_file); |
267 | source_change.push_file_system_edit(move_file); | 265 | } |
268 | } | 266 | |
269 | ModuleSource::Module(..) => {} | 267 | if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) { |
270 | } | 268 | let file_id = file_id.original_file(sema.db); |
271 | 269 | match decl_source.name() { | |
272 | if let Some(src) = module.declaration_source(sema.db) { | 270 | Some(name) => source_change.insert_source_edit( |
273 | let file_id = src.file_id.original_file(sema.db); | 271 | file_id, |
274 | let name = src.value.name().unwrap(); | 272 | TextEdit::replace(name.syntax().text_range(), new_name.to_string()), |
275 | source_change.insert_source_edit( | 273 | ), |
276 | file_id, | 274 | _ => unreachable!(), |
277 | TextEdit::replace(name.syntax().text_range(), new_name.into()), | 275 | }; |
278 | ); | ||
279 | } | 276 | } |
280 | 277 | let def = Definition::ModuleDef(ModuleDef::Module(module)); | |
281 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; | 278 | let usages = def.usages(sema).all(); |
282 | let ref_edits = refs.references().iter().map(|(&file_id, references)| { | 279 | let ref_edits = usages.iter().map(|(&file_id, references)| { |
283 | source_edit_from_references(sema, file_id, references, new_name) | 280 | source_edit_from_references(sema, file_id, references, new_name) |
284 | }); | 281 | }); |
285 | source_change.extend(ref_edits); | 282 | source_change.extend(ref_edits); |
286 | 283 | ||
287 | Ok(RangeInfo::new(range, source_change)) | 284 | Ok(source_change) |
288 | } | 285 | } |
289 | 286 | ||
290 | fn rename_to_self( | 287 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { |
291 | sema: &Semantics<RootDatabase>, | 288 | if assert_never!(local.is_self(sema.db)) { |
292 | position: FilePosition, | 289 | bail!("rename_to_self invoked on self"); |
293 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 290 | } |
294 | let source_file = sema.parse(position.file_id); | 291 | |
295 | let syn = source_file.syntax(); | 292 | let fn_def = match local.parent(sema.db) { |
293 | hir::DefWithBody::Function(func) => func, | ||
294 | _ => bail!("Cannot rename non-param local to self"), | ||
295 | }; | ||
296 | |||
297 | // FIXME: reimplement this on the hir instead | ||
298 | // as of the time of this writing params in hir don't keep their names | ||
299 | let fn_ast = | ||
300 | fn_def.source(sema.db).ok_or(format_err!("Cannot rename non-param local to self"))?.value; | ||
296 | 301 | ||
297 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) | 302 | let first_param_range = fn_ast |
298 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) | ||
299 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; | ||
300 | let param_range = fn_ast | ||
301 | .param_list() | 303 | .param_list() |
302 | .and_then(|p| p.params().next()) | 304 | .and_then(|p| p.params().next()) |
303 | .ok_or_else(|| format_err!("Method has no parameters"))? | 305 | .ok_or_else(|| format_err!("Method has no parameters"))? |
304 | .syntax() | 306 | .syntax() |
305 | .text_range(); | 307 | .text_range(); |
306 | if !param_range.contains(position.offset) { | 308 | let InFile { file_id, value: local_source } = local.source(sema.db); |
307 | bail!("Only the first parameter can be self"); | 309 | match local_source { |
310 | either::Either::Left(pat) | ||
311 | if !first_param_range.contains_range(pat.syntax().text_range()) => | ||
312 | { | ||
313 | bail!("Only the first parameter can be self"); | ||
314 | } | ||
315 | _ => (), | ||