diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml index c3cfda85517e4..070560dfbc316 100644 --- a/src/tools/rust-analyzer/.cargo/config.toml +++ b/src/tools/rust-analyzer/.cargo/config.toml @@ -3,6 +3,7 @@ xtask = "run --package xtask --bin xtask --" tq = "test -- -q" qt = "tq" lint = "clippy --all-targets -- --cap-lints warn" +codegen = "run --package xtask --bin xtask -- codegen" [target.x86_64-pc-windows-msvc] linker = "rust-lld" diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 5a8b18e3fe1b3..2d8946520d5e7 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -79,6 +79,9 @@ jobs: if: matrix.os == 'ubuntu-latest' run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml + - name: Codegen checks (rust-analyzer) + run: cargo codegen --check + - name: Compile (tests) run: cargo test --no-run --locked ${{ env.USE_SYSROOT_ABI }} diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml index 98dbe3a5d9d36..c2e8b265218fb 100644 --- a/src/tools/rust-analyzer/.typos.toml +++ b/src/tools/rust-analyzer/.typos.toml @@ -5,7 +5,6 @@ extend-exclude = [ "crates/parser/test_data/lexer/err/", "crates/project-model/test_data/", ] -ignore-hidden = false [default] extend-ignore-re = [ diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9acace2fb3313..903141eee9afb 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arbitrary" @@ -52,16 +52,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", - "object 0.30.4", + "miniz_oxide", + "object 0.32.2", "rustc-demangle", ] @@ -71,7 +71,6 @@ version = "0.0.0" dependencies = [ "cfg", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "profile", "rustc-hash", "salsa", "semver", @@ -91,30 +90,30 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -135,9 +134,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg" @@ -177,7 +176,7 @@ version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff550c2cdd63ff74394214dce03d06386928a641c0f08837535f04af573a966d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "chalk-derive", "lazy_static", ] @@ -217,7 +216,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ - "nix 0.26.2", + "nix 0.26.4", "winapi", ] @@ -240,64 +239,55 @@ checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix 0.27.1", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -313,6 +303,15 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -344,9 +343,9 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "ena" @@ -357,20 +356,11 @@ dependencies = [ "log", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", -] - [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "expect-test" @@ -384,14 +374,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -402,12 +392,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -428,9 +418,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -463,9 +453,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "hashbrown" @@ -481,12 +471,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hir" @@ -501,7 +488,6 @@ dependencies = [ "hir-ty", "itertools", "once_cell", - "profile", "rustc-hash", "smallvec", "span", @@ -518,7 +504,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg", "cov-mark", "dashmap", @@ -565,7 +551,6 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", - "profile", "rustc-hash", "smallvec", "span", @@ -582,7 +567,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.4.1", + "bitflags 2.4.2", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -601,10 +586,9 @@ dependencies = [ "nohash-hasher", "once_cell", "oorandom", - "profile", "project-model", "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.35.0", + "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", "rustc-hash", "scoped-tls", @@ -622,11 +606,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -673,9 +657,7 @@ dependencies = [ "hir", "ide-db", "itertools", - "profile", "smallvec", - "sourcegen", "stdx", "syntax", "test-fixture", @@ -695,7 +677,6 @@ dependencies = [ "ide-db", "itertools", "once_cell", - "profile", "smallvec", "stdx", "syntax", @@ -724,12 +705,10 @@ dependencies = [ "memchr", "nohash-hasher", "once_cell", - "oorandom", "parser", "profile", "rayon", "rustc-hash", - "sourcegen", "span", "stdx", "syntax", @@ -738,7 +717,6 @@ dependencies = [ "text-edit", "tracing", "triomphe", - "xshell", ] [[package]] @@ -753,9 +731,7 @@ dependencies = [ "ide-db", "itertools", "once_cell", - "profile", "serde_json", - "sourcegen", "stdx", "syntax", "test-fixture", @@ -785,9 +761,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -795,9 +771,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown", @@ -835,18 +811,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jod-thread" @@ -856,9 +832,9 @@ checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" [[package]] name = "kqueue" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ "kqueue-sys", "libc", @@ -866,9 +842,9 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ "bitflags 1.3.2", "libc", @@ -892,25 +868,25 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.4", ] [[package]] name = "libmimalloc-sys" -version = "0.1.33" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ac0e912c8ef1b735e92369695618dc5b1819f5a7bf3f167301a3ba1cea515e" +checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" dependencies = [ "cc", "libc", @@ -925,6 +901,7 @@ name = "line-index" version = "0.1.1" dependencies = [ "nohash-hasher", + "oorandom", "text-size", ] @@ -964,9 +941,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -974,9 +951,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lsp-server" @@ -1057,41 +1034,32 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2894987a3459f3ffb755608bd82188f8ed00d0ae077f1edea29c068d639d98" +checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" dependencies = [ "libmimalloc-sys", ] [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -1105,14 +1073,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -1121,7 +1088,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -1138,7 +1105,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1160,11 +1127,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", @@ -1172,27 +1145,27 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "object" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -1218,9 +1191,9 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1233,13 +1206,14 @@ dependencies = [ "ra-ap-rustc_lexer", "sourcegen", "stdx", + "tracing", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "paths" @@ -1247,9 +1221,9 @@ version = "0.0.0" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "perf-event" @@ -1282,9 +1256,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -1300,9 +1280,8 @@ dependencies = [ "indexmap", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "memmap2", - "object 0.32.0", + "object 0.33.0", "paths", - "profile", "rustc-hash", "serde", "serde_json", @@ -1324,7 +1303,7 @@ dependencies = [ "libloading", "mbe", "memmap2", - "object 0.32.0", + "object 0.33.0", "paths", "proc-macro-api", "proc-macro-test", @@ -1347,14 +1326,13 @@ name = "proc-macro-test" version = "0.0.0" dependencies = [ "cargo_metadata", - "toolchain", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1386,7 +1364,6 @@ dependencies = [ "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", - "profile", "rustc-hash", "semver", "serde", @@ -1419,11 +1396,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "memchr", "unicase", ] @@ -1439,63 +1416,40 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "ra-ap-rustc_abi" -version = "0.35.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0baa423a2c2bfd6e4bd40e7215f7ddebd12a649ce0b65078a38b91068895aa" +checksum = "c2ae52e2d5b08762c9464b541345f519b8719d57b643b73632bade43ecece9dc" dependencies = [ - "bitflags 2.4.1", - "ra-ap-rustc_index 0.35.0", + "bitflags 2.4.2", + "ra-ap-rustc_index", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322b751895cc4a0a2ee0c6ab36ec80bc8abf5f8d76254c482f96f03c27c92ebe" -dependencies = [ - "arrayvec", - "ra-ap-rustc_index_macros 0.35.0", - "smallvec", -] - -[[package]] -name = "ra-ap-rustc_index" -version = "0.37.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5a0ba0d08af366cf235dbe8eb7226cced7a4fe502c98aa434ccf416defd746" +checksum = "bfd7e10c7853fe79443d46e1d2d8ab09fe99926118e59653fb8b480d5045f126" dependencies = [ "arrayvec", - "ra-ap-rustc_index_macros 0.37.0", + "ra-ap-rustc_index_macros", "smallvec", ] [[package]] name = "ra-ap-rustc_index_macros" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054e25eac52f0506c1309ca4317c11ad4925d7b99eb897f71aa7c3cbafb46c2b" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "ra-ap-rustc_index_macros" -version = "0.37.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1971ebf9a701e0e68387c264a32517dcb4861ad3a4862f2e2803c1121ade20d5" +checksum = "47f1d1c589be6c9a9e852fadee0e60329c0f862e87442ac2fe5adae30663cc76" dependencies = [ "proc-macro2", "quote", @@ -1505,9 +1459,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.35.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8da0fa51a1a97ba4296a1c78fa454815a153b472e2546b6338a0902ad59e015" +checksum = "fa852373a757b4c723bbdc96ced7f575cad68a1e266e45fee12bc4c69a482d80" dependencies = [ "unicode-properties", "unicode-xid", @@ -1515,21 +1469,21 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.35.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3851f930a54adcb76889983dcd5c00a0c4e206e190e1384dbc00d49b82dfb45e" +checksum = "2afe3c49accd95a53ac4d72ae13bafc7d115bdd80c8cd56ab09e6fc68f482210" dependencies = [ - "ra-ap-rustc_index 0.35.0", + "ra-ap-rustc_index", "ra-ap-rustc_lexer", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.37.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3c0e7ca9c5bdc66e3b590688e237a22ac47a48e4eac7f46b05b2abbfaf0abd" +checksum = "1253da23515d80c377a3998731e0ec3794997b62b989fd47db73efbde6a0bd7c" dependencies = [ - "ra-ap-rustc_index 0.37.0", + "ra-ap-rustc_index", "rustc-hash", "rustc_apfloat", "smallvec", @@ -1568,9 +1522,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -1578,23 +1532,14 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1697,9 +1642,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "salsa" @@ -1717,7 +1662,6 @@ dependencies = [ "rustc-hash", "salsa-macros", "smallvec", - "test-log", "tracing", "triomphe", ] @@ -1758,33 +1702,33 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -1793,9 +1737,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "indexmap", "itoa", @@ -1805,9 +1749,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.12" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", @@ -1816,18 +1760,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "smallvec" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smol_str" @@ -1840,9 +1784,9 @@ dependencies = [ [[package]] name = "snap" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "sourcegen" @@ -1870,12 +1814,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdx" version = "0.0.0" @@ -1892,9 +1830,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -1903,14 +1841,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", - "unicode-xid", ] [[package]] @@ -1925,7 +1862,6 @@ dependencies = [ "once_cell", "parser", "proc-macro2", - "profile", "quote", "ra-ap-rustc_lexer", "rayon", @@ -1955,27 +1891,6 @@ dependencies = [ "tt", ] -[[package]] -name = "test-log" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b" -dependencies = [ - "env_logger", - "test-log-macros", -] - -[[package]] -name = "test-log-macros" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "test-utils" version = "0.0.0" @@ -2004,18 +1919,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -2024,9 +1939,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -2034,9 +1949,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-ctl" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" +checksum = "619bfed27d807b54f7f776b9430d4f8060e66ee138a28632ca898584d462c31c" dependencies = [ "libc", "paste", @@ -2045,9 +1960,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.3+5.3.0-patched" +version = "0.5.4+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" +checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" dependencies = [ "cc", "libc", @@ -2055,9 +1970,9 @@ dependencies = [ [[package]] name = "tikv-jemallocator" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979" +checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca" dependencies = [ "libc", "tikv-jemalloc-sys", @@ -2065,19 +1980,22 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", + "num-conv", + "powerfmt", "serde", "time-core", ] [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "tinyvec" @@ -2202,39 +2120,39 @@ checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" [[package]] name = "unicode-xid" @@ -2244,9 +2162,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2293,9 +2211,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2325,9 +2243,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -2340,147 +2258,156 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.4", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "write-json" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3" +checksum = "23f6174b2566cc4a74f95e1367ec343e7fa80c93cc8087f5c4a3d6a1088b2118" [[package]] name = "xflags" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4554b580522d0ca238369c16b8f6ce34524d61dafe7244993754bbd05f2c2ea" +checksum = "7d9e15fbb3de55454b0106e314b28e671279009b363e6f1d8e39fdc3bf048944" dependencies = [ "xflags-macros", ] [[package]] name = "xflags-macros" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58e7b3ca8977093aae6b87b6a7730216fc4c53a6530bab5c43a783cd810c1a8" +checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155" [[package]] name = "xshell" @@ -2503,6 +2430,7 @@ version = "0.1.0" dependencies = [ "anyhow", "flate2", + "stdx", "time", "write-json", "xflags", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 16dd510389988..440f46a938b97 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -84,11 +84,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.35.0", default-features = false } -ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false } -ra-ap-rustc_index = { version = "0.35.0", default-features = false } -ra-ap-rustc_abi = { version = "0.35.0", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.37.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.42.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.42.0", default-features = false } +ra-ap-rustc_index = { version = "0.42.0", default-features = false } +ra-ap-rustc_abi = { version = "0.42.0", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.42.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. sourcegen = { path = "./crates/sourcegen" } @@ -108,6 +108,7 @@ cargo_metadata = "0.18.1" command-group = "2.0.1" crossbeam-channel = "0.5.8" dissimilar = "1.0.7" +dot = "0.1.4" either = "1.9.0" expect-test = "1.4.0" hashbrown = { version = "0.14", features = [ @@ -117,6 +118,16 @@ indexmap = "2.1.0" itertools = "0.12.0" libc = "0.2.150" nohash-hasher = "0.2.0" +oorandom = "11.1.3" +object = { version = "0.33.0", default-features = false, features = [ + "std", + "read_core", + "elf", + "macho", + "pe", +] } +pulldown-cmark-to-cmark = "10.0.4" +pulldown-cmark = { version = "0.9.0", default-features = false } rayon = "1.8.0" rustc-hash = "1.1.0" semver = "1.0.14" @@ -137,6 +148,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features = "tracing-log", ] } triomphe = { version = "0.1.10", default-features = false, features = ["std"] } +url = "2.3.1" xshell = "0.2.5" @@ -146,6 +158,7 @@ dashmap = { version = "=5.5.3", features = ["raw-api"] } [workspace.lints.rust] rust_2018_idioms = "warn" unused_lifetimes = "warn" +unreachable_pub = "warn" semicolon_in_expressions_from_macros = "warn" [workspace.lints.clippy] diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 801ba2d1f6c85..118abf5d6eb8b 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -21,7 +21,6 @@ tracing.workspace = true # local deps cfg.workspace = true -profile.workspace = true stdx.workspace = true syntax.workspace = true vfs.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index cb2e6cdaa28dc..758d2a45c8fc5 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -43,7 +43,7 @@ pub trait Upcast { } pub const DEFAULT_PARSE_LRU_CAP: usize = 128; -pub const DEFAULT_BORROWCK_LRU_CAP: usize = 256; +pub const DEFAULT_BORROWCK_LRU_CAP: usize = 1024; pub trait FileLoader { /// Text of the file. diff --git a/src/tools/rust-analyzer/crates/flycheck/src/command.rs b/src/tools/rust-analyzer/crates/flycheck/src/command.rs new file mode 100644 index 0000000000000..091146a0010a5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/flycheck/src/command.rs @@ -0,0 +1,156 @@ +//! Utilities for running a cargo command like `cargo check` or `cargo test` in a separate thread and +//! parse its stdout/stderr. + +use std::{ + ffi::OsString, + fmt, io, + path::PathBuf, + process::{ChildStderr, ChildStdout, Command, Stdio}, +}; + +use command_group::{CommandGroup, GroupChild}; +use crossbeam_channel::{unbounded, Receiver, Sender}; +use stdx::process::streaming_output; + +/// Cargo output is structured as a one JSON per line. This trait abstracts parsing one line of +/// cargo output into a Rust data type. +pub(crate) trait ParseFromLine: Sized + Send + 'static { + fn from_line(line: &str, error: &mut String) -> Option; + fn from_eof() -> Option; +} + +struct CargoActor { + sender: Sender, + stdout: ChildStdout, + stderr: ChildStderr, +} + +impl CargoActor { + fn new(sender: Sender, stdout: ChildStdout, stderr: ChildStderr) -> Self { + CargoActor { sender, stdout, stderr } + } + + fn run(self) -> io::Result<(bool, String)> { + // We manually read a line at a time, instead of using serde's + // stream deserializers, because the deserializer cannot recover + // from an error, resulting in it getting stuck, because we try to + // be resilient against failures. + // + // Because cargo only outputs one JSON object per line, we can + // simply skip a line if it doesn't parse, which just ignores any + // erroneous output. + + let mut stdout_errors = String::new(); + let mut stderr_errors = String::new(); + let mut read_at_least_one_stdout_message = false; + let mut read_at_least_one_stderr_message = false; + let process_line = |line: &str, error: &mut String| { + // Try to deserialize a message from Cargo or Rustc. + if let Some(t) = T::from_line(line, error) { + self.sender.send(t).unwrap(); + true + } else { + false + } + }; + let output = streaming_output( + self.stdout, + self.stderr, + &mut |line| { + if process_line(line, &mut stdout_errors) { + read_at_least_one_stdout_message = true; + } + }, + &mut |line| { + if process_line(line, &mut stderr_errors) { + read_at_least_one_stderr_message = true; + } + }, + &mut || { + if let Some(t) = T::from_eof() { + self.sender.send(t).unwrap(); + } + }, + ); + + let read_at_least_one_message = + read_at_least_one_stdout_message || read_at_least_one_stderr_message; + let mut error = stdout_errors; + error.push_str(&stderr_errors); + match output { + Ok(_) => Ok((read_at_least_one_message, error)), + Err(e) => Err(io::Error::new(e.kind(), format!("{e:?}: {error}"))), + } + } +} + +struct JodGroupChild(GroupChild); + +impl Drop for JodGroupChild { + fn drop(&mut self) { + _ = self.0.kill(); + _ = self.0.wait(); + } +} + +/// A handle to a cargo process used for fly-checking. +pub(crate) struct CommandHandle { + /// The handle to the actual cargo process. As we cannot cancel directly from with + /// a read syscall dropping and therefore terminating the process is our best option. + child: JodGroupChild, + thread: stdx::thread::JoinHandle>, + pub(crate) receiver: Receiver, + program: OsString, + arguments: Vec, + current_dir: Option, +} + +impl fmt::Debug for CommandHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CommandHandle") + .field("program", &self.program) + .field("arguments", &self.arguments) + .field("current_dir", &self.current_dir) + .finish() + } +} + +impl CommandHandle { + pub(crate) fn spawn(mut command: Command) -> std::io::Result { + command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); + let mut child = command.group_spawn().map(JodGroupChild)?; + + let program = command.get_program().into(); + let arguments = command.get_args().map(|arg| arg.into()).collect::>(); + let current_dir = command.get_current_dir().map(|arg| arg.to_path_buf()); + + let stdout = child.0.inner().stdout.take().unwrap(); + let stderr = child.0.inner().stderr.take().unwrap(); + + let (sender, receiver) = unbounded(); + let actor = CargoActor::::new(sender, stdout, stderr); + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) + .name("CommandHandle".to_owned()) + .spawn(move || actor.run()) + .expect("failed to spawn thread"); + Ok(CommandHandle { program, arguments, current_dir, child, thread, receiver }) + } + + pub(crate) fn cancel(mut self) { + let _ = self.child.0.kill(); + let _ = self.child.0.wait(); + } + + pub(crate) fn join(mut self) -> io::Result<()> { + let _ = self.child.0.kill(); + let exit_status = self.child.0.wait()?; + let (read_at_least_one_message, error) = self.thread.join()?; + if read_at_least_one_message || exit_status.success() { + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::Other, format!( + "Cargo watcher failed, the command produced no valid metadata (exit code: {exit_status:?}):\n{error}" + ))) + } + } +} diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index 8bcdca5bb828f..f8efb52022205 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -2,22 +2,18 @@ //! another compatible command (f.x. clippy) in a background thread and provide //! LSP diagnostics based on the output of the command. +// FIXME: This crate now handles running `cargo test` needed in the test explorer in +// addition to `cargo check`. Either split it into 3 crates (one for test, one for check +// and one common utilities) or change its name and docs to reflect the current state. + #![warn(rust_2018_idioms, unused_lifetimes)] -use std::{ - ffi::OsString, - fmt, io, - path::PathBuf, - process::{ChildStderr, ChildStdout, Command, Stdio}, - time::Duration, -}; +use std::{fmt, io, path::PathBuf, process::Command, time::Duration}; -use command_group::{CommandGroup, GroupChild}; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; use serde::Deserialize; -use stdx::process::streaming_output; pub use cargo_metadata::diagnostic::{ Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, @@ -25,6 +21,12 @@ pub use cargo_metadata::diagnostic::{ }; use toolchain::Tool; +mod command; +mod test_runner; + +use command::{CommandHandle, ParseFromLine}; +pub use test_runner::{CargoTestHandle, CargoTestMessage, TestState}; + #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum InvocationStrategy { Once, @@ -181,12 +183,12 @@ struct FlycheckActor { /// doesn't provide a way to read sub-process output without blocking, so we /// have to wrap sub-processes output handling in a thread and pass messages /// back over a channel. - command_handle: Option, + command_handle: Option>, } enum Event { RequestStateChange(StateChange), - CheckEvent(Option), + CheckEvent(Option), } const SAVED_FILE_PLACEHOLDER: &str = "$saved_file"; @@ -282,7 +284,7 @@ impl FlycheckActor { self.report_progress(Progress::DidFinish(res)); } Event::CheckEvent(Some(message)) => match message { - CargoMessage::CompilerArtifact(msg) => { + CargoCheckMessage::CompilerArtifact(msg) => { tracing::trace!( flycheck_id = self.id, artifact = msg.target.name, @@ -291,7 +293,7 @@ impl FlycheckActor { self.report_progress(Progress::DidCheckCrate(msg.target.name)); } - CargoMessage::Diagnostic(msg) => { + CargoCheckMessage::Diagnostic(msg) => { tracing::trace!( flycheck_id = self.id, message = msg.message, @@ -448,161 +450,42 @@ impl FlycheckActor { } } -struct JodGroupChild(GroupChild); - -impl Drop for JodGroupChild { - fn drop(&mut self) { - _ = self.0.kill(); - _ = self.0.wait(); - } -} - -/// A handle to a cargo process used for fly-checking. -struct CommandHandle { - /// The handle to the actual cargo process. As we cannot cancel directly from with - /// a read syscall dropping and therefore terminating the process is our best option. - child: JodGroupChild, - thread: stdx::thread::JoinHandle>, - receiver: Receiver, - program: OsString, - arguments: Vec, - current_dir: Option, -} - -impl fmt::Debug for CommandHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CommandHandle") - .field("program", &self.program) - .field("arguments", &self.arguments) - .field("current_dir", &self.current_dir) - .finish() - } +#[allow(clippy::large_enum_variant)] +enum CargoCheckMessage { + CompilerArtifact(cargo_metadata::Artifact), + Diagnostic(Diagnostic), } -impl CommandHandle { - fn spawn(mut command: Command) -> std::io::Result { - command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - let mut child = command.group_spawn().map(JodGroupChild)?; - - let program = command.get_program().into(); - let arguments = command.get_args().map(|arg| arg.into()).collect::>(); - let current_dir = command.get_current_dir().map(|arg| arg.to_path_buf()); - - let stdout = child.0.inner().stdout.take().unwrap(); - let stderr = child.0.inner().stderr.take().unwrap(); - - let (sender, receiver) = unbounded(); - let actor = CargoActor::new(sender, stdout, stderr); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("CommandHandle".to_owned()) - .spawn(move || actor.run()) - .expect("failed to spawn thread"); - Ok(CommandHandle { program, arguments, current_dir, child, thread, receiver }) - } - - fn cancel(mut self) { - let _ = self.child.0.kill(); - let _ = self.child.0.wait(); - } - - fn join(mut self) -> io::Result<()> { - let _ = self.child.0.kill(); - let exit_status = self.child.0.wait()?; - let (read_at_least_one_message, error) = self.thread.join()?; - if read_at_least_one_message || exit_status.success() { - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::Other, format!( - "Cargo watcher failed, the command produced no valid metadata (exit code: {exit_status:?}):\n{error}" - ))) +impl ParseFromLine for CargoCheckMessage { + fn from_line(line: &str, error: &mut String) -> Option { + let mut deserializer = serde_json::Deserializer::from_str(line); + deserializer.disable_recursion_limit(); + if let Ok(message) = JsonMessage::deserialize(&mut deserializer) { + return match message { + // Skip certain kinds of messages to only spend time on what's useful + JsonMessage::Cargo(message) => match message { + cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => { + Some(CargoCheckMessage::CompilerArtifact(artifact)) + } + cargo_metadata::Message::CompilerMessage(msg) => { + Some(CargoCheckMessage::Diagnostic(msg.message)) + } + _ => None, + }, + JsonMessage::Rustc(message) => Some(CargoCheckMessage::Diagnostic(message)), + }; } - } -} -struct CargoActor { - sender: Sender, - stdout: ChildStdout, - stderr: ChildStderr, -} - -impl CargoActor { - fn new(sender: Sender, stdout: ChildStdout, stderr: ChildStderr) -> CargoActor { - CargoActor { sender, stdout, stderr } + error.push_str(line); + error.push('\n'); + None } - fn run(self) -> io::Result<(bool, String)> { - // We manually read a line at a time, instead of using serde's - // stream deserializers, because the deserializer cannot recover - // from an error, resulting in it getting stuck, because we try to - // be resilient against failures. - // - // Because cargo only outputs one JSON object per line, we can - // simply skip a line if it doesn't parse, which just ignores any - // erroneous output. - - let mut stdout_errors = String::new(); - let mut stderr_errors = String::new(); - let mut read_at_least_one_stdout_message = false; - let mut read_at_least_one_stderr_message = false; - let process_line = |line: &str, error: &mut String| { - // Try to deserialize a message from Cargo or Rustc. - let mut deserializer = serde_json::Deserializer::from_str(line); - deserializer.disable_recursion_limit(); - if let Ok(message) = JsonMessage::deserialize(&mut deserializer) { - match message { - // Skip certain kinds of messages to only spend time on what's useful - JsonMessage::Cargo(message) => match message { - cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => { - self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap(); - } - cargo_metadata::Message::CompilerMessage(msg) => { - self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap(); - } - _ => (), - }, - JsonMessage::Rustc(message) => { - self.sender.send(CargoMessage::Diagnostic(message)).unwrap(); - } - } - return true; - } - - error.push_str(line); - error.push('\n'); - false - }; - let output = streaming_output( - self.stdout, - self.stderr, - &mut |line| { - if process_line(line, &mut stdout_errors) { - read_at_least_one_stdout_message = true; - } - }, - &mut |line| { - if process_line(line, &mut stderr_errors) { - read_at_least_one_stderr_message = true; - } - }, - ); - - let read_at_least_one_message = - read_at_least_one_stdout_message || read_at_least_one_stderr_message; - let mut error = stdout_errors; - error.push_str(&stderr_errors); - match output { - Ok(_) => Ok((read_at_least_one_message, error)), - Err(e) => Err(io::Error::new(e.kind(), format!("{e:?}: {error}"))), - } + fn from_eof() -> Option { + None } } -#[allow(clippy::large_enum_variant)] -enum CargoMessage { - CompilerArtifact(cargo_metadata::Artifact), - Diagnostic(Diagnostic), -} - #[derive(Deserialize)] #[serde(untagged)] enum JsonMessage { diff --git a/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs new file mode 100644 index 0000000000000..6dac5899ee3a5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs @@ -0,0 +1,76 @@ +//! This module provides the functionality needed to run `cargo test` in a background +//! thread and report the result of each test in a channel. + +use std::process::Command; + +use crossbeam_channel::Receiver; +use serde::Deserialize; +use toolchain::Tool; + +use crate::command::{CommandHandle, ParseFromLine}; + +#[derive(Debug, Deserialize)] +#[serde(tag = "event", rename_all = "camelCase")] +pub enum TestState { + Started, + Ok, + Ignored, + Failed { stdout: String }, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "type", rename_all = "camelCase")] +pub enum CargoTestMessage { + Test { + name: String, + #[serde(flatten)] + state: TestState, + }, + Suite, + Finished, +} + +impl ParseFromLine for CargoTestMessage { + fn from_line(line: &str, error: &mut String) -> Option { + let mut deserializer = serde_json::Deserializer::from_str(line); + deserializer.disable_recursion_limit(); + if let Ok(message) = CargoTestMessage::deserialize(&mut deserializer) { + return Some(message); + } + + error.push_str(line); + error.push('\n'); + None + } + + fn from_eof() -> Option { + Some(CargoTestMessage::Finished) + } +} + +#[derive(Debug)] +pub struct CargoTestHandle { + handle: CommandHandle, +} + +// Example of a cargo test command: +// cargo test -- module::func -Z unstable-options --format=json + +impl CargoTestHandle { + pub fn new(path: Option<&str>) -> std::io::Result { + let mut cmd = Command::new(Tool::Cargo.path()); + cmd.env("RUSTC_BOOTSTRAP", "1"); + cmd.arg("test"); + cmd.arg("--"); + if let Some(path) = path { + cmd.arg(path); + } + cmd.args(["-Z", "unstable-options"]); + cmd.arg("--format=json"); + Ok(Self { handle: CommandHandle::spawn(cmd)? }) + } + + pub fn receiver(&self) -> &Receiver { + &self.handle.receiver + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 519706c65f29b..21536098b82dd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -348,7 +348,7 @@ impl AttrsWithOwner { .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) .clone(), ModuleOrigin::BlockExpr { id, .. } => { - let tree = db.block_item_tree_query(id); + let tree = db.block_item_tree(id); tree.raw_attrs(AttrOwner::TopLevel).clone() } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index ce8a9eab14a9d..37d37fd331158 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -13,7 +13,6 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{name::Name, HirFileId, InFile}; use la_arena::{Arena, ArenaMap}; -use profile::Count; use rustc_hash::FxHashMap; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; @@ -51,7 +50,6 @@ pub struct Body { pub body_expr: ExprId, /// Block expressions in this body that may contain inner items. block_scopes: Vec, - _c: Count, } pub type ExprPtr = AstPtr; @@ -216,7 +214,6 @@ impl Body { fn shrink_to_fit(&mut self) { let Self { - _c: _, body_expr: _, block_scopes, exprs, @@ -300,7 +297,6 @@ impl Default for Body { params: Default::default(), block_scopes: Default::default(), binding_owners: Default::default(), - _c: Default::default(), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index ad8782d3d1e30..6669127789495 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -10,7 +10,6 @@ use hir_expand::{ ExpandError, InFile, }; use intern::Interned; -use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::AstIdMap; @@ -76,7 +75,6 @@ pub(super) fn lower( params: Vec::new(), body_expr: dummy_expr_id(), block_scopes: Vec::new(), - _c: Count::new(), }, expander, current_try_block_label: None, @@ -705,7 +703,8 @@ impl ExprCollector<'_> { let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else { return self.collect_block(e); }; - let label = self.alloc_label_desugared(Label { name: Name::generate_new_name() }); + let label = self + .alloc_label_desugared(Label { name: Name::generate_new_name(self.body.labels.len()) }); let old_label = self.current_try_block_label.replace(label); let (btail, expr_id) = self.with_labeled_rib(label, |this| { @@ -842,7 +841,7 @@ impl ExprCollector<'_> { this.collect_expr_opt(e.loop_body().map(|it| it.into())) }), }; - let iter_name = Name::generate_new_name(); + let iter_name = Name::generate_new_name(self.body.exprs.len()); let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr); let iter_expr_mut = self.alloc_expr( Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut }, @@ -903,7 +902,7 @@ impl ExprCollector<'_> { Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false }, syntax_ptr, ); - let continue_name = Name::generate_new_name(); + let continue_name = Name::generate_new_name(self.body.bindings.len()); let continue_binding = self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated); let continue_bpat = @@ -918,7 +917,7 @@ impl ExprCollector<'_> { guard: None, expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr), }; - let break_name = Name::generate_new_name(); + let break_name = Name::generate_new_name(self.body.bindings.len()); let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated); let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); self.add_definition_to_binding(break_binding, break_bpat); @@ -1415,16 +1414,10 @@ impl ExprCollector<'_> { ast::Pat::LiteralPat(it) => { Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(it)?.0))) } - ast::Pat::IdentPat(p) => { - let name = - p.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); - Some(Box::new(LiteralOrConst::Const(name.into()))) + pat @ (ast::Pat::IdentPat(_) | ast::Pat::PathPat(_)) => { + let subpat = self.collect_pat(pat.clone(), binding_list); + Some(Box::new(LiteralOrConst::Const(subpat))) } - ast::Pat::PathPat(p) => p - .path() - .and_then(|path| self.expander.parse_path(self.db, path)) - .map(LiteralOrConst::Const) - .map(Box::new), _ => None, }) }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index cd14f7b855a81..b2aab55a6a89a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -635,7 +635,7 @@ impl Printer<'_> { fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) { match literal_or_const { LiteralOrConst::Literal(l) => self.print_literal(l), - LiteralOrConst::Const(c) => self.print_path(c), + LiteralOrConst::Const(c) => self.print_pat(*c), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index f506864902c47..d4c1db8b95b48 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -788,11 +788,12 @@ impl<'a> AssocItemCollector<'a> { }; self.diagnostics.push(diag); } - if let errors @ [_, ..] = parse.errors() { + let errors = parse.errors(); + if !errors.is_empty() { self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error( self.module_id.local_id, error_call_kind(), - errors, + errors.into_boxed_slice(), )); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index f07b1257662d5..5790e600f63c8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -400,7 +400,7 @@ pub(crate) fn lower_struct( item_tree: &ItemTree, fields: &Fields, ) -> StructKind { - let ctx = LowerCtx::with_file_id(db, ast.file_id); + let ctx = LowerCtx::new(db, ast.file_id); match (&ast.value, fields) { (ast::StructKind::Tuple(fl), Fields::Tuple(fields)) => { @@ -415,7 +415,9 @@ pub(crate) fn lower_struct( || FieldData { name: Name::new_tuple_field(i), type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), + visibility: RawVisibility::from_ast(db, fd.visibility(), &mut |range| { + ctx.span_map().span_for_range(range).ctx + }), }, ); } @@ -433,7 +435,9 @@ pub(crate) fn lower_struct( || FieldData { name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), + visibility: RawVisibility::from_ast(db, fd.visibility(), &mut |range| { + ctx.span_map().span_for_range(range).ctx + }), }, ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 68f57600ec450..544ed6bc347d8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -87,14 +87,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; #[salsa::invoke(ItemTree::block_item_tree_query)] - fn block_item_tree_query(&self, block_id: BlockId) -> Arc; - - #[salsa::invoke(crate_def_map_wait)] - #[salsa::transparent] - fn crate_def_map(&self, krate: CrateId) -> Arc; + fn block_item_tree(&self, block_id: BlockId) -> Arc; #[salsa::invoke(DefMap::crate_def_map_query)] - fn crate_def_map_query(&self, krate: CrateId) -> Arc; + fn crate_def_map(&self, krate: CrateId) -> Arc; /// Computes the block-level `DefMap`. #[salsa::invoke(DefMap::block_def_map_query)] @@ -253,11 +249,6 @@ fn include_macro_invoc(db: &dyn DefDatabase, krate: CrateId) -> Vec<(MacroCallId .collect() } -fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "crate_def_map:wait").entered(); - db.crate_def_map_query(krate) -} - fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { let file = db.crate_graph()[crate_id].root_file_id; let item_tree = db.file_item_tree(file.into()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index b99df1ed59348..b0872fcdc0e64 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -1,5 +1,7 @@ //! Macro expansion utilities. +use std::cell::OnceCell; + use base_db::CrateId; use cfg::CfgOptions; use drop_bomb::DropBomb; @@ -18,7 +20,7 @@ use crate::{ #[derive(Debug)] pub struct Expander { cfg_options: CfgOptions, - span_map: SpanMap, + span_map: OnceCell, krate: CrateId, current_file_id: HirFileId, pub(crate) module: ModuleId, @@ -42,7 +44,7 @@ impl Expander { recursion_depth: 0, recursion_limit, cfg_options: db.crate_graph()[module.krate].cfg_options.clone(), - span_map: db.span_map(current_file_id), + span_map: OnceCell::new(), krate: module.krate, } } @@ -100,7 +102,7 @@ impl Expander { } pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> { - LowerCtx::new(db, self.span_map.clone(), self.current_file_id) + LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone()) } pub(crate) fn in_file(&self, value: T) -> InFile { @@ -108,7 +110,15 @@ impl Expander { } pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, self.span_map.as_ref())) + Attrs::filter( + db, + self.krate, + RawAttrs::new( + db.upcast(), + owner, + self.span_map.get_or_init(|| db.span_map(self.current_file_id)).as_ref(), + ), + ) } pub(crate) fn cfg_options(&self) -> &CfgOptions { @@ -120,7 +130,7 @@ impl Expander { } pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::new(db, self.span_map.clone(), self.current_file_id); + let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone()); Path::from_src(&ctx, path) } @@ -165,10 +175,11 @@ impl Expander { let parse = res.value.0.cast::()?; self.recursion_depth += 1; - let old_span_map = std::mem::replace( - &mut self.span_map, - SpanMap::ExpansionSpanMap(res.value.1), - ); + let old_span_map = OnceCell::new(); + if let Some(prev) = self.span_map.take() { + _ = old_span_map.set(prev); + }; + _ = self.span_map.set(SpanMap::ExpansionSpanMap(res.value.1)); let old_file_id = std::mem::replace(&mut self.current_file_id, macro_file.into()); let mark = Mark { @@ -187,6 +198,6 @@ impl Expander { #[derive(Debug)] pub struct Mark { file_id: HirFileId, - span_map: SpanMap, + span_map: OnceCell, bomb: DropBomb, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 26247ba5b507d..0cd4a5db8c345 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -611,8 +611,10 @@ mod tests { let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};")); let ast_path = parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); - let mod_path = - ModPath::from_src(&db, ast_path, db.span_map(pos.file_id.into()).as_ref()).unwrap(); + let mod_path = ModPath::from_src(&db, ast_path, &mut |range| { + db.span_map(pos.file_id.into()).as_ref().span_for_range(range).ctx + }) + .unwrap(); let def_map = module.def_map(&db); let resolved = def_map diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 34b2910b4f5e5..ac0caaf0dc898 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -101,7 +101,7 @@ pub enum Literal { /// Used in range patterns. pub enum LiteralOrConst { Literal(Literal), - Const(Path), + Const(PatId), } impl Literal { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 8db00f9d76e01..ec207a7f9651b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -251,7 +251,7 @@ impl TypeRef { TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) } ast::Type::MacroType(mt) => match mt.macro_call() { - Some(mc) => ctx.ast_id(&mc).map(TypeRef::Macro).unwrap_or(TypeRef::Error), + Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)), None => TypeRef::Error, }, } @@ -398,9 +398,8 @@ pub enum ConstRef { impl ConstRef { pub(crate) fn from_const_arg(lower_ctx: &LowerCtx<'_>, arg: Option) -> Self { if let Some(arg) = arg { - let ast_id = lower_ctx.ast_id(&arg); if let Some(expr) = arg.expr() { - return Self::from_expr(expr, ast_id); + return Self::from_expr(expr, Some(lower_ctx.ast_id(&arg))); } } Self::Scalar(LiteralConstRef::Unknown) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index c7cf611589b0d..bd3d377ec083a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -29,9 +29,6 @@ //! //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its //! surface syntax. -//! -//! Note that we cannot store [`span::Span`]s inside of this, as typing in an item invalidates its -//! encompassing span! mod lower; mod pretty; @@ -50,7 +47,6 @@ use either::Either; use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile}; use intern::Interned; use la_arena::{Arena, Idx, IdxRange, RawIdx}; -use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::{AstIdNode, FileAstId, Span}; @@ -94,8 +90,6 @@ impl fmt::Debug for RawVisibilityId { /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { - _c: Count, - top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, @@ -263,14 +257,6 @@ impl ItemVisibilities { } } -static VIS_PUB: RawVisibility = RawVisibility::Public; -static VIS_PRIV_IMPLICIT: RawVisibility = - RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicitness::Implicit); -static VIS_PRIV_EXPLICIT: RawVisibility = - RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicitness::Explicit); -static VIS_PUB_CRATE: RawVisibility = - RawVisibility::Module(ModPath::from_kind(PathKind::Crate), VisibilityExplicitness::Explicit); - #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { uses: Arena, @@ -403,7 +389,7 @@ impl TreeId { pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc { match self.block { - Some(block) => db.block_item_tree_query(block), + Some(block) => db.block_item_tree(block), None => db.file_item_tree(self.file), } } @@ -562,6 +548,20 @@ impl_index!(fields: Field, variants: Variant, params: Param); impl Index for ItemTree { type Output = RawVisibility; fn index(&self, index: RawVisibilityId) -> &Self::Output { + static VIS_PUB: RawVisibility = RawVisibility::Public; + static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module( + ModPath::from_kind(PathKind::Super(0)), + VisibilityExplicitness::Implicit, + ); + static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module( + ModPath::from_kind(PathKind::Super(0)), + VisibilityExplicitness::Explicit, + ); + static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module( + ModPath::from_kind(PathKind::Crate), + VisibilityExplicitness::Explicit, + ); + match index { RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT, RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT, @@ -821,11 +821,13 @@ impl Use { // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); - let span_map = db.span_map(file_id); - let (_, source_map) = lower::lower_use_tree(db, span_map.as_ref(), ast_use_tree) - .expect("failed to lower use tree"); + let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| { + db.span_map(file_id).span_for_range(range).ctx + }) + .expect("failed to lower use tree"); source_map[index].clone() } + /// Maps a `UseTree` contained in this import back to its AST node. pub fn use_tree_source_map( &self, @@ -836,10 +838,11 @@ impl Use { // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); - let span_map = db.span_map(file_id); - lower::lower_use_tree(db, span_map.as_ref(), ast_use_tree) - .expect("failed to lower use tree") - .1 + lower::lower_use_tree(db, ast_use_tree, &mut |range| { + db.span_map(file_id).span_for_range(range).ctx + }) + .expect("failed to lower use tree") + .1 } } @@ -871,25 +874,19 @@ impl UseTree { prefix: Option, path: &ModPath, ) -> Option<(ModPath, ImportKind)> { - match (prefix, &path.kind) { + match (prefix, path.kind) { (None, _) => Some((path.clone(), ImportKind::Plain)), (Some(mut prefix), PathKind::Plain) => { - for segment in path.segments() { - prefix.push_segment(segment.clone()); - } + prefix.extend(path.segments().iter().cloned()); Some((prefix, ImportKind::Plain)) } - (Some(mut prefix), PathKind::Super(n)) - if *n > 0 && prefix.segments().is_empty() => - { + (Some(mut prefix), PathKind::Super(n)) if n > 0 && prefix.segments().is_empty() => { // `super::super` + `super::rest` match &mut prefix.kind { PathKind::Super(m) => { cov_mark::hit!(concat_super_mod_paths); - *m += *n; - for segment in path.segments() { - prefix.push_segment(segment.clone()); - } + *m += n; + prefix.extend(path.segments().iter().cloned()); Some((prefix, ImportKind::Plain)) } _ => None, @@ -963,10 +960,10 @@ impl ModItem { | ModItem::Mod(_) | ModItem::MacroRules(_) | ModItem::Macro2(_) => None, - ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), - ModItem::Const(konst) => Some(AssocItem::Const(*konst)), - ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), - ModItem::Function(func) => Some(AssocItem::Function(*func)), + &ModItem::MacroCall(call) => Some(AssocItem::MacroCall(call)), + &ModItem::Const(konst) => Some(AssocItem::Const(konst)), + &ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(alias)), + &ModItem::Function(func) => Some(AssocItem::Function(func)), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 21cffafa9522a..bf3d54f4caf44 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -4,7 +4,7 @@ use std::collections::hash_map::Entry; use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId}; use la_arena::Arena; -use span::AstIdMap; +use span::{AstIdMap, SyntaxContextId}; use syntax::{ ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString}, AstNode, @@ -45,7 +45,7 @@ impl<'a> Ctx<'a> { db, tree: ItemTree::default(), source_ast_id_map: db.ast_id_map(file), - body_ctx: crate::lower::LowerCtx::with_file_id(db, file), + body_ctx: crate::lower::LowerCtx::new(db, file), } } @@ -535,7 +535,9 @@ impl<'a> Ctx<'a> { fn lower_use(&mut self, use_item: &ast::Use) -> Option> { let visibility = self.lower_visibility(use_item); let ast_id = self.source_ast_id_map.ast_id(use_item); - let (use_tree, _) = lower_use_tree(self.db, self.span_map(), use_item.use_tree()?)?; + let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| { + self.span_map().span_for_range(range).ctx + })?; let res = Use { visibility, ast_id, use_tree }; Some(id(self.data().uses.alloc(res))) @@ -558,7 +560,9 @@ impl<'a> Ctx<'a> { fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { let span_map = self.span_map(); - let path = Interned::new(ModPath::from_src(self.db.upcast(), m.path()?, span_map)?); + let path = Interned::new(ModPath::from_src(self.db.upcast(), m.path()?, &mut |range| { + span_map.span_for_range(range).ctx + })?); let ast_id = self.source_ast_id_map.ast_id(m); let expand_to = hir_expand::ExpandTo::from_call_site(m); let res = MacroCall { @@ -672,8 +676,9 @@ impl<'a> Ctx<'a> { } fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId { - let vis = - RawVisibility::from_opt_ast_with_span_map(self.db, item.visibility(), self.span_map()); + let vis = RawVisibility::from_ast(self.db, item.visibility(), &mut |range| { + self.span_map().span_for_range(range).ctx + }); self.data().vis.alloc(vis) } @@ -745,12 +750,15 @@ fn lower_abi(abi: ast::Abi) -> Interned { struct UseTreeLowering<'a> { db: &'a dyn DefDatabase, - span_map: SpanMapRef<'a>, mapping: Arena, } impl UseTreeLowering<'_> { - fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option { + fn lower_use_tree( + &mut self, + tree: ast::UseTree, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, + ) -> Option { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { // E.g. use something::{{{inner}}}; @@ -758,15 +766,17 @@ impl UseTreeLowering<'_> { // E.g. `use something::{inner}` (prefix is `None`, path is `something`) // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) Some(path) => { - match ModPath::from_src(self.db.upcast(), path, self.span_map) { + match ModPath::from_src(self.db.upcast(), path, span_for_range) { Some(it) => Some(it), None => return None, // FIXME: report errors somewhere } } }; - let list = - use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect(); + let list = use_tree_list + .use_trees() + .filter_map(|tree| self.lower_use_tree(tree, span_for_range)) + .collect(); Some( self.use_tree( @@ -777,7 +787,7 @@ impl UseTreeLowering<'_> { } else { let is_glob = tree.star_token().is_some(); let path = match tree.path() { - Some(path) => Some(ModPath::from_src(self.db.upcast(), path, self.span_map)?), + Some(path) => Some(ModPath::from_src(self.db.upcast(), path, span_for_range)?), None => None, }; let alias = tree.rename().map(|a| { @@ -813,10 +823,10 @@ impl UseTreeLowering<'_> { pub(crate) fn lower_use_tree( db: &dyn DefDatabase, - span_map: SpanMapRef<'_>, tree: ast::UseTree, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, ) -> Option<(UseTree, Arena)> { - let mut lowering = UseTreeLowering { db, span_map, mapping: Arena::new() }; - let tree = lowering.lower_use_tree(tree)?; + let mut lowering = UseTreeLowering { db, mapping: Arena::new() }; + let tree = lowering.lower_use_tree(tree, span_for_range)?; Some((tree, lowering.mapping)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index de3ab57a1243b..d63f2268aa4c7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1341,8 +1341,11 @@ impl AsMacroCall for InFile<&ast::MacroCall> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); let span_map = db.span_map(self.file_id); - let path = - self.value.path().and_then(|path| path::ModPath::from_src(db, path, span_map.as_ref())); + let path = self.value.path().and_then(|path| { + path::ModPath::from_src(db, path, &mut |range| { + span_map.as_ref().span_for_range(range).ctx + }) + }); let Some(path) = path else { return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation"))); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index 2fa6acdf1751e..d574d80a8e0d4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -13,39 +13,36 @@ use crate::{db::DefDatabase, path::Path}; pub struct LowerCtx<'a> { pub db: &'a dyn DefDatabase, - span_map: SpanMap, - // FIXME: This optimization is probably pointless, ast id map should pretty much always exist anyways. - ast_id_map: Option<(HirFileId, OnceCell>)>, + file_id: HirFileId, + span_map: OnceCell, + ast_id_map: OnceCell>, } impl<'a> LowerCtx<'a> { - pub fn new(db: &'a dyn DefDatabase, span_map: SpanMap, file_id: HirFileId) -> Self { - LowerCtx { db, span_map, ast_id_map: Some((file_id, OnceCell::new())) } + pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { + LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() } } - pub fn with_file_id(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { - LowerCtx { - db, - span_map: db.span_map(file_id), - ast_id_map: Some((file_id, OnceCell::new())), - } - } - - pub fn with_span_map(db: &'a dyn DefDatabase, span_map: SpanMap) -> Self { - LowerCtx { db, span_map, ast_id_map: None } + pub fn with_span_map_cell( + db: &'a dyn DefDatabase, + file_id: HirFileId, + span_map: OnceCell, + ) -> Self { + LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() } } pub(crate) fn span_map(&self) -> SpanMapRef<'_> { - self.span_map.as_ref() + self.span_map.get_or_init(|| self.db.span_map(self.file_id)).as_ref() } pub(crate) fn lower_path(&self, ast: ast::Path) -> Option { Path::from_src(self, ast) } - pub(crate) fn ast_id(&self, item: &N) -> Option> { - let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?; - let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id)); - Some(InFile::new(file_id, ast_id_map.ast_id(item))) + pub(crate) fn ast_id(&self, item: &N) -> AstId { + InFile::new( + self.file_id, + self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item), + ) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 270468ad0a622..764617eafb7bb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -65,7 +65,6 @@ use hir_expand::{ }; use itertools::Itertools; use la_arena::Arena; -use profile::Count; use rustc_hash::{FxHashMap, FxHashSet}; use span::FileAstId; use stdx::format_to; @@ -95,7 +94,6 @@ use crate::{ /// is computed by the `block_def_map` query. #[derive(Debug, PartialEq, Eq)] pub struct DefMap { - _c: Count, /// When this is a block def map, this will hold the block id of the block and module that /// contains this block. block: Option, @@ -154,6 +152,23 @@ struct DefMapCrateData { } impl DefMapCrateData { + fn new(edition: Edition) -> Self { + Self { + extern_prelude: FxHashMap::default(), + exported_derives: FxHashMap::default(), + fn_proc_macro_mapping: FxHashMap::default(), + proc_macro_loading_error: None, + registered_attrs: Vec::new(), + registered_tools: Vec::new(), + unstable_features: FxHashSet::default(), + rustc_coherence_is_core: false, + no_core: false, + no_std: false, + edition, + recursion_limit: None, + } + } + fn shrink_to_fit(&mut self) { let Self { extern_prelude, @@ -305,67 +320,67 @@ impl DefMap { /// The module id of a crate or block root. pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); - pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { + pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc { let crate_graph = db.crate_graph(); - let krate_name = crate_graph[krate].display_name.as_deref().unwrap_or_default(); - - let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?krate_name).entered(); + let krate = &crate_graph[crate_id]; + let name = krate.display_name.as_deref().unwrap_or_default(); + let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?name).entered(); - let crate_graph = db.crate_graph(); + let module_data = ModuleData::new( + ModuleOrigin::CrateRoot { definition: krate.root_file_id }, + Visibility::Public, + ); - let edition = crate_graph[krate].edition; - let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id }; - let def_map = DefMap::empty(krate, edition, ModuleData::new(origin, Visibility::Public)); - let def_map = collector::collect_defs( - db, - def_map, - TreeId::new(crate_graph[krate].root_file_id.into(), None), + let def_map = DefMap::empty( + crate_id, + Arc::new(DefMapCrateData::new(krate.edition)), + module_data, + None, ); + let def_map = + collector::collect_defs(db, def_map, TreeId::new(krate.root_file_id.into(), None)); Arc::new(def_map) } pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc { - let block: BlockLoc = block_id.lookup(db); - - let parent_map = block.module.def_map(db); - let krate = block.module.krate; - let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0)); - // NB: we use `None` as block here, which would be wrong for implicit - // modules declared by blocks with items. At the moment, we don't use - // this visibility for anything outside IDE, so that's probably OK. + let BlockLoc { ast_id, module } = block_id.lookup(db); + let visibility = Visibility::Module( - ModuleId { krate, local_id, block: None }, + ModuleId { krate: module.krate, local_id: Self::ROOT, block: module.block }, VisibilityExplicitness::Implicit, ); - let module_data = ModuleData::new( - ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id }, - visibility, + let module_data = + ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility); + + let parent_map = module.def_map(db); + let def_map = DefMap::empty( + module.krate, + parent_map.data.clone(), + module_data, + Some(BlockInfo { + block: block_id, + parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id }, + }), ); - let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data); - def_map.data = parent_map.data.clone(); - def_map.block = Some(BlockInfo { - block: block_id, - parent: BlockRelativeModuleId { - block: block.module.block, - local_id: block.module.local_id, - }, - }); - let def_map = - collector::collect_defs(db, def_map, TreeId::new(block.ast_id.file_id, Some(block_id))); + collector::collect_defs(db, def_map, TreeId::new(ast_id.file_id, Some(block_id))); Arc::new(def_map) } - fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap { + fn empty( + krate: CrateId, + crate_data: Arc, + module_data: ModuleData, + block: Option, + ) -> DefMap { let mut modules: Arena = Arena::default(); let root = modules.alloc(module_data); assert_eq!(root, Self::ROOT); DefMap { - _c: Count::new(), - block: None, + block, modules, krate, prelude: None, @@ -373,23 +388,36 @@ impl DefMap { derive_helpers_in_scope: FxHashMap::default(), diagnostics: Vec::new(), enum_definitions: FxHashMap::default(), - data: Arc::new(DefMapCrateData { - extern_prelude: FxHashMap::default(), - exported_derives: FxHashMap::default(), - fn_proc_macro_mapping: FxHashMap::default(), - proc_macro_loading_error: None, - registered_attrs: Vec::new(), - registered_tools: Vec::new(), - unstable_features: FxHashSet::default(), - rustc_coherence_is_core: false, - no_core: false, - no_std: false, - edition, - recursion_limit: None, - }), + data: crate_data, + } + } + fn shrink_to_fit(&mut self) { + // Exhaustive match to require handling new fields. + let Self { + macro_use_prelude, + diagnostics, + modules, + derive_helpers_in_scope, + block: _, + krate: _, + prelude: _, + data: _, + enum_definitions, + } = self; + + macro_use_prelude.shrink_to_fit(); + diagnostics.shrink_to_fit(); + modules.shrink_to_fit(); + derive_helpers_in_scope.shrink_to_fit(); + enum_definitions.shrink_to_fit(); + for (_, module) in modules.iter_mut() { + module.children.shrink_to_fit(); + module.scope.shrink_to_fit(); } } +} +impl DefMap { pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator + '_ { self.modules .iter() @@ -440,26 +468,6 @@ impl DefMap { self.krate } - pub(crate) fn block_id(&self) -> Option { - self.block.map(|block| block.block) - } - - pub(crate) fn prelude(&self) -> Option<(ModuleId, Option)> { - self.prelude - } - - pub(crate) fn extern_prelude( - &self, - ) -> impl Iterator))> + '_ { - self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) - } - - pub(crate) fn macro_use_prelude( - &self, - ) -> impl Iterator))> + '_ { - self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) - } - pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { let block = self.block.map(|b| b.block); ModuleId { krate: self.krate, local_id, block } @@ -475,68 +483,6 @@ impl DefMap { self.module_id(Self::ROOT) } - pub(crate) fn resolve_path( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - expected_macro_subns: Option, - ) -> (PerNs, Option) { - let res = self.resolve_path_fp_with_macro( - db, - ResolveMode::Other, - original_module, - path, - shadow, - expected_macro_subns, - ); - (res.resolved_def, res.segment_index) - } - - pub(crate) fn resolve_path_locally( - &self, - db: &dyn DefDatabase, - original_module: LocalModuleId, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> (PerNs, Option) { - let res = self.resolve_path_fp_with_macro_single( - db, - ResolveMode::Other, - original_module, - path, - shadow, - None, // Currently this function isn't used for macro resolution. - ); - (res.resolved_def, res.segment_index) - } - - /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. - /// - /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns - /// `None`, iteration continues. - pub(crate) fn with_ancestor_maps( - &self, - db: &dyn DefDatabase, - local_mod: LocalModuleId, - f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option, - ) -> Option { - if let Some(it) = f(self, local_mod) { - return Some(it); - } - let mut block = self.block; - while let Some(block_info) = block { - let parent = block_info.parent.def_map(db, self.krate); - if let Some(it) = f(&parent, block_info.parent.local_id) { - return Some(it); - } - block = parent.block; - } - - None - } - /// If this `DefMap` is for a block expression, returns the module containing the block (which /// might again be a block, or a module inside a block). pub fn parent(&self) -> Option { @@ -559,6 +505,16 @@ impl DefMap { } } + /// Get a reference to the def map's diagnostics. + pub fn diagnostics(&self) -> &[DefDiagnostic] { + self.diagnostics.as_slice() + } + + pub fn recursion_limit(&self) -> u32 { + // 128 is the default in rustc + self.data.recursion_limit.unwrap_or(128) + } + // FIXME: this can use some more human-readable format (ideally, an IR // even), as this should be a great debugging aid. pub fn dump(&self, db: &dyn DefDatabase) -> String { @@ -608,41 +564,89 @@ impl DefMap { format_to!(buf, "crate scope\n"); buf } +} - fn shrink_to_fit(&mut self) { - // Exhaustive match to require handling new fields. - let Self { - _c: _, - macro_use_prelude, - diagnostics, - modules, - derive_helpers_in_scope, - block: _, - krate: _, - prelude: _, - data: _, - enum_definitions, - } = self; +impl DefMap { + pub(crate) fn block_id(&self) -> Option { + self.block.map(|block| block.block) + } - macro_use_prelude.shrink_to_fit(); - diagnostics.shrink_to_fit(); - modules.shrink_to_fit(); - derive_helpers_in_scope.shrink_to_fit(); - enum_definitions.shrink_to_fit(); - for (_, module) in modules.iter_mut() { - module.children.shrink_to_fit(); - module.scope.shrink_to_fit(); - } + pub(crate) fn prelude(&self) -> Option<(ModuleId, Option)> { + self.prelude } - /// Get a reference to the def map's diagnostics. - pub fn diagnostics(&self) -> &[DefDiagnostic] { - self.diagnostics.as_slice() + pub(crate) fn extern_prelude( + &self, + ) -> impl Iterator))> + '_ { + self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) } - pub fn recursion_limit(&self) -> u32 { - // 128 is the default in rustc - self.data.recursion_limit.unwrap_or(128) + pub(crate) fn macro_use_prelude( + &self, + ) -> impl Iterator))> + '_ { + self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) + } + + pub(crate) fn resolve_path( + &self, + db: &dyn DefDatabase, + original_module: LocalModuleId, + path: &ModPath, + shadow: BuiltinShadowMode, + expected_macro_subns: Option, + ) -> (PerNs, Option) { + let res = self.resolve_path_fp_with_macro( + db, + ResolveMode::Other, + original_module, + path, + shadow, + expected_macro_subns, + ); + (res.resolved_def, res.segment_index) + } + + pub(crate) fn resolve_path_locally( + &self, + db: &dyn DefDatabase, + original_module: LocalModuleId, + path: &ModPath, + shadow: BuiltinShadowMode, + ) -> (PerNs, Option) { + let res = self.resolve_path_fp_with_macro_single( + db, + ResolveMode::Other, + original_module, + path, + shadow, + None, // Currently this function isn't used for macro resolution. + ); + (res.resolved_def, res.segment_index) + } + + /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. + /// + /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns + /// `None`, iteration continues. + pub(crate) fn with_ancestor_maps( + &self, + db: &dyn DefDatabase, + local_mod: LocalModuleId, + f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option, + ) -> Option { + if let Some(it) = f(self, local_mod) { + return Some(it); + } + let mut block = self.block; + while let Some(block_info) = block { + let parent = block_info.parent.def_map(db, self.krate); + if let Some(it) = f(&parent, block_info.parent.local_id) { + return Some(it); + } + block = parent.block; + } + + None } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 538e735688bab..f9fe6d3b903b3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -64,19 +64,18 @@ static FIXED_POINT_LIMIT: Limit = Limit::new(8192); pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap { let crate_graph = db.crate_graph(); - let mut deps = FxHashMap::default(); - // populate external prelude and dependency list let krate = &crate_graph[def_map.krate]; + + // populate external prelude and dependency list + let mut deps = + FxHashMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default()); for dep in &krate.dependencies { tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); deps.insert(dep.as_name(), dep.clone()); } - let cfg_options = &krate.cfg_options; - - let is_proc_macro = krate.is_proc_macro; - let proc_macros = if is_proc_macro { + let proc_macros = if krate.is_proc_macro { match db.proc_macros().get(&def_map.krate) { Some(Ok(proc_macros)) => { Ok(proc_macros @@ -124,11 +123,11 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI indeterminate_imports: Vec::new(), unresolved_macros: Vec::new(), mod_dirs: FxHashMap::default(), - cfg_options, + cfg_options: &krate.cfg_options, proc_macros, from_glob_import: Default::default(), skip_attrs: Default::default(), - is_proc_macro, + is_proc_macro: krate.is_proc_macro, }; if tree_id.is_block() { collector.seed_with_inner(tree_id); @@ -302,71 +301,50 @@ impl DefCollector<'_> { return; } } - let attr_name = match attr.path.as_ident() { - Some(name) => name, - None => continue, - }; + let Some(attr_name) = attr.path.as_ident() else { continue }; - if *attr_name == hir_expand::name![recursion_limit] { - if let Some(limit) = attr.string_value() { - if let Ok(limit) = limit.parse() { - crate_data.recursion_limit = Some(limit); + match () { + () if *attr_name == hir_expand::name![recursion_limit] => { + if let Some(limit) = attr.string_value() { + if let Ok(limit) = limit.parse() { + crate_data.recursion_limit = Some(limit); + } } } - continue; - } - - if *attr_name == hir_expand::name![crate_type] { - if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { - self.is_proc_macro = true; + () if *attr_name == hir_expand::name![crate_type] => { + if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { + self.is_proc_macro = true; + } } - continue; - } - - if *attr_name == hir_expand::name![no_core] { - crate_data.no_core = true; - continue; - } - - if *attr_name == hir_expand::name![no_std] { - crate_data.no_std = true; - continue; - } - - if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { - crate_data.rustc_coherence_is_core = true; - continue; - } - - if *attr_name == hir_expand::name![feature] { - let features = attr - .parse_path_comma_token_tree(self.db.upcast()) - .into_iter() - .flatten() - .filter_map(|(feat, _)| match feat.segments() { - [name] => Some(name.to_smol_str()), - _ => None, - }); - crate_data.unstable_features.extend(features); - } - - let attr_is_register_like = *attr_name == hir_expand::name![register_attr] - || *attr_name == hir_expand::name![register_tool]; - if !attr_is_register_like { - continue; - } - - let registered_name = match attr.single_ident_value() { - Some(ident) => ident.as_name(), - _ => continue, - }; - - if *attr_name == hir_expand::name![register_attr] { - crate_data.registered_attrs.push(registered_name.to_smol_str()); - cov_mark::hit!(register_attr); - } else { - crate_data.registered_tools.push(registered_name.to_smol_str()); - cov_mark::hit!(register_tool); + () if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true, + () if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true, + () if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => { + crate_data.rustc_coherence_is_core = true; + } + () if *attr_name == hir_expand::name![feature] => { + let features = attr + .parse_path_comma_token_tree(self.db.upcast()) + .into_iter() + .flatten() + .filter_map(|(feat, _)| match feat.segments() { + [name] => Some(name.to_smol_str()), + _ => None, + }); + crate_data.unstable_features.extend(features); + } + () if *attr_name == hir_expand::name![register_attr] => { + if let Some(ident) = attr.single_ident_value() { + crate_data.registered_attrs.push(ident.text.clone()); + cov_mark::hit!(register_attr); + } + } + () if *attr_name == hir_expand::name![register_tool] => { + if let Some(ident) = attr.single_ident_value() { + crate_data.registered_tools.push(ident.text.clone()); + cov_mark::hit!(register_tool); + } + } + () => (), } } @@ -409,6 +387,7 @@ impl DefCollector<'_> { // main name resolution fixed-point loop. let mut i = 0; 'resolve_attr: loop { + let _p = tracing::span!(tracing::Level::INFO, "resolve_macros loop").entered(); 'resolve_macros: loop { self.db.unwind_if_cancelled(); @@ -466,9 +445,8 @@ impl DefCollector<'_> { // Additionally, while the proc macro entry points must be `pub`, they are not publicly // exported in type/value namespace. This function reduces the visibility of all items // in the crate root that aren't proc macros. - let root = DefMap::ROOT; - let module_id = self.def_map.module_id(root); - let root = &mut self.def_map.modules[root]; + let module_id = self.def_map.module_id(DefMap::ROOT); + let root = &mut self.def_map.modules[DefMap::ROOT]; root.scope.censor_non_proc_macros(module_id); } } @@ -828,12 +806,10 @@ impl DefCollector<'_> { return PartialResolvedImport::Unresolved; } - if let Some(krate) = res.krate { - if krate != self.def_map.krate { - return PartialResolvedImport::Resolved( - def.filter_visibility(|v| matches!(v, Visibility::Public)), - ); - } + if res.from_differing_crate { + return PartialResolvedImport::Resolved( + def.filter_visibility(|v| matches!(v, Visibility::Public)), + ); } // Check whether all namespaces are resolved. @@ -1408,7 +1384,9 @@ impl DefCollector<'_> { // First, fetch the raw expansion result for purposes of error reporting. This goes through // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve // incrementality). - let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id); + // FIXME: This kind of error fetching feels a bit odd? + let ExpandResult { value: errors, err } = + self.db.parse_macro_expansion_error(macro_call_id); if let Some(err) = err { let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); let diag = match err { @@ -1422,7 +1400,7 @@ impl DefCollector<'_> { self.def_map.diagnostics.push(diag); } - if let errors @ [_, ..] = &*value { + if !errors.is_empty() { let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors); self.def_map.diagnostics.push(diag); @@ -1920,7 +1898,7 @@ impl ModCollector<'_, '_> { } fn collect_module(&mut self, module_id: FileItemTreeId, attrs: &Attrs) { - let path_attr = attrs.by_key("path").string_value(); + let path_attr = attrs.by_key("path").string_value().map(SmolStr::as_str); let is_macro_use = attrs.by_key("macro_use").exists(); let module = &self.item_tree[module_id]; match &module.kind { @@ -1934,25 +1912,26 @@ impl ModCollector<'_, '_> { module_id, ); - if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr) - { - ModCollector { - def_collector: &mut *self.def_collector, - macro_depth: self.macro_depth, - module_id, - tree_id: self.tree_id, - item_tree: self.item_tree, - mod_dir, - } - .collect_in_top_module(items); - if is_macro_use { - self.import_all_legacy_macros(module_id); - } + let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr) + else { + return; + }; + ModCollector { + def_collector: &mut *self.def_collector, + macro_depth: self.macro_depth, + module_id, + tree_id: self.tree_id, + item_tree: self.item_tree, + mod_dir, + } + .collect_in_top_module(items); + if is_macro_use { + self.import_all_legacy_macros(module_id); } } // out of line module, resolve, parse and recurse ModKind::Outline => { - let ast_id = AstId::new(self.tree_id.file_id(), module.ast_id); + let ast_id = AstId::new(self.file_id(), module.ast_id); let db = self.def_collector.db; match self.mod_dir.resolve_declaration(db, self.file_id(), &module.name, path_attr) { @@ -2445,7 +2424,7 @@ mod tests { use base_db::SourceDatabase; use test_fixture::WithFixture; - use crate::test_db::TestDB; + use crate::{nameres::DefMapCrateData, test_db::TestDB}; use super::*; @@ -2476,8 +2455,12 @@ mod tests { let edition = db.crate_graph()[krate].edition; let module_origin = ModuleOrigin::CrateRoot { definition: file_id }; - let def_map = - DefMap::empty(krate, edition, ModuleData::new(module_origin, Visibility::Public)); + let def_map = DefMap::empty( + krate, + Arc::new(DefMapCrateData::new(edition)), + ModuleData::new(module_origin, Visibility::Public), + None, + ); do_collect_defs(&db, def_map) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs index 161b2c0599099..8c7fdaaf58b32 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs @@ -1,5 +1,7 @@ //! Diagnostics emitted during DefMap construction. +use std::ops::Not; + use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind}; @@ -16,27 +18,16 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { UnresolvedModule { ast: AstId, candidates: Box<[String]> }, - UnresolvedExternCrate { ast: AstId }, - UnresolvedImport { id: ItemTreeId, index: Idx }, - UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, - UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, - UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, - MacroError { ast: MacroCallKind, message: String }, - MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> }, - UnimplementedBuiltinMacro { ast: AstId }, - InvalidDeriveTarget { ast: AstId, id: usize }, - MalformedDerive { ast: AstId, id: usize }, - MacroDefError { ast: AstId, message: String }, } @@ -45,11 +36,12 @@ pub struct DefDiagnostics(Option>>); impl DefDiagnostics { pub fn new(diagnostics: Vec) -> Self { - Self(if diagnostics.is_empty() { - None - } else { - Some(triomphe::Arc::new(diagnostics.into_boxed_slice())) - }) + Self( + diagnostics + .is_empty() + .not() + .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())), + ) } pub fn iter(&self) -> impl Iterator { @@ -125,14 +117,11 @@ impl DefDiagnostic { pub(crate) fn macro_expansion_parse_error( container: LocalModuleId, ast: MacroCallKind, - errors: &[SyntaxError], + errors: Box<[SyntaxError]>, ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::MacroExpansionParseError { - ast, - errors: errors.to_vec().into_boxed_slice(), - }, + kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors }, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index c45200e2de9df..696fb6a961cd7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -3,7 +3,6 @@ use arrayvec::ArrayVec; use base_db::{AnchoredPath, FileId}; use hir_expand::{name::Name, HirFileIdExt, MacroFileIdExt}; use limit::Limit; -use syntax::SmolStr; use crate::{db::DefDatabase, HirFileId}; @@ -29,9 +28,9 @@ impl ModDir { pub(super) fn descend_into_definition( &self, name: &Name, - attr_path: Option<&SmolStr>, + attr_path: Option<&str>, ) -> Option { - let path = match attr_path.map(SmolStr::as_str) { + let path = match attr_path { None => { let mut path = self.dir_path.clone(); path.push(&name.unescaped().to_smol_str()); @@ -63,10 +62,9 @@ impl ModDir { db: &dyn DefDatabase, file_id: HirFileId, name: &Name, - attr_path: Option<&SmolStr>, + attr_path: Option<&str>, ) -> Result<(FileId, bool, ModDir), Box<[String]>> { let name = name.unescaped(); - let orig_file_id = file_id.original_file_respecting_includes(db.upcast()); let mut candidate_files = ArrayVec::<_, 2>::new(); match attr_path { @@ -91,17 +89,19 @@ impl ModDir { } }; + let orig_file_id = file_id.original_file_respecting_includes(db.upcast()); for candidate in candidate_files.iter() { let path = AnchoredPath { anchor: orig_file_id, path: candidate.as_str() }; if let Some(file_id) = db.resolve_path(path) { let is_mod_rs = candidate.ends_with("/mod.rs"); - let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { - (DirPath::empty(), false) + let root_dir_owner = is_mod_rs || attr_path.is_some(); + let dir_path = if root_dir_owner { + DirPath::empty() } else { - (DirPath::new(format!("{}/", name.display(db.upcast()))), true) + DirPath::new(format!("{}/", name.display(db.upcast()))) }; - if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) { + if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) { return Ok((file_id, is_mod_rs, mod_dir)); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 1e13f7f8fd018..9e53b03728304 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -22,7 +22,7 @@ use crate::{ path::{ModPath, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, - AdtId, CrateId, LocalModuleId, ModuleDefId, + AdtId, LocalModuleId, ModuleDefId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -42,21 +42,21 @@ pub(super) struct ResolvePathResult { pub(super) resolved_def: PerNs, pub(super) segment_index: Option, pub(super) reached_fixedpoint: ReachedFixedPoint, - pub(super) krate: Option, + pub(super) from_differing_crate: bool, } impl ResolvePathResult { fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { - ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) + ResolvePathResult::new(PerNs::none(), reached_fixedpoint, None, false) } - fn with( + fn new( resolved_def: PerNs, reached_fixedpoint: ReachedFixedPoint, segment_index: Option, - krate: Option, + from_differing_crate: bool, ) -> ResolvePathResult { - ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate } + ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, from_differing_crate } } } @@ -134,7 +134,19 @@ impl DefMap { // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths. expected_macro_subns: Option, ) -> ResolvePathResult { - let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); + let mut result = self.resolve_path_fp_with_macro_single( + db, + mode, + original_module, + path, + shadow, + expected_macro_subns, + ); + + if self.block.is_none() { + // If we're in the root `DefMap`, we can resolve the path directly. + return result; + } let mut arc; let mut current_map = self; @@ -153,8 +165,7 @@ impl DefMap { if result.reached_fixedpoint == ReachedFixedPoint::No { result.reached_fixedpoint = new.reached_fixedpoint; } - // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? - result.krate = result.krate.or(new.krate); + result.from_differing_crate |= new.from_differing_crate; result.segment_index = match (result.segment_index, new.segment_index) { (Some(idx), None) => Some(idx), (Some(old), Some(new)) => Some(old.max(new)), @@ -333,11 +344,11 @@ impl DefMap { // expectation is discarded. let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow, None); - return ResolvePathResult::with( + return ResolvePathResult::new( def, ReachedFixedPoint::Yes, s.map(|s| s + i), - Some(module.krate), + true, ); } @@ -385,11 +396,11 @@ impl DefMap { match res { Some(res) => res, None => { - return ResolvePathResult::with( + return ResolvePathResult::new( PerNs::types(e.into(), vis, imp), ReachedFixedPoint::Yes, Some(i), - Some(self.krate), + false, ) } } @@ -403,11 +414,11 @@ impl DefMap { curr, ); - return ResolvePathResult::with( + return ResolvePathResult::new( PerNs::types(s, vis, imp), ReachedFixedPoint::Yes, Some(i), - Some(self.krate), + false, ); } }; @@ -416,7 +427,7 @@ impl DefMap { .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module)); } - ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) + ResolvePathResult::new(curr_per_ns, ReachedFixedPoint::Yes, None, false) } fn resolve_name_in_module( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 0f3fac1cecd02..1ef8fa772a11c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -2,8 +2,8 @@ use std::iter; -use hir_expand::{span_map::SpanMapRef, InFile}; use la_arena::ArenaMap; +use span::SyntaxContextId; use syntax::ast; use triomphe::Arc; @@ -34,36 +34,25 @@ impl RawVisibility { } pub(crate) fn from_ast( - db: &dyn DefDatabase, - node: InFile>, - ) -> RawVisibility { - let node = match node.transpose() { - None => return RawVisibility::private(), - Some(node) => node, - }; - Self::from_ast_with_span_map(db, node.value, db.span_map(node.file_id).as_ref()) - } - - pub(crate) fn from_opt_ast_with_span_map( db: &dyn DefDatabase, node: Option, - span_map: SpanMapRef<'_>, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, ) -> RawVisibility { let node = match node { None => return RawVisibility::private(), Some(node) => node, }; - Self::from_ast_with_span_map(db, node, span_map) + Self::from_ast_with_span_map(db, node, span_for_range) } fn from_ast_with_span_map( db: &dyn DefDatabase, node: ast::Visibility, - span_map: SpanMapRef<'_>, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, ) -> RawVisibility { let path = match node.kind() { ast::VisibilityKind::In(path) => { - let path = ModPath::from_src(db.upcast(), path, span_map); + let path = ModPath::from_src(db.upcast(), path, span_for_range); match path { None => return RawVisibility::private(), Some(path) => path, diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index 506a188a211dc..4f3080801565d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -28,7 +28,6 @@ intern.workspace = true base-db.workspace = true cfg.workspace = true syntax.workspace = true -profile.workspace = true tt.workspace = true mbe.workspace = true limit.workspace = true @@ -38,4 +37,4 @@ span.workspace = true expect-test = "1.4.0" [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 1c92dea38e6d1..7793e99532315 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -90,7 +90,7 @@ impl RawAttrs { } /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. - // FIXME: This should return a different type + // FIXME: This should return a different type, signaling it was filtered? pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs { let has_cfg_attrs = self .iter() @@ -201,7 +201,9 @@ impl Attr { span_map: SpanMapRef<'_>, id: AttrId, ) -> Option { - let path = Interned::new(ModPath::from_src(db, ast.path()?, span_map)?); + let path = Interned::new(ModPath::from_src(db, ast.path()?, &mut |range| { + span_map.span_for_range(range).ctx + })?); let span = span_map.span_for_range(ast.syntax().text_range()); let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { let value = match lit.kind() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs index 903b0d4807008..a0102f36aff51 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs @@ -4,23 +4,17 @@ use span::{MacroCallId, Span}; use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind}; macro_rules! register_builtin { - ($expand_fn:ident: $(($name:ident, $variant:ident) => $expand:ident),* ) => { + ($(($name:ident, $variant:ident) => $expand:ident),* ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinAttrExpander { $($variant),* } impl BuiltinAttrExpander { - pub fn $expand_fn( - &self, - db: &dyn ExpandDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { + pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree) -> ExpandResult { + match *self { $( BuiltinAttrExpander::$variant => $expand, )* - }; - expander(db, id, tt) + } } fn find_by_name(name: &name::Name) -> Option { @@ -35,6 +29,15 @@ macro_rules! register_builtin { } impl BuiltinAttrExpander { + pub fn expand( + &self, + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> ExpandResult { + self.expander()(db, id, tt) + } + pub fn is_derive(self) -> bool { matches!(self, BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst) } @@ -46,7 +49,7 @@ impl BuiltinAttrExpander { } } -register_builtin! { expand: +register_builtin! { (bench, Bench) => dummy_attr_expand, (cfg, Cfg) => dummy_attr_expand, (cfg_attr, CfgAttr) => dummy_attr_expand, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index 2795487514349..66dec7d89e5a1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -10,10 +10,12 @@ use crate::{ hygiene::span_with_def_site_ctxt, name::{AsName, Name}, quote::dollar_crate, - span_map::SpanMapRef, + span_map::ExpansionSpanMap, tt, }; -use syntax::ast::{self, AstNode, FieldList, HasAttrs, HasGenericParams, HasName, HasTypeBounds}; +use syntax::ast::{ + self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds, +}; use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult}; @@ -25,20 +27,10 @@ macro_rules! register_builtin { } impl BuiltinDeriveExpander { - pub fn expand( - &self, - db: &dyn ExpandDatabase, - id: MacroCallId, - tt: &ast::Adt, - token_map: SpanMapRef<'_>, - ) -> ExpandResult { - let expander = match *self { + pub fn expander(&self) -> fn(Span, &tt::Subtree) -> ExpandResult { + match *self { $( BuiltinDeriveExpander::$trait => $expand, )* - }; - - let span = db.lookup_intern_macro_call(id).call_site; - let span = span_with_def_site_ctxt(db, span, id); - expander(span, tt, token_map) + } } fn find_by_name(name: &name::Name) -> Option { @@ -52,6 +44,19 @@ macro_rules! register_builtin { }; } +impl BuiltinDeriveExpander { + pub fn expand( + &self, + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> ExpandResult { + let span = db.lookup_intern_macro_call(id).call_site; + let span = span_with_def_site_ctxt(db, span, id); + self.expander()(span, tt) + } +} + register_builtin! { Copy => copy_expand, Clone => clone_expand, @@ -122,7 +127,7 @@ impl VariantShape { } } - fn from(tm: SpanMapRef<'_>, value: Option) -> Result { + fn from(tm: &ExpansionSpanMap, value: Option) -> Result { let r = match value { None => VariantShape::Unit, Some(FieldList::RecordFieldList(it)) => VariantShape::Struct( @@ -198,11 +203,13 @@ struct BasicAdtInfo { associated_types: Vec, } -fn parse_adt( - tm: SpanMapRef<'_>, - adt: &ast::Adt, - call_site: Span, -) -> Result { +fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result { + let (parsed, tm) = &mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems); + let macro_items = ast::MacroItems::cast(parsed.syntax_node()) + .ok_or_else(|| ExpandError::other("invalid item definition"))?; + let item = macro_items.items().next().ok_or_else(|| ExpandError::other("no item found"))?; + let adt = &ast::Adt::cast(item.syntax().clone()) + .ok_or_else(|| ExpandError::other("expected struct, enum or union"))?; let (name, generic_param_list, where_clause, shape) = match adt { ast::Adt::Struct(it) => ( it.name(), @@ -318,14 +325,14 @@ fn parse_adt( } fn name_to_token( - token_map: SpanMapRef<'_>, + token_map: &ExpansionSpanMap, name: Option, ) -> Result { let name = name.ok_or_else(|| { debug!("parsed item has no name"); ExpandError::other("missing name") })?; - let span = token_map.span_for_range(name.syntax().text_range()); + let span = token_map.span_at(name.syntax().text_range().start()); let name_token = tt::Ident { span, text: name.text().into() }; Ok(name_token) } @@ -362,14 +369,12 @@ fn name_to_token( /// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and /// therefore does not get bound by the derived trait. fn expand_simple_derive( - // FIXME: use invoc_span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, + tt: &tt::Subtree, trait_path: tt::Subtree, make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, ) -> ExpandResult { - let info = match parse_adt(tm, tt, invoc_span) { + let info = match parse_adt(tt, invoc_span) { Ok(info) => info, Err(e) => { return ExpandResult::new( @@ -412,14 +417,14 @@ fn expand_simple_derive( ExpandResult::ok(expanded) } -fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn copy_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) + expand_simple_derive(span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) } -fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn clone_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::clone::Clone }, |adt| { if matches!(adt.shape, AdtShape::Union) { let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span }; return quote! {span => @@ -468,9 +473,9 @@ fn and_and(span: Span) -> tt::Subtree { quote! {span => #and& } } -fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn default_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::default::Default }, |adt| { let body = match &adt.shape { AdtShape::Struct(fields) => { let name = &adt.name; @@ -507,9 +512,9 @@ fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult }) } -fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn debug_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { let for_fields = fields.iter().map(|it| { @@ -579,9 +584,9 @@ fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult) -> ExpandResult { +fn hash_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::hash::Hash }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -626,14 +631,14 @@ fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult) -> ExpandResult { +fn eq_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) + expand_simple_derive(span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) } -fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn partial_eq_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -703,9 +708,9 @@ fn self_and_other_patterns( (self_patterns, other_patterns) } -fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { +fn ord_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::cmp::Ord }, |adt| { fn compare( krate: &tt::Ident, left: tt::Subtree, @@ -761,9 +766,9 @@ fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult) -> ExpandResult { +fn partial_ord_expand(span: Span, tt: &tt::Subtree) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| { + expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| { fn compare( krate: &tt::Ident, left: tt::Subtree, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 90cd3af75783d..0fd0c25dcce25 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -31,36 +31,18 @@ macro_rules! register_builtin { } impl BuiltinFnLikeExpander { - pub fn expand( - &self, - db: &dyn ExpandDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { + pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree, Span) -> ExpandResult { + match *self { $( BuiltinFnLikeExpander::$kind => $expand, )* - }; - - let span = db.lookup_intern_macro_call(id).call_site; - let span = span_with_def_site_ctxt(db, span, id); - expander(db, id, tt, span) + } } } impl EagerExpander { - pub fn expand( - &self, - db: &dyn ExpandDatabase, - id: MacroCallId, - tt: &tt::Subtree, - ) -> ExpandResult { - let expander = match *self { + pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree, Span) -> ExpandResult { + match *self { $( EagerExpander::$e_kind => $e_expand, )* - }; - - let span = db.lookup_intern_macro_call(id).call_site; - let span = span_with_def_site_ctxt(db, span, id); - expander(db, id, tt, span) + } } } @@ -74,7 +56,31 @@ macro_rules! register_builtin { }; } +impl BuiltinFnLikeExpander { + pub fn expand( + &self, + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> ExpandResult { + let span = db.lookup_intern_macro_call(id).call_site; + let span = span_with_def_site_ctxt(db, span, id); + self.expander()(db, id, tt, span) + } +} + impl EagerExpander { + pub fn expand( + &self, + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> ExpandResult { + let span = db.lookup_intern_macro_call(id).call_site; + let span = span_with_def_site_ctxt(db, span, id); + self.expander()(db, id, tt, span) + } + pub fn is_include(&self) -> bool { matches!(self, EagerExpander::Include) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index c6611438e64d8..8b9e5a59df8f0 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -11,14 +11,14 @@ use triomphe::Arc; use crate::{db::ExpandDatabase, proc_macro::ProcMacros}; #[derive(Debug, Default)] -pub struct Change { +pub struct ChangeWithProcMacros { pub source_change: FileChange, pub proc_macros: Option, pub toolchains: Option>>, pub target_data_layouts: Option>, } -impl Change { +impl ChangeWithProcMacros { pub fn new() -> Self { Self::default() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index f1f0d8990f1cd..6f69ee15acacb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -215,11 +215,6 @@ pub fn expand_speculative( MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, loc.call_site) } - MacroDefKind::BuiltInDerive(expander, ..) => { - // this cast is a bit sus, can we avoid losing the typedness here? - let adt = ast::Adt::cast(speculative_args.clone()).unwrap(); - expander.expand(db, actual_macro_call, &adt, span_map) - } MacroDefKind::Declarative(it) => db.decl_macro_expander(loc.krate, it).expand_unhygienic( db, tt, @@ -227,6 +222,9 @@ pub fn expand_speculative( loc.call_site, ), MacroDefKind::BuiltIn(it, _) => it.expand(db, actual_macro_call, &tt).map_err(Into::into), + MacroDefKind::BuiltInDerive(it, ..) => { + it.expand(db, actual_macro_call, &tt).map_err(Into::into) + } MacroDefKind::BuiltInEager(it, _) => { it.expand(db, actual_macro_call, &tt).map_err(Into::into) } @@ -303,7 +301,7 @@ fn parse_macro_expansion_error( macro_call_id: MacroCallId, ) -> ExpandResult> { db.parse_macro_expansion(MacroFileId { macro_call_id }) - .map(|it| it.0.errors().to_vec().into_boxed_slice()) + .map(|it| it.0.errors().into_boxed_slice()) } pub(crate) fn parse_with_map( @@ -321,6 +319,7 @@ pub(crate) fn parse_with_map( } } +// FIXME: for derive attributes, this will return separate copies of the same structures! fn macro_arg( db: &dyn ExpandDatabase, id: MacroCallId, @@ -445,7 +444,7 @@ fn macro_arg( if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) { match parse.errors() { - [] => ValueResult::ok((Arc::new(tt), undo_info)), + errors if errors.is_empty() => ValueResult::ok((Arc::new(tt), undo_info)), errors => ValueResult::new( (Arc::new(tt), undo_info), // Box::<[_]>::from(res.errors()), not stable yet @@ -526,16 +525,6 @@ fn macro_expand( let ExpandResult { value: tt, mut err } = match loc.def.kind { MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc), - MacroDefKind::BuiltInDerive(expander, ..) => { - let (root, map) = parse_with_map(db, loc.kind.file_id()); - let root = root.syntax_node(); - let MacroCallKind::Derive { ast_id, .. } = loc.kind else { unreachable!() }; - let node = ast_id.to_ptr(db).to_node(&root); - - // FIXME: Use censoring - let _censor = censor_for_macro_input(&loc, node.syntax()); - expander.expand(db, macro_call_id, &node, map.as_ref()) - } _ => { let ValueResult { value: (macro_arg, undo_info), err } = db.macro_arg(macro_call_id); let format_parse_err = |err: Arc>| { @@ -569,6 +558,9 @@ fn macro_expand( err: err.map(format_parse_err), }; } + MacroDefKind::BuiltInDerive(it, _) => { + it.expand(db, macro_call_id, arg).map_err(Into::into) + } MacroDefKind::BuiltInEager(it, _) => { it.expand(db, macro_call_id, arg).map_err(Into::into) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index da85c2ec7ac8f..5337a5bb028cd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -27,7 +27,6 @@ use crate::{ ast::{self, AstNode}, db::ExpandDatabase, mod_path::ModPath, - span_map::SpanMapRef, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, Intern, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, }; @@ -155,10 +154,9 @@ fn eager_macro_recur( } }; - let def = match call - .path() - .and_then(|path| ModPath::from_src(db, path, SpanMapRef::ExpansionSpanMap(span_map))) - { + let def = match call.path().and_then(|path| { + ModPath::from_src(db, path, &mut |range| span_map.span_at(range.start()).ctx) + }) { Some(path) => match macro_resolver(path.clone()) { Some(def) => def, None => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 66ceb1b7d4206..a500c24ce8811 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -252,7 +252,7 @@ impl InFile<&SyntaxNode> { map_node_range_up(db, &db.expansion_span_map(file_id), self.value.text_range())?; // FIXME: Figure out an API that makes proper use of ctx, this only exists to - // keep pre-token map rewrite behaviour. + // keep pre-token map rewrite behavior. if !ctx.is_root() { return None; } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 0cf1fadec9721..fc186d2c26d35 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -9,7 +9,6 @@ use crate::{ db::ExpandDatabase, hygiene::{marks_rev, SyntaxContextExt, Transparency}, name::{known, AsName, Name}, - span_map::SpanMapRef, tt, }; use base_db::CrateId; @@ -49,9 +48,9 @@ impl ModPath { pub fn from_src( db: &dyn ExpandDatabase, path: ast::Path, - span_map: SpanMapRef<'_>, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, ) -> Option { - convert_path(db, path, span_map) + convert_path(db, path, span_for_range) } pub fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option { @@ -144,6 +143,12 @@ impl ModPath { } } +impl Extend for ModPath { + fn extend>(&mut self, iter: T) { + self.segments.extend(iter); + } +} + struct Display<'a> { db: &'a dyn ExpandDatabase, path: &'a ModPath, @@ -215,7 +220,7 @@ fn display_fmt_path( fn convert_path( db: &dyn ExpandDatabase, path: ast::Path, - span_map: SpanMapRef<'_>, + span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContextId, ) -> Option { let mut segments = path.segments(); @@ -224,12 +229,9 @@ fn convert_path( ast::PathSegmentKind::Name(name_ref) => { if name_ref.text() == "$crate" { ModPath::from_kind( - resolve_crate_root( - db, - span_map.span_for_range(name_ref.syntax().text_range()).ctx, - ) - .map(PathKind::DollarCrate) - .unwrap_or(PathKind::Crate), + resolve_crate_root(db, span_for_range(name_ref.syntax().text_range())) + .map(PathKind::DollarCrate) + .unwrap_or(PathKind::Crate), ) } else { let mut res = ModPath::from_kind( @@ -283,7 +285,7 @@ fn convert_path( // We follow what it did anyway :) if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain { if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - let syn_ctx = span_map.span_for_range(segment.syntax().text_range()).ctx; + let syn_ctx = span_for_range(segment.syntax().text_range()); if let Some(macro_call_id) = db.lookup_intern_syntax_context(syn_ctx).outer_expn { if db.lookup_intern_macro_call(macro_call_id).def.local_inner { mod_path.kind = match resolve_crate_root(db, syn_ctx) { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index cf17d90ed1217..0b69799e6bffa 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -111,15 +111,11 @@ impl Name { self == &Name::missing() } - /// Generates a new name which is only equal to itself, by incrementing a counter. Due - /// its implementation, it should not be used in things that salsa considers, like - /// type names or field names, and it should be only used in names of local variables - /// and labels and similar things. - pub fn generate_new_name() -> Name { - use std::sync::atomic::{AtomicUsize, Ordering}; - static CNT: AtomicUsize = AtomicUsize::new(0); - let c = CNT.fetch_add(1, Ordering::Relaxed); - Name::new_text(format_smolstr!("{c}")) + /// Generates a new name that attempts to be unique. Should only be used when body lowering and + /// creating desugared locals and labels. The caller is responsible for picking an index + /// that is stable across re-executions + pub fn generate_new_name(idx: usize) -> Name { + Name::new_text(format_smolstr!("{idx}")) } /// Returns the tuple index this name represents if it is a tuple field. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs index 4a60a9485608a..ef86be67096a2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs @@ -31,11 +31,13 @@ impl mbe::SpanMapper for SpanMap { self.span_for_range(range) } } + impl mbe::SpanMapper for SpanMapRef<'_> { fn span_for(&self, range: TextRange) -> Span { self.span_for_range(range) } } + impl SpanMap { pub fn span_for_range(&self, range: TextRange) -> Span { match self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 1f8f8744f9ebe..41e2f7ad73c33 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -45,7 +45,6 @@ intern.workspace = true hir-def.workspace = true hir-expand.workspace = true base-db.workspace = true -profile.workspace = true syntax.workspace = true limit.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index f9e8cff55393f..28c497989fe98 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -31,12 +31,8 @@ use hir_expand::name::Name; #[salsa::query_group(HirDatabaseStorage)] pub trait HirDatabase: DefDatabase + Upcast { - #[salsa::invoke(infer_wait)] - #[salsa::transparent] - fn infer(&self, def: DefWithBodyId) -> Arc; - #[salsa::invoke(crate::infer::infer_query)] - fn infer_query(&self, def: DefWithBodyId) -> Arc; + fn infer(&self, def: DefWithBodyId) -> Arc; // region:mir @@ -258,17 +254,8 @@ pub trait HirDatabase: DefDatabase + Upcast { env: Arc, ) -> Ty; - #[salsa::invoke(trait_solve_wait)] - #[salsa::transparent] - fn trait_solve( - &self, - krate: CrateId, - block: Option, - goal: crate::Canonical>, - ) -> Option; - #[salsa::invoke(crate::traits::trait_solve_query)] - fn trait_solve_query( + fn trait_solve( &self, krate: CrateId, block: Option, @@ -284,38 +271,6 @@ pub trait HirDatabase: DefDatabase + Upcast { ) -> chalk_ir::ProgramClauses; } -fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let detail = match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), - DefWithBodyId::StaticId(it) => { - db.static_data(it).name.clone().display(db.upcast()).to_string() - } - DefWithBodyId::ConstId(it) => db - .const_data(it) - .name - .clone() - .unwrap_or_else(Name::missing) - .display(db.upcast()) - .to_string(), - DefWithBodyId::VariantId(it) => { - db.enum_variant_data(it).name.display(db.upcast()).to_string() - } - DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), - }; - let _p = tracing::span!(tracing::Level::INFO, "infer:wait", ?detail).entered(); - db.infer_query(def) -} - -fn trait_solve_wait( - db: &dyn HirDatabase, - krate: CrateId, - block: Option, - goal: crate::Canonical>, -) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "trait_solve::wait").entered(); - db.trait_solve_query(krate, block, goal) -} - #[test] fn hir_database_is_object_safe() { fn _assert_object_safe(_: &dyn HirDatabase) {} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 1a134e6d780e4..67cfbc294df7f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -60,12 +60,17 @@ pub enum BodyValidationDiagnostic { } impl BodyValidationDiagnostic { - pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec { + pub fn collect( + db: &dyn HirDatabase, + owner: DefWithBodyId, + validate_lints: bool, + ) -> Vec { let _p = tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); let body = db.body(owner); - let mut validator = ExprValidator { owner, body, infer, diagnostics: Vec::new() }; + let mut validator = + ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints }; validator.validate_body(db); validator.diagnostics } @@ -76,6 +81,7 @@ struct ExprValidator { body: Arc, infer: Arc, diagnostics: Vec, + validate_lints: bool, } impl ExprValidator { @@ -139,6 +145,9 @@ impl ExprValidator { expr: &Expr, filter_map_next_checker: &mut Option, ) { + if !self.validate_lints { + return; + } // Check that the number of arguments matches the number of parameters. if self.infer.expr_type_mismatches().next().is_some() { @@ -173,7 +182,7 @@ impl ExprValidator { db: &dyn HirDatabase, ) { let scrut_ty = &self.infer[scrutinee_expr]; - if scrut_ty.is_unknown() { + if scrut_ty.contains_unknown() { return; } @@ -230,6 +239,7 @@ impl ExprValidator { m_arms.as_slice(), scrut_ty.clone(), ValidityConstraint::ValidOnly, + None, ) { Ok(report) => report, Err(()) => return, @@ -257,6 +267,9 @@ impl ExprValidator { }; let Some(initializer) = initializer else { continue }; let ty = &self.infer[initializer]; + if ty.contains_unknown() { + continue; + } let mut have_errors = false; let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors); @@ -274,6 +287,7 @@ impl ExprValidator { &[match_arm], ty.clone(), ValidityConstraint::ValidOnly, + None, ) { Ok(v) => v, Err(e) => { @@ -308,6 +322,9 @@ impl ExprValidator { } fn check_for_trailing_return(&mut self, body_expr: ExprId, body: &Body) { + if !self.validate_lints { + return; + } match &body.exprs[body_expr] { Expr::Block { statements, tail, .. } => { let last_stmt = tail.or_else(|| match statements.last()? { @@ -340,6 +357,9 @@ impl ExprValidator { } fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) { + if !self.validate_lints { + return; + } if let Expr::If { condition: _, then_branch, else_branch } = expr { if else_branch.is_none() { return; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index e98a946a8708c..ca05842879657 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; use rustc_pattern_analysis::{ constructor::{Constructor, ConstructorSet, VariantVisibility}, index::IdxContainer, - Captures, TypeCx, + Captures, PrivateUninhabitedField, TypeCx, }; use smallvec::{smallvec, SmallVec}; use stdx::never; @@ -88,39 +88,21 @@ impl<'p> MatchCheckCtx<'p> { } } - // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide - // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. - // This lists the fields we keep along with their types. - fn list_variant_nonhidden_fields<'a>( + // This lists the fields of a variant along with their types. + fn list_variant_fields<'a>( &'a self, ty: &'a Ty, variant: VariantId, ) -> impl Iterator + Captures<'a> + Captures<'p> { - let cx = self; - let (adt, substs) = ty.as_adt().unwrap(); - - let adt_is_local = variant.module(cx.db.upcast()).krate() == cx.module.krate(); - - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - cx.db.attrs(variant.into()).by_key("non_exhaustive").exists() && !adt_is_local; + let (_, substs) = ty.as_adt().unwrap(); - let visibility = cx.db.field_visibilities(variant); - let field_ty = cx.db.field_types(variant); - let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32; + let field_tys = self.db.field_types(variant); + let fields_len = variant.variant_data(self.db.upcast()).fields().len() as u32; - (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| { - let ty = field_ty[fid].clone().substitute(Interner, substs); - let ty = normalize(cx.db, cx.db.trait_environment_for_body(cx.body), ty); - let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) - || visibility[fid].is_visible_from(cx.db.upcast(), cx.module); - let is_uninhabited = cx.is_uninhabited(&ty); - - if is_uninhabited && (!is_visible || is_non_exhaustive) { - None - } else { - Some((fid, ty)) - } + (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| { + let ty = field_tys[fid].clone().substitute(Interner, substs); + let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty); + (fid, ty) }) } @@ -199,23 +181,16 @@ impl<'p> MatchCheckCtx<'p> { } }; let variant = Self::variant_id_for_adt(&ctor, adt.0).unwrap(); - let fields_len = variant.variant_data(self.db.upcast()).fields().len(); - // For each field in the variant, we store the relevant index into `self.fields` if any. - let mut field_id_to_id: Vec> = vec![None; fields_len]; - let tys = self - .list_variant_nonhidden_fields(&pat.ty, variant) - .enumerate() - .map(|(i, (fid, ty))| { - let field_idx: u32 = fid.into_raw().into(); - field_id_to_id[field_idx as usize] = Some(i); - ty - }); - let mut wilds: Vec<_> = tys.map(DeconstructedPat::wildcard).collect(); + // Fill a vec with wildcards, then place the fields we have at the right + // index. + let mut wilds: Vec<_> = self + .list_variant_fields(&pat.ty, variant) + .map(|(_, ty)| ty) + .map(DeconstructedPat::wildcard) + .collect(); for pat in subpatterns { - let field_idx: u32 = pat.field.into_raw().into(); - if let Some(i) = field_id_to_id[field_idx as usize] { - wilds[i] = self.lower_pat(&pat.pattern); - } + let field_id: u32 = pat.field.into_raw().into(); + wilds[field_id as usize] = self.lower_pat(&pat.pattern); } fields = wilds; } @@ -263,7 +238,7 @@ impl<'p> MatchCheckCtx<'p> { TyKind::Adt(adt, substs) => { let variant = Self::variant_id_for_adt(pat.ctor(), adt.0).unwrap(); let subpatterns = self - .list_variant_nonhidden_fields(pat.ty(), variant) + .list_variant_fields(pat.ty(), variant) .zip(subpatterns) .map(|((field, _ty), pattern)| FieldPat { field, pattern }) .collect(); @@ -286,7 +261,7 @@ impl<'p> MatchCheckCtx<'p> { Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), &Str(void) => match void {}, - Wildcard | NonExhaustive | Hidden => PatKind::Wild, + Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => { never!("can't convert to pattern: {:?}", pat.ctor()); PatKind::Wild @@ -326,7 +301,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { 1 } else { let variant = Self::variant_id_for_adt(ctor, adt).unwrap(); - self.list_variant_nonhidden_fields(ty, variant).count() + variant.variant_data(self.db.upcast()).fields().len() } } _ => { @@ -337,7 +312,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { Ref => 1, Slice(..) => unimplemented!(), Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | Wildcard => 0, + | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, Or => { never!("The `Or` constructor doesn't have a fixed arity"); 0 @@ -349,13 +324,13 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { &'a self, ctor: &'a rustc_pattern_analysis::constructor::Constructor, ty: &'a Self::Ty, - ) -> impl ExactSizeIterator + Captures<'a> { - let single = |ty| smallvec![ty]; + ) -> impl ExactSizeIterator + Captures<'a> { + let single = |ty| smallvec![(ty, PrivateUninhabitedField(false))]; let tys: SmallVec<[_; 2]> = match ctor { Struct | Variant(_) | UnionField => match ty.kind(Interner) { TyKind::Tuple(_, substs) => { let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner)); - tys.cloned().collect() + tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect() } TyKind::Ref(.., rty) => single(rty.clone()), &TyKind::Adt(AdtId(adt), ref substs) => { @@ -366,7 +341,27 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { single(subst_ty) } else { let variant = Self::variant_id_for_adt(ctor, adt).unwrap(); - self.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty).collect() + let (adt, _) = ty.as_adt().unwrap(); + + let adt_is_local = + variant.module(self.db.upcast()).krate() == self.module.krate(); + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = + self.db.attrs(variant.into()).by_key("non_exhaustive").exists() + && !adt_is_local; + let visibilities = self.db.field_visibilities(variant); + + self.list_variant_fields(ty, variant) + .map(move |(fid, ty)| { + let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) + || visibilities[fid] + .is_visible_from(self.db.upcast(), self.module); + let is_uninhabited = self.is_uninhabited(&ty); + let private_uninhabited = + is_uninhabited && (!is_visible || is_non_exhaustive); + (ty, PrivateUninhabitedField(private_uninhabited)) + }) + .collect() } } ty_kind => { @@ -383,7 +378,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | Wildcard => smallvec![], + | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => smallvec![], Or => { never!("called `Fields::wildcards` on an `Or` ctor"); smallvec![] @@ -478,6 +473,11 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { fn bug(&self, fmt: fmt::Arguments<'_>) { debug!("{}", fmt) } + + fn complexity_exceeded(&self) -> Result<(), Self::Error> { + // FIXME(Nadrieril): make use of the complexity counter. + Err(()) + } } impl<'p> fmt::Debug for MatchCheckCtx<'p> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index fe51ec3f82108..20964f5acbd01 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -63,6 +63,7 @@ pub struct HirFormatter<'a> { buf: String, curr_size: usize, pub(crate) max_size: Option, + pub entity_limit: Option, omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, @@ -86,6 +87,7 @@ pub trait HirDisplay { &'a self, db: &'a dyn HirDatabase, max_size: Option, + limited_size: Option, omit_verbose_types: bool, display_target: DisplayTarget, closure_style: ClosureStyle, @@ -101,6 +103,7 @@ pub trait HirDisplay { db, t: self, max_size, + limited_size, omit_verbose_types, display_target, closure_style, @@ -117,6 +120,7 @@ pub trait HirDisplay { db, t: self, max_size: None, + limited_size: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, @@ -137,6 +141,28 @@ pub trait HirDisplay { db, t: self, max_size, + limited_size: None, + omit_verbose_types: true, + closure_style: ClosureStyle::ImplFn, + display_target: DisplayTarget::Diagnostics, + } + } + + /// Returns a `Display`able type that is human-readable and tries to limit the number of items inside. + /// Use this for showing definitions which may contain too many items, like `trait`, `struct`, `enum` + fn display_limited<'a>( + &'a self, + db: &'a dyn HirDatabase, + limited_size: Option, + ) -> HirDisplayWrapper<'a, Self> + where + Self: Sized, + { + HirDisplayWrapper { + db, + t: self, + max_size: None, + limited_size, omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, @@ -158,6 +184,7 @@ pub trait HirDisplay { buf: String::with_capacity(20), curr_size: 0, max_size: None, + entity_limit: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::SourceCode { module_id, allow_opaque }, @@ -178,6 +205,7 @@ pub trait HirDisplay { db, t: self, max_size: None, + limited_size: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Test, @@ -295,6 +323,7 @@ pub struct HirDisplayWrapper<'a, T> { db: &'a dyn HirDatabase, t: &'a T, max_size: Option, + limited_size: Option, omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, @@ -323,6 +352,7 @@ impl HirDisplayWrapper<'_, T> { buf: String::with_capacity(20), curr_size: 0, max_size: self.max_size, + entity_limit: self.limited_size, omit_verbose_types: self.omit_verbose_types, display_target: self.display_target, closure_style: self.closure_style, @@ -1751,10 +1781,7 @@ impl HirDisplay for TypeRef { f.write_joined(bounds, " + ")?; } TypeRef::Macro(macro_call) => { - let ctx = hir_def::lower::LowerCtx::with_span_map( - f.db.upcast(), - f.db.span_map(macro_call.file_id), - ); + let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id); let macro_call = macro_call.to_node(f.db.upcast()); match macro_call.path() { Some(path) => match Path::from_src(&ctx, path) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index a1be60180838c..dea292711d86c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -1,7 +1,6 @@ //! Compute the binary representation of a type -use std::borrow::Cow; -use std::fmt; +use std::{borrow::Cow, fmt}; use base_db::salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 75ac3b0d66b8d..dac20f2259717 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -995,12 +995,12 @@ impl<'a> TyLoweringContext<'a> { pub(crate) fn lower_type_bound( &'a self, - bound: &'a TypeBound, + bound: &'a Interned, self_ty: Ty, ignore_bindings: bool, ) -> impl Iterator + 'a { let mut bindings = None; - let trait_ref = match bound { + let trait_ref = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) => { bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); bindings @@ -1055,10 +1055,10 @@ impl<'a> TyLoweringContext<'a> { fn assoc_type_bindings_from_type_bound( &'a self, - bound: &'a TypeBound, + bound: &'a Interned, trait_ref: TraitRef, ) -> impl Iterator + 'a { - let last_segment = match bound { + let last_segment = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { path.segments().last() } @@ -1121,7 +1121,63 @@ impl<'a> TyLoweringContext<'a> { ); } } else { - let ty = self.lower_ty(type_ref); + let ty = 'ty: { + if matches!( + self.impl_trait_mode, + ImplTraitLoweringState::Param(_) + | ImplTraitLoweringState::Variable(_) + ) { + // Find the generic index for the target of our `bound` + let target_param_idx = self + .resolver + .where_predicates_in_scope() + .find_map(|p| match p { + WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeOrConstParam(idx), + bound: b, + } if b == bound => Some(idx), + _ => None, + }); + if let Some(target_param_idx) = target_param_idx { + let mut counter = 0; + for (idx, data) in self.generics().params.type_or_consts.iter() + { + // Count the number of `impl Trait` things that appear before + // the target of our `bound`. + // Our counter within `impl_trait_mode` should be that number + // to properly lower each types within `type_ref` + if data.type_param().is_some_and(|p| { + p.provenance == TypeParamProvenance::ArgumentImplTrait + }) { + counter += 1; + } + if idx == *target_param_idx { + break; + } + } + let mut ext = TyLoweringContext::new_maybe_unowned( + self.db, + self.resolver, + self.owner, + ) + .with_type_param_mode(self.type_param_mode); + match &self.impl_trait_mode { + ImplTraitLoweringState::Param(_) => { + ext.impl_trait_mode = + ImplTraitLoweringState::Param(Cell::new(counter)); + } + ImplTraitLoweringState::Variable(_) => { + ext.impl_trait_mode = ImplTraitLoweringState::Variable( + Cell::new(counter), + ); + } + _ => unreachable!(), + } + break 'ty ext.lower_ty(type_ref); + } + } + self.lower_ty(type_ref) + }; let alias_eq = AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); @@ -1403,8 +1459,14 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); + let ctx = if let GenericDefId::FunctionId(_) = def { + TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Variable) + .with_type_param_mode(ParamLoweringMode::Variable) + } else { + TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable) + }; let generics = generics(db.upcast(), def); // we have to filter out all other predicates *first*, before attempting to lower them @@ -1490,8 +1552,14 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc { let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Placeholder); + let ctx = if let GenericDefId::FunctionId(_) = def { + TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Param) + .with_type_param_mode(ParamLoweringMode::Placeholder) + } else { + TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder) + }; let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); for pred in resolver.where_predicates_in_scope() { @@ -1549,8 +1617,14 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); + let ctx = if let GenericDefId::FunctionId(_) = def { + TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Variable) + .with_type_param_mode(ParamLoweringMode::Variable) + } else { + TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable) + }; let generics = generics(db.upcast(), def); let mut predicates = resolver diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index ed316f972689f..d0f739e6ac66f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1364,10 +1364,16 @@ impl<'ctx> MirLowerCtx<'ctx> { match loc { LiteralOrConst::Literal(l) => self.lower_literal_to_operand(ty, l), LiteralOrConst::Const(c) => { - let unresolved_name = || MirLowerError::unresolved_path(self.db, c); + let c = match &self.body.pats[*c] { + Pat::Path(p) => p, + _ => not_supported!( + "only `char` and numeric types are allowed in range patterns" + ), + }; + let unresolved_name = || MirLowerError::unresolved_path(self.db, c.as_ref()); let resolver = self.owner.resolver(self.db.upcast()); let pr = resolver - .resolve_path_in_value_ns(self.db.upcast(), c) + .resolve_path_in_value_ns(self.db.upcast(), c.as_ref()) .ok_or_else(unresolved_name)?; match pr { ResolveValueResult::ValueNs(v, _) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 39c5547b8d0e9..b80cfe18e4cf9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1231,6 +1231,53 @@ fn test(x: impl Trait, y: &impl Trait) { ); } +#[test] +fn argument_impl_trait_with_projection() { + check_infer( + r#" +trait X { + type Item; +} + +impl X for [T; 2] { + type Item = T; +} + +trait Y {} + +impl Y for T {} + +enum R { + A(T), + B(U), +} + +fn foo(x: impl X>) -> T { loop {} } + +fn bar() { + let a = foo([R::A(()), R::B(7)]); +} +"#, + expect![[r#" + 153..154 'x': impl X> + ?Sized + 190..201 '{ loop {} }': T + 192..199 'loop {}': ! + 197..199 '{}': () + 212..253 '{ ...)]); }': () + 222..223 'a': i32 + 226..229 'foo': fn foo([R<(), i32>; 2]) -> i32 + 226..250 'foo([R...B(7)])': i32 + 230..249 '[R::A(...:B(7)]': [R<(), i32>; 2] + 231..235 'R::A': extern "rust-call" A<(), i32>(()) -> R<(), i32> + 231..239 'R::A(())': R<(), i32> + 236..238 '()': () + 241..245 'R::B': extern "rust-call" B<(), i32>(i32) -> R<(), i32> + 241..248 'R::B(7)': R<(), i32> + 246..247 '7': i32 + "#]], + ); +} + #[test] fn simple_return_pos_impl_trait() { cov_mark::check!(lower_rpit); diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 7fea8372876ee..190722075a202 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -27,7 +27,6 @@ cfg.workspace = true hir-def.workspace = true hir-expand.workspace = true hir-ty.workspace = true -profile.workspace = true stdx.workspace = true syntax.workspace = true tt.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index 557c8d29a1731..1d74f9a4bb226 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -4,20 +4,20 @@ //! //! But we need this for at least LRU caching at the query level. pub use hir_def::db::{ - AttrsQuery, BlockDefMapQuery, BlockItemTreeQueryQuery, BodyQuery, BodyWithSourceMapQuery, - ConstDataQuery, ConstVisibilityQuery, CrateDefMapQueryQuery, CrateLangItemsQuery, - CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, - EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, - FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, - FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery, - ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase, - InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery, - InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query, - InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery, - InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, - InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, - StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery, - TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery, + AttrsQuery, BlockDefMapQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, + ConstVisibilityQuery, CrateLangItemsQuery, CrateSupportsNoStdQuery, DefDatabase, + DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, + ExternCrateDeclDataQuery, FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, + FileItemTreeQuery, FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, + ImplDataWithDiagnosticsQuery, ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, + InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, + InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery, + InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, + InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery, + InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, + MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataWithDiagnosticsQuery, + TraitAliasDataQuery, TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, + UnionDataWithDiagnosticsQuery, }; pub use hir_expand::db::{ AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage, diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 30f402a79f3db..cdc0db8653c11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -17,10 +17,10 @@ use hir_ty::{ }; use crate::{ - Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field, - Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, SelfParam, - Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, - TypeParam, Union, Variant, + Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, + Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, + SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, + TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -595,6 +595,35 @@ impl HirDisplay for Trait { let def_id = GenericDefId::TraitId(self.id); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; + + if let Some(limit) = f.entity_limit { + let assoc_items = self.items(f.db); + let count = assoc_items.len().min(limit); + if count == 0 { + if assoc_items.is_empty() { + f.write_str(" {}")?; + } else { + f.write_str(" { /* … */ }")?; + } + } else { + f.write_str(" {\n")?; + for item in &assoc_items[..count] { + f.write_str(" ")?; + match item { + AssocItem::Function(func) => func.hir_fmt(f), + AssocItem::Const(cst) => cst.hir_fmt(f), + AssocItem::TypeAlias(type_alias) => type_alias.hir_fmt(f), + }?; + f.write_str(";\n")?; + } + + if assoc_items.len() > count { + f.write_str(" /* … */\n")?; + } + f.write_str("}")?; + } + } + Ok(()) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 5c607030167f4..5eed7ecd5b21d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -126,7 +126,7 @@ pub use { }, hir_expand::{ attrs::{Attr, AttrId}, - change::Change, + change::ChangeWithProcMacros, hygiene::{marks_rev, SyntaxContextExt}, name::{known, Name}, proc_macro::ProcMacros, @@ -365,7 +365,7 @@ impl ModuleDef { Some(name) } - pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec { + pub fn diagnostics(self, db: &dyn HirDatabase, style_lints: bool) -> Vec { let id = match self { ModuleDef::Adt(it) => match it { Adt::Struct(it) => it.id.into(), @@ -387,7 +387,7 @@ impl ModuleDef { match self.as_def_with_body() { Some(def) => { - def.diagnostics(db, &mut acc); + def.diagnostics(db, &mut acc, style_lints); } None => { for diag in hir_ty::diagnostics::incorrect_case(db, id) { @@ -541,7 +541,12 @@ impl Module { } /// Fills `acc` with the module's diagnostics. - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + pub fn diagnostics( + self, + db: &dyn HirDatabase, + acc: &mut Vec, + style_lints: bool, + ) { let name = self.name(db); let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", ?name); let def_map = self.id.def_map(db.upcast()); @@ -558,9 +563,9 @@ impl Module { ModuleDef::Module(m) => { // Only add diagnostics from inline modules if def_map[m.id.local_id].origin.is_inline() { - m.diagnostics(db, acc) + m.diagnostics(db, acc, style_lints) } - acc.extend(def.diagnostics(db)) + acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Trait(t) => { for diag in db.trait_data_with_diagnostics(t.id).1.iter() { @@ -568,10 +573,10 @@ impl Module { } for item in t.items(db) { - item.diagnostics(db, acc); + item.diagnostics(db, acc, style_lints); } - acc.extend(def.diagnostics(db)) + acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Adt(adt) => { match adt { @@ -587,17 +592,17 @@ impl Module { } Adt::Enum(e) => { for v in e.variants(db) { - acc.extend(ModuleDef::Variant(v).diagnostics(db)); + acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { emit_def_diagnostic(db, acc, diag); } } } } - acc.extend(def.diagnostics(db)) + acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), - _ => acc.extend(def.diagnostics(db)), + _ => acc.extend(def.diagnostics(db, style_lints)), } } self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m)); @@ -738,7 +743,7 @@ impl Module { } for &item in &db.impl_data(impl_def.id).items { - AssocItem::from(item).diagnostics(db, acc); + AssocItem::from(item).diagnostics(db, acc, style_lints); } } } @@ -1616,14 +1621,19 @@ impl DefWithBody { } } - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + pub fn diagnostics( + self, + db: &dyn HirDatabase, + acc: &mut Vec, + style_lints: bool, + ) { db.unwind_if_cancelled(); let krate = self.module(db).id.krate(); let (body, source_map) = db.body_with_source_map(self.into()); for (_, def_map) in body.blocks(db.upcast()) { - Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc); + Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); } for diag in source_map.diagnostics() { @@ -1784,7 +1794,7 @@ impl DefWithBody { } } - for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) { + for diagnostic in BodyValidationDiagnostic::collect(db, self.into(), style_lints) { acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); } @@ -2098,6 +2108,14 @@ pub struct Param { } impl Param { + pub fn parent_fn(&self) -> Function { + self.func + } + + pub fn index(&self) -> usize { + self.idx + } + pub fn ty(&self) -> &Type { &self.ty } @@ -2162,6 +2180,10 @@ impl SelfParam { .map(|value| InFile { file_id, value }) } + pub fn parent_fn(&self) -> Function { + Function::from(self.func) + } + pub fn ty(&self, db: &dyn HirDatabase) -> Type { let substs = TyBuilder::placeholder_subst(db, self.func); let callable_sig = @@ -2897,13 +2919,18 @@ impl AssocItem { } } - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + pub fn diagnostics( + self, + db: &dyn HirDatabase, + acc: &mut Vec, + style_lints: bool, + ) { match self { AssocItem::Function(func) => { - DefWithBody::from(func).diagnostics(db, acc); + DefWithBody::from(func).diagnostics(db, acc, style_lints); } AssocItem::Const(const_) => { - DefWithBody::from(const_).diagnostics(db, acc); + DefWithBody::from(const_).diagnostics(db, acc, style_lints); } AssocItem::TypeAlias(type_alias) => { for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index cfda8d4f937c4..99907ea15b501 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -38,10 +38,11 @@ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, - Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, - DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, - Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Struct, ToolModule, Trait, - TupleField, Type, TypeAlias, TypeParam, VariantDef, + Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, + ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile, + Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, + Static, Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, + Variant, VariantDef, }; pub enum DescendPreference { @@ -223,21 +224,69 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_variant(record_lit).map(VariantDef::from) } - pub fn to_module_def(&self, file: FileId) -> Option { - self.imp.to_module_def(file).next() + pub fn file_to_module_def(&self, file: FileId) -> Option { + self.imp.file_to_module_defs(file).next() } - pub fn to_module_defs(&self, file: FileId) -> impl Iterator { - self.imp.to_module_def(file) + pub fn file_to_module_defs(&self, file: FileId) -> impl Iterator { + self.imp.file_to_module_defs(file) } - pub fn to_struct_def(&self, s: &ast::Struct) -> Option { - self.imp.to_def(s).map(Struct::from) + pub fn to_adt_def(&self, a: &ast::Adt) -> Option { + self.imp.to_def(a).map(Adt::from) + } + + pub fn to_const_def(&self, c: &ast::Const) -> Option { + self.imp.to_def(c).map(Const::from) + } + + pub fn to_enum_def(&self, e: &ast::Enum) -> Option { + self.imp.to_def(e).map(Enum::from) + } + + pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option { + self.imp.to_def(v).map(Variant::from) + } + + pub fn to_fn_def(&self, f: &ast::Fn) -> Option { + self.imp.to_def(f).map(Function::from) } pub fn to_impl_def(&self, i: &ast::Impl) -> Option { self.imp.to_def(i).map(Impl::from) } + + pub fn to_macro_def(&self, m: &ast::Macro) -> Option { + self.imp.to_def(m).map(Macro::from) + } + + pub fn to_module_def(&self, m: &ast::Module) -> Option { + self.imp.to_def(m).map(Module::from) + } + + pub fn to_static_def(&self, s: &ast::Static) -> Option { + self.imp.to_def(s).map(Static::from) + } + + pub fn to_struct_def(&self, s: &ast::Struct) -> Option { + self.imp.to_def(s).map(Struct::from) + } + + pub fn to_trait_alias_def(&self, t: &ast::TraitAlias) -> Option { + self.imp.to_def(t).map(TraitAlias::from) + } + + pub fn to_trait_def(&self, t: &ast::Trait) -> Option { + self.imp.to_def(t).map(Trait::from) + } + + pub fn to_type_alias_def(&self, t: &ast::TypeAlias) -> Option { + self.imp.to_def(t).map(TypeAlias::from) + } + + pub fn to_union_def(&self, u: &ast::Union) -> Option { + self.imp.to_def(u).map(Union::from) + } } impl<'db> SemanticsImpl<'db> { @@ -1024,7 +1073,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_type(&self, ty: &ast::Type) -> Option { let analyze = self.analyze(ty.syntax())?; - let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); + let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); let ty = hir_ty::TyLoweringContext::new_maybe_unowned( self.db, &analyze.resolver, @@ -1036,8 +1085,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_trait(&self, path: &ast::Path) -> Option { let analyze = self.analyze(path.syntax())?; - let span_map = self.db.span_map(analyze.file_id); - let ctx = LowerCtx::with_span_map(self.db.upcast(), span_map); + let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); let hir_path = Path::from_src(&ctx, path.clone())?; match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { TypeNs::TraitId(id) => Some(Trait { id }), @@ -1241,7 +1289,7 @@ impl<'db> SemanticsImpl<'db> { T::to_def(self, src) } - fn to_module_def(&self, file: FileId) -> impl Iterator { + fn file_to_module_defs(&self, file: FileId) -> impl Iterator { self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from) } @@ -1645,7 +1693,7 @@ impl SemanticsScope<'_> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, path: &ast::Path) -> Option { - let ctx = LowerCtx::with_file_id(self.db.upcast(), self.file_id); + let ctx = LowerCtx::new(self.db.upcast(), self.file_id); let path = Path::from_src(&ctx, path.clone())?; resolve_hir_path(self.db, &self.resolver, &path) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index ef4ed90ce35f5..4733ea5a35b92 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -118,7 +118,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> { impl SourceToDefCtx<'_, '_> { pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> { - let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::to_module_def"); + let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def"); let mut mods = SmallVec::new(); for &crate_id in self.db.relevant_crates(file).iter() { // FIXME: inner items diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index a147102bcd8e8..f87e0a3897af3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -549,7 +549,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option { - let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id); + let ctx = LowerCtx::new(db.upcast(), macro_call.file_id); let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?; self.resolver .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) @@ -662,7 +662,7 @@ impl SourceAnalyzer { } // This must be a normal source file rather than macro file. - let ctx = LowerCtx::with_span_map(db.upcast(), db.span_map(self.file_id)); + let ctx = LowerCtx::new(db.upcast(), self.file_id); let hir_path = Path::from_src(&ctx, path.clone())?; // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index 98961a18de257..b1e7609afef41 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -23,7 +23,6 @@ tracing.workspace = true stdx.workspace = true syntax.workspace = true text-edit.workspace = true -profile.workspace = true ide-db.workspace = true hir.workspace = true @@ -33,10 +32,6 @@ expect-test = "1.4.0" # local deps test-utils.workspace = true test-fixture.workspace = true -sourcegen.workspace = true - -[features] -in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 4edc52b614ab1..c1a3f9302650e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -107,6 +107,10 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option Option { let db = ctx.sema.db; - let module = ctx.sema.to_module_def(ctx.file_id())?; + let module = ctx.sema.file_to_module_def(ctx.file_id())?; let (name, range, ty) = match f { Either::Left(f) => { @@ -619,7 +620,8 @@ fn process_assoc_item( qual_path_ty: ast::Path, base_name: &str, ) -> Option { - match item { + let attrs = item.attrs(); + let assoc = match item { AssocItem::Const(c) => const_assoc_item(c, qual_path_ty), AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name), AssocItem::MacroCall(_) => { @@ -628,7 +630,18 @@ fn process_assoc_item( None } AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty), + }; + if let Some(assoc) = &assoc { + attrs.for_each(|attr| { + assoc.add_attr(attr.clone()); + // fix indentations + if let Some(tok) = attr.syntax().next_sibling_or_token() { + let pos = Position::after(tok); + ted::insert(pos, make::tokens::whitespace(" ")); + } + }) } + assoc } fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option { @@ -1703,4 +1716,65 @@ impl some_module::SomeTrait for B { }"#, ) } + + #[test] + fn test_fn_with_attrs() { + check_assist( + generate_delegate_trait, + r#" +struct A; + +trait T { + #[cfg(test)] + fn f(&self, a: u32); + #[cfg(not(test))] + fn f(&self, a: bool); +} + +impl T for A { + #[cfg(test)] + fn f(&self, a: u32) {} + #[cfg(not(test))] + fn f(&self, a: bool) {} +} + +struct B { + a$0: A, +} +"#, + r#" +struct A; + +trait T { + #[cfg(test)] + fn f(&self, a: u32); + #[cfg(not(test))] + fn f(&self, a: bool); +} + +impl T for A { + #[cfg(test)] + fn f(&self, a: u32) {} + #[cfg(not(test))] + fn f(&self, a: bool) {} +} + +struct B { + a: A, +} + +impl T for B { + #[cfg(test)] + fn f(&self, a: u32) { + ::f(&self.a, a) + } + + #[cfg(not(test))] + fn f(&self, a: bool) { + ::f(&self.a, a) + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 2b9ed86e41b07..50ec4347dc2a1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -418,24 +418,15 @@ fn inline( let expr: &ast::Expr = expr; let mut insert_let_stmt = || { - let param_ty = match param_ty { - None => None, - Some(param_ty) => { - if sema.hir_file_for(param_ty.syntax()).is_macro() { - if let Some(param_ty) = - ast::Type::cast(insert_ws_into(param_ty.syntax().clone())) - { - Some(param_ty) - } else { - Some(param_ty.clone_for_update()) - } - } else { - Some(param_ty.clone_for_update()) - } + let param_ty = param_ty.clone().map(|param_ty| { + if sema.hir_file_for(param_ty.syntax()).is_macro() { + ast::Type::cast(insert_ws_into(param_ty.syntax().clone())).unwrap_or(param_ty) + } else { + param_ty } - }; - let ty: Option = - sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty); + }); + + let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty); let is_self = param .name(sema.db) @@ -1359,8 +1350,8 @@ macro_rules! define_foo { define_foo!(); fn bar() -> u32 { { - let x = 0; - x + let x = 0; + x } } "#, @@ -1673,7 +1664,7 @@ fn main() { let a: A = A{}; let b = { let a = a; - a as A + a as A }; } "#, @@ -1792,7 +1783,7 @@ fn _hash2(self_: &u64, state: &mut u64) { { let inner_self_: &u64 = &self_; let state: &mut u64 = state; - _write_u64(state, *inner_self_) + _write_u64(state, *inner_self_) }; } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index 0c9e971dd23ca..4708be616964f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -288,11 +288,11 @@ macro_rules! foo { } fn main() { cfg_if!{ - if #[cfg(test)]{ - 1; - }else { - 1; - } + if #[cfg(test)]{ + 1; + }else { + 1; + } }; } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs index 917d0b3671e8e..a256f60c421c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs @@ -25,7 +25,7 @@ use crate::{ // ``` pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let source_file = ctx.find_node_at_offset::()?; - let module = ctx.sema.to_module_def(ctx.file_id())?; + let module = ctx.sema.file_to_module_def(ctx.file_id())?; // Enable this assist if the user select all "meaningful" content in the source file let trimmed_selected_range = trimmed_text_range(&source_file, ctx.selection_trimmed()); let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs index b73270cd05fb5..a8a124eebb68d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs @@ -25,7 +25,7 @@ use crate::{ // ``` pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let source_file = ctx.find_node_at_offset::()?; - let module = ctx.sema.to_module_def(ctx.file_id())?; + let module = ctx.sema.file_to_module_def(ctx.file_id())?; // Enable this assist if the user select all "meaningful" content in the source file let trimmed_selected_range = trimmed_text_range(&source_file, ctx.selection_trimmed()); let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 9b6f7d018ee37..32d6984102081 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -1,6 +1,4 @@ mod generated; -#[cfg(not(feature = "in-rust-tree"))] -mod sourcegen; use expect_test::expect; use hir::Semantics; diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index f2a11276ba2b8..6a4c70d460f2c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -23,7 +23,6 @@ smallvec.workspace = true # local deps base-db.workspace = true ide-db.workspace = true -profile.workspace = true stdx.workspace = true syntax.workspace = true text-edit.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs index cecbe75391d14..5512ac2153460 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs @@ -1,6 +1,7 @@ //! Completes identifiers in format string literals. -use ide_db::syntax_helpers::format_string::is_format_string; +use hir::{ModuleDef, ScopeDef}; +use ide_db::{syntax_helpers::format_string::is_format_string, SymbolKind}; use itertools::Itertools; use syntax::{ast, AstToken, TextRange, TextSize}; @@ -33,7 +34,23 @@ pub(crate) fn format_string( ctx.locals.iter().for_each(|(name, _)| { CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str()) .add_to(acc, ctx.db); - }) + }); + ctx.scope.process_all_names(&mut |name, scope| { + if let ScopeDef::ModuleDef(module_def) = scope { + let symbol_kind = match module_def { + ModuleDef::Const(..) => SymbolKind::Const, + ModuleDef::Static(..) => SymbolKind::Static, + _ => return, + }; + + CompletionItem::new( + CompletionItemKind::SymbolKind(symbol_kind), + source_range, + name.to_smol_str(), + ) + .add_to(acc, ctx.db); + } + }); } #[cfg(test)] @@ -110,6 +127,80 @@ fn main() { let foobar = 1; format_args!("{foobar"); } +"#, + ); + } + + #[test] + fn completes_constants() { + check_edit( + "FOOBAR", + r#" +//- minicore: fmt +fn main() { + const FOOBAR: usize = 42; + format_args!("{f$0"); +} +"#, + r#" +fn main() { + const FOOBAR: usize = 42; + format_args!("{FOOBAR"); +} +"#, + ); + + check_edit( + "FOOBAR", + r#" +//- minicore: fmt +fn main() { + const FOOBAR: usize = 42; + format_args!("{$0"); +} +"#, + r#" +fn main() { + const FOOBAR: usize = 42; + format_args!("{FOOBAR"); +} +"#, + ); + } + + #[test] + fn completes_static_constants() { + check_edit( + "FOOBAR", + r#" +//- minicore: fmt +fn main() { + static FOOBAR: usize = 42; + format_args!("{f$0"); +} +"#, + r#" +fn main() { + static FOOBAR: usize = 42; + format_args!("{FOOBAR"); +} +"#, + ); + + check_edit( + "FOOBAR", + r#" +//- minicore: fmt +fn main() { + static FOOBAR: usize = 42; + format_args!("{$0"); +} +"#, + r#" +fn main() { + static FOOBAR: usize = 42; + format_args!("{FOOBAR"); +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 72c0885e92fa2..361ad821f4a42 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -258,7 +258,7 @@ pub(crate) fn complete_postfix( } fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { - let text = if receiver_is_ambiguous_float_literal { + let mut text = if receiver_is_ambiguous_float_literal { let text = receiver.syntax().text(); let without_dot = ..text.len() - TextSize::of('.'); text.slice(without_dot).to_string() @@ -267,12 +267,18 @@ fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: }; // The receiver texts should be interpreted as-is, as they are expected to be - // normal Rust expressions. We escape '\' and '$' so they don't get treated as - // snippet-specific constructs. - // - // Note that we don't need to escape the other characters that can be escaped, - // because they wouldn't be treated as snippet-specific constructs without '$'. - text.replace('\\', "\\\\").replace('$', "\\$") + // normal Rust expressions. + escape_snippet_bits(&mut text); + text +} + +/// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs. +/// +/// Note that we don't need to escape the other characters that can be escaped, +/// because they wouldn't be treated as snippet-specific constructs without '$'. +fn escape_snippet_bits(text: &mut String) { + stdx::replace(text, '\\', "\\\\"); + stdx::replace(text, '$', "\\$"); } fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs index cb242e4aa6869..fd50fd4e8c5c5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs @@ -17,13 +17,15 @@ // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] use ide_db::{ - syntax_helpers::format_string_exprs::{parse_format_exprs, with_placeholders}, + syntax_helpers::format_string_exprs::{parse_format_exprs, with_placeholders, Arg}, SnippetCap, }; use syntax::{ast, AstToken}; use crate::{ - completions::postfix::build_postfix_snippet_builder, context::CompletionContext, Completions, + completions::postfix::{build_postfix_snippet_builder, escape_snippet_bits}, + context::CompletionContext, + Completions, }; /// Mapping ("postfix completion item" => "macro to use") @@ -51,7 +53,15 @@ pub(crate) fn add_format_like_completions( None => return, }; - if let Ok((out, exprs)) = parse_format_exprs(receiver_text.text()) { + if let Ok((mut out, mut exprs)) = parse_format_exprs(receiver_text.text()) { + // Escape any snippet bits in the out text and any of the exprs. + escape_snippet_bits(&mut out); + for arg in &mut exprs { + if let Arg::Ident(text) | Arg::Expr(text) = arg { + escape_snippet_bits(text) + } + } + let exprs = with_placeholders(exprs); for (label, macro_name) in KINDS { let snippet = if exprs.is_empty() { diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index b487b138fc0e7..071e1b471793d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -44,13 +44,10 @@ line-index.workspace = true [dev-dependencies] expect-test = "1.4.0" -oorandom = "11.1.3" -xshell.workspace = true # local deps test-utils.workspace = true test-fixture.workspace = true -sourcegen.workspace = true [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 2b2df144d6dd1..017635d88e74e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -11,7 +11,7 @@ use profile::{memory_usage, Bytes}; use rustc_hash::FxHashSet; use triomphe::Arc; -use crate::{symbol_index::SymbolsDatabase, Change, RootDatabase}; +use crate::{symbol_index::SymbolsDatabase, ChangeWithProcMacros, RootDatabase}; impl RootDatabase { pub fn request_cancellation(&mut self) { @@ -20,7 +20,7 @@ impl RootDatabase { self.synthetic_write(Durability::LOW); } - pub fn apply_change(&mut self, change: Change) { + pub fn apply_change(&mut self, change: ChangeWithProcMacros) { let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered(); self.request_cancellation(); tracing::trace!("apply_change {:?}", change); @@ -91,7 +91,6 @@ impl RootDatabase { crate::symbol_index::LocalRootsQuery crate::symbol_index::LibraryRootsQuery // HirDatabase - hir::db::InferQueryQuery hir::db::MirBodyQuery hir::db::BorrowckQuery hir::db::TyQuery @@ -130,12 +129,10 @@ impl RootDatabase { hir::db::FnDefVarianceQuery hir::db::AdtVarianceQuery hir::db::AssociatedTyValueQuery - hir::db::TraitSolveQueryQuery hir::db::ProgramClausesForChalkEnvQuery // DefDatabase hir::db::FileItemTreeQuery - hir::db::CrateDefMapQueryQuery hir::db::BlockDefMapQuery hir::db::StructDataWithDiagnosticsQuery hir::db::UnionDataWithDiagnosticsQuery @@ -165,7 +162,6 @@ impl RootDatabase { hir::db::FunctionVisibilityQuery hir::db::ConstVisibilityQuery hir::db::CrateSupportsNoStdQuery - hir::db::BlockItemTreeQueryQuery hir::db::ExternCrateDeclDataQuery hir::db::InternAnonymousConstQuery hir::db::InternExternCrateQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 3329909e9dab4..d50088e6cf1d9 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -22,6 +22,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects certain glob imports that require reporting an ambiguity error"##, }, Lint { label: "ambiguous_glob_reexports", description: r##"ambiguous glob re-exports"## }, + Lint { + label: "ambiguous_wide_pointer_comparisons", + description: r##"detects ambiguous wide pointer comparisons"##, + }, Lint { label: "anonymous_parameters", description: r##"detects anonymous parameters"## }, Lint { label: "arithmetic_overflow", description: r##"arithmetic operation overflows"## }, Lint { @@ -66,10 +70,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "coherence_leak_check", description: r##"distinct impls distinguished only by the leak-check code"##, }, - Lint { - label: "coinductive_overlap_in_coherence", - description: r##"impls that are not considered to overlap may be considered to overlap in the future"##, - }, Lint { label: "conflicting_repr_hints", description: r##"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"##, @@ -86,10 +86,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "const_item_mutation", description: r##"detects attempts to mutate a `const` item"##, }, - Lint { - label: "const_patterns_without_partial_eq", - description: r##"constant in pattern does not implement `PartialEq`"##, - }, Lint { label: "dead_code", description: r##"detect unused, unexported items"## }, Lint { label: "deprecated", description: r##"detects use of deprecated items"## }, Lint { @@ -176,7 +172,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, }, Lint { label: "fuzzy_provenance_casts", @@ -190,14 +186,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "ill_formed_attribute_input", description: r##"ill-formed attribute inputs that were previously accepted and used in practice"##, }, - Lint { - label: "illegal_floating_point_literal_pattern", - description: r##"floating-point literals cannot be used in patterns"##, - }, - Lint { - label: "implied_bounds_entailment", - description: r##"impl method assumes more implied bounds than its corresponding trait method"##, - }, Lint { label: "improper_ctypes", description: r##"proper use of libc types in foreign modules"##, @@ -372,6 +360,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "non_fmt_panics", description: r##"detect single-argument panic!() invocations in which the argument is not a format string"##, }, + Lint { label: "non_local_definitions", description: r##"checks for non-local definitions"## }, Lint { label: "non_shorthand_field_patterns", description: r##"using `Struct { x: x }` instead of `Struct { x }` in a pattern"##, @@ -388,10 +377,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "nonstandard_style", description: r##"lint group for: non-camel-case-types, non-snake-case, non-upper-case-globals"##, }, - Lint { - label: "nontrivial_structural_match", - description: r##"constant used in pattern of non-structural-match type and the constant's initializer expression contains values of non-structural-match types"##, - }, Lint { label: "noop_method_call", description: r##"detects the use of well-known noop methods"##, @@ -482,6 +467,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "rust_2021_prelude_collisions", description: r##"detects the usage of trait methods which are ambiguous with traits added to the prelude in future editions"##, }, + Lint { + label: "rust_2024_compatibility", + description: r##"lint group for: static-mut-refs, unsafe-op-in-unsafe-fn"##, + }, Lint { label: "semicolon_in_expressions_from_macros", description: r##"trailing semicolon in macro body used as expression"##, @@ -502,6 +491,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "stable_features", description: r##"stable features found in `#[feature]` directive"##, }, + Lint { + label: "static_mut_refs", + description: r##"shared references or mutable references of mutable static is discouraged"##, + }, Lint { label: "suspicious_double_ref_op", description: r##"suspicious call of trait method on `&&T`"##, @@ -575,6 +568,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"##, }, Lint { label: "uninhabited_static", description: r##"uninhabited static"## }, + Lint { + label: "unit_bindings", + description: r##"binding is useless because it has the unit `()` type"##, + }, Lint { label: "unknown_crate_types", description: r##"unknown crate type found in `#[crate_type]` directive"##, @@ -606,10 +603,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "unsafe_op_in_unsafe_fn", description: r##"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"##, }, - Lint { - label: "unstable_features", - description: r##"enabling unstable features (deprecated. do not use)"##, - }, + Lint { label: "unstable_features", description: r##"enabling unstable features"## }, Lint { label: "unstable_name_collisions", description: r##"detects name collision with an existing but unstable method"##, @@ -695,10 +689,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "unused_results", description: r##"unused result of an expression in a statement"##, }, - Lint { - label: "unused_tuple_struct_fields", - description: r##"detects tuple struct fields that are never read"##, - }, Lint { label: "unused_unsafe", description: r##"unnecessary use of an `unsafe` block"## }, Lint { label: "unused_variables", @@ -732,13 +722,17 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "while_true", description: r##"suggest using `loop { }` instead of `while true { }`"##, }, + Lint { + label: "writes_through_immutable_pointer", + description: r##"shared references are immutable, and pointers derived from them must not be written to"##, + }, ]; pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, }, children: &[ "deref_into_dyn_supertrait", @@ -747,16 +741,12 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "byte_slice_in_packed_struct_with_derive", "cenum_impl_drop_cast", "coherence_leak_check", - "coinductive_overlap_in_coherence", "conflicting_repr_hints", "const_evaluatable_unchecked", - "const_patterns_without_partial_eq", "deprecated_cfg_attr_crate_type_name", "elided_lifetimes_in_associated_constant", "forbidden_lint_groups", "ill_formed_attribute_input", - "illegal_floating_point_literal_pattern", - "implied_bounds_entailment", "indirect_structural_match", "invalid_doc_attributes", "invalid_type_param_default", @@ -764,7 +754,6 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "legacy_derive_helpers", "macro_expanded_macro_exports_accessed_by_absolute_paths", "missing_fragment_specifier", - "nontrivial_structural_match", "order_dependent_trait_objects", "patterns_in_fns_without_body", "pointer_structural_match", @@ -779,6 +768,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "unstable_syntax_pre_expansion", "unsupported_calling_conventions", "where_clauses_object_safety", + "writes_through_immutable_pointer", ], }, LintGroup { @@ -836,6 +826,13 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "non_fmt_panics", ], }, + LintGroup { + lint: Lint { + label: "rust_2024_compatibility", + description: r##"lint group for: static-mut-refs, unsafe-op-in-unsafe-fn"##, + }, + children: &["static_mut_refs", "unsafe_op_in_unsafe_fn"], + }, LintGroup { lint: Lint { label: "unused", @@ -1730,9 +1727,17 @@ The tracking issue for this feature is: [#110011] label: "async_fn_traits", description: r##"# `async_fn_traits` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +See Also: [`fn_traits`](../library-features/fn-traits.md) ------------------------- +---- + +The `async_fn_traits` feature allows for implementation of the [`AsyncFn*`] traits +for creating custom closure-like types that return futures. + +[`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html + +The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future +that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does). "##, }, Lint { @@ -2372,17 +2377,6 @@ The tracking issue for this feature is: [#89653] [#89653]: https://github.com/rust-lang/rust/issues/89653 ------------------------- -"##, - }, - Lint { - label: "cfg_target_abi", - description: r##"# `cfg_target_abi` - -The tracking issue for this feature is: [#80970] - -[#80970]: https://github.com/rust-lang/rust/issues/80970 - ------------------------ "##, }, @@ -3128,6 +3122,17 @@ The tracking issue for this feature is: [#90603] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +------------------------ +"##, + }, + Lint { + label: "const_intrinsic_copy", + description: r##"# `const_intrinsic_copy` + +The tracking issue for this feature is: [#80697] + +[#80697]: https://github.com/rust-lang/rust/issues/80697 + ------------------------ "##, }, @@ -3296,6 +3301,17 @@ The tracking issue for this feature is: [#110840] [#110840]: https://github.com/rust-lang/rust/issues/110840 +------------------------ +"##, + }, + Lint { + label: "const_ops", + description: r##"# `const_ops` + +The tracking issue for this feature is: [#90080] + +[#90080]: https://github.com/rust-lang/rust/issues/90080 + ------------------------ "##, }, @@ -3439,6 +3455,17 @@ The tracking issue for this feature is: [#80384] [#80384]: https://github.com/rust-lang/rust/issues/80384 +------------------------ +"##, + }, + Lint { + label: "const_refs_to_static", + description: r##"# `const_refs_to_static` + +The tracking issue for this feature is: [#119618] + +[#119618]: https://github.com/rust-lang/rust/issues/119618 + ------------------------ "##, }, @@ -4251,6 +4278,15 @@ The tracking issue for this feature is: [#27336] [#27336]: https://github.com/rust-lang/rust/issues/27336 +------------------------ +"##, + }, + Lint { + label: "delayed_debug_assertions", + description: r##"# `delayed_debug_assertions` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -4632,6 +4668,19 @@ The tracking issue for this feature is: [#57391] [#57391]: https://github.com/rust-lang/rust/issues/57391 ------------------------ +"##, + }, + Lint { + label: "duration_constructors", + description: r##"# `duration_constructors` + +The tracking issue for this feature is: [#120301] + +[#120301]: https://github.com/rust-lang/rust/issues/120301 + +------------------------ + +Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`. "##, }, Lint { @@ -4642,6 +4691,17 @@ The tracking issue for this feature is: [#72440] [#72440]: https://github.com/rust-lang/rust/issues/72440 +------------------------ +"##, + }, + Lint { + label: "duration_units", + description: r##"# `duration_units` + +The tracking issue for this feature is: [#120301] + +[#120301]: https://github.com/rust-lang/rust/issues/120301 + ------------------------ "##, }, @@ -5654,13 +5714,62 @@ raw pointers in intra-doc links are unstable until it does. The tracking issue for this feature is: None. -Intrinsics are never intended to be stable directly, but intrinsics are often +Intrinsics are rarely intended to be stable directly, but are usually exported in some sort of stable manner. Prefer using the stable interfaces to the intrinsic directly when you can. ------------------------ +## Intrinsics with fallback logic + +Many intrinsics can be written in pure rust, albeit inefficiently or without supporting +some features that only exist on some backends. Backends can simply not implement those +intrinsics without causing any code miscompilations or failures to compile. +All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`) +by the codegen backend, but not the MIR inliner. + +```rust +#![feature(rustc_attrs, effects)] +#![allow(internal_features)] + +#[rustc_intrinsic] +const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} +``` + +Since these are just regular functions, it is perfectly ok to create the intrinsic twice: + +```rust +#![feature(rustc_attrs, effects)] +#![allow(internal_features)] + +#[rustc_intrinsic] +const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + +mod foo { + #[rustc_intrinsic] + const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { + panic!("noisy const dealloc") + } +} + +``` + +The behaviour on backends that override the intrinsic is exactly the same. On other +backends, the intrinsic behaviour depends on which implementation is called, just like +with any regular function. + +## Intrinsics lowered to MIR instructions + +Various intrinsics have native MIR operations that they correspond to. Instead of requiring +backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass +will convert the calls to the MIR operation. Backends do not need to know about these intrinsics +at all. + +## Intrinsics without fallback logic + +These must be implemented by all backends. + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and @@ -5679,7 +5788,8 @@ extern "rust-intrinsic" { } ``` -As with any other FFI functions, these are always `unsafe` to call. +As with any other FFI functions, these are by default always `unsafe` to call. +You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. "##, }, Lint { @@ -5754,6 +5864,17 @@ The tracking issue for this feature is: [#101288] [#101288]: https://github.com/rust-lang/rust/issues/101288 +------------------------ +"##, + }, + Lint { + label: "is_riscv_feature_detected", + description: r##"# `is_riscv_feature_detected` + +The tracking issue for this feature is: [#111192] + +[#111192]: https://github.com/rust-lang/rust/issues/111192 + ------------------------ "##, }, @@ -5932,6 +6053,17 @@ The tracking issue for this feature is: [#87053] [#87053]: https://github.com/rust-lang/rust/issues/87053 +------------------------ +"##, + }, + Lint { + label: "lahfsahf_target_feature", + description: r##"# `lahfsahf_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + ------------------------ "##, }, @@ -6255,6 +6387,17 @@ The tracking issue for this feature is: [#82971] [#82971]: https://github.com/rust-lang/rust/issues/82971 +------------------------ +"##, + }, + Lint { + label: "local_waker", + description: r##"# `local_waker` + +The tracking issue for this feature is: [#118959] + +[#118959]: https://github.com/rust-lang/rust/issues/118959 + ------------------------ "##, }, @@ -6321,6 +6464,17 @@ The tracking issue for this feature is: [#82766] [#82766]: https://github.com/rust-lang/rust/issues/82766 +------------------------ +"##, + }, + Lint { + label: "mapped_lock_guards", + description: r##"# `mapped_lock_guards` + +The tracking issue for this feature is: [#117108] + +[#117108]: https://github.com/rust-lang/rust/issues/117108 + ------------------------ "##, }, @@ -6534,17 +6688,6 @@ The tracking issue for this feature is: [#83310] [#83310]: https://github.com/rust-lang/rust/issues/83310 ------------------------- -"##, - }, - Lint { - label: "mutex_unlock", - description: r##"# `mutex_unlock` - -The tracking issue for this feature is: [#81872] - -[#81872]: https://github.com/rust-lang/rust/issues/81872 - ------------------------ "##, }, @@ -6972,6 +7115,17 @@ The tracking issue for this feature is: [#70086] [#70086]: https://github.com/rust-lang/rust/issues/70086 +------------------------ +"##, + }, + Lint { + label: "os_str_display", + description: r##"# `os_str_display` + +The tracking issue for this feature is: [#120048] + +[#120048]: https://github.com/rust-lang/rust/issues/120048 + ------------------------ "##, }, @@ -7102,6 +7256,15 @@ The tracking issue for this feature is: [#27721] [#27721]: https://github.com/rust-lang/rust/issues/27721 +------------------------ +"##, + }, + Lint { + label: "pattern_complexity", + description: r##"# `pattern_complexity` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -7124,17 +7287,6 @@ The tracking issue for this feature is: [#86918] [#86918]: https://github.com/rust-lang/rust/issues/86918 ------------------------- -"##, - }, - Lint { - label: "platform_intrinsics", - description: r##"# `platform_intrinsics` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------ "##, }, @@ -7184,7 +7336,9 @@ The tracking issue for this feature is: [#44839] label: "prelude_2024", description: r##"# `prelude_2024` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#121042] + +[#121042]: https://github.com/rust-lang/rust/issues/121042 ------------------------ "##, @@ -7195,6 +7349,17 @@ This feature has no tracking issue, and is therefore likely internal to the comp This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +------------------------ +"##, + }, + Lint { + label: "prfchw_target_feature", + description: r##"# `prfchw_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + ------------------------ "##, }, @@ -7507,6 +7672,17 @@ The tracking issue for this feature is: [#101196] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +------------------------ +"##, + }, + Lint { + label: "reentrant_lock", + description: r##"# `reentrant_lock` + +The tracking issue for this feature is: [#121440] + +[#121440]: https://github.com/rust-lang/rust/issues/121440 + ------------------------ "##, }, @@ -8181,23 +8357,45 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "stdio_makes_pipe", - description: r##"# `stdio_makes_pipe` + label: "stdarch_arm_feature_detection", + description: r##"# `stdarch_arm_feature_detection` -The tracking issue for this feature is: [#98288] +The tracking issue for this feature is: [#111190] -[#98288]: https://github.com/rust-lang/rust/issues/98288 +[#111190]: https://github.com/rust-lang/rust/issues/111190 + +------------------------ +"##, + }, + Lint { + label: "stdarch_mips_feature_detection", + description: r##"# `stdarch_mips_feature_detection` + +The tracking issue for this feature is: [#111188] + +[#111188]: https://github.com/rust-lang/rust/issues/111188 + +------------------------ +"##, + }, + Lint { + label: "stdarch_powerpc_feature_detection", + description: r##"# `stdarch_powerpc_feature_detection` + +The tracking issue for this feature is: [#111191] + +[#111191]: https://github.com/rust-lang/rust/issues/111191 ------------------------ "##, }, Lint { - label: "stdsimd", - description: r##"# `stdsimd` + label: "stdio_makes_pipe", + description: r##"# `stdio_makes_pipe` -The tracking issue for this feature is: [#48556] +The tracking issue for this feature is: [#98288] -[#48556]: https://github.com/rust-lang/rust/issues/48556 +[#98288]: https://github.com/rust-lang/rust/issues/98288 ------------------------ "##, @@ -8459,6 +8657,17 @@ The tracking issue for this feature is: [#44839] [#44839]: https://github.com/rust-lang/rust/issues/44839 +------------------------ +"##, + }, + Lint { + label: "tcp_deferaccept", + description: r##"# `tcp_deferaccept` + +The tracking issue for this feature is: [#119639] + +[#119639]: https://github.com/rust-lang/rust/issues/119639 + ------------------------ "##, }, @@ -10151,7 +10360,7 @@ table: }, Lint { label: "clippy::blocks_in_conditions", - description: r##"Checks for `if` conditions that use blocks containing an + description: r##"Checks for `if` and `match` conditions that use blocks containing an expression, statements or conditions that use closures with blocks."##, }, Lint { @@ -10453,6 +10662,12 @@ See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-in label: "clippy::deprecated_cfg_attr", description: r##"Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it with `#[rustfmt::skip]`."##, + }, + Lint { + label: "clippy::deprecated_clippy_cfg_attr", + description: r##"Checks for `#[cfg_attr(feature = cargo-clippy, ...)]` and for +`#[cfg(feature = cargo-clippy)]` and suggests to replace it with +`#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`."##, }, Lint { label: "clippy::deprecated_semver", @@ -10596,6 +10811,7 @@ eagerly (e.g. using `bool::then_some`)."##, description: r##"Checks for usage of if expressions with an `else if` branch, but without a final `else` branch."##, }, + Lint { label: "clippy::empty_docs", description: r##"Detects documentation that is empty."## }, Lint { label: "clippy::empty_drop", description: r##"Checks for empty `Drop` implementations."##, @@ -11352,6 +11568,7 @@ cannot be represented as the underlying type without loss."##, description: r##"Checks for usage of `std::mem::size_of::() * 8` when `T::BITS` is available."##, }, + Lint { label: "clippy::manual_c_str_literals", description: r##""## }, Lint { label: "clippy::manual_clamp", description: r##"Identifies good opportunities for a clamp function from std or core, and suggests using it."##, @@ -11726,6 +11943,10 @@ rather than globally."##, label: "clippy::mistyped_literal_suffixes", description: r##"Warns for mistyped suffix in literals"##, }, + Lint { + label: "clippy::mixed_attributes_style", + description: r##"Checks that an item has only one kind of attributes."##, + }, Lint { label: "clippy::mixed_case_hex_literals", description: r##"Warns on hexadecimal literals with mixed-case letter @@ -11758,6 +11979,10 @@ containing module's name."##, one."##, }, Lint { label: "clippy::multi_assignments", description: r##"Checks for nested assignments."## }, + Lint { + label: "clippy::multiple_bound_locations", + description: r##"Check if a generic is defined both in the bound predicate and in the `where` clause."##, + }, Lint { label: "clippy::multiple_crate_versions", description: r##"Checks to see if multiple versions of a crate are being @@ -12331,8 +12556,8 @@ in `vec![elem; len]`"##, Lint { label: "clippy::read_line_without_trim", description: r##"Looks for calls to [`Stdin::read_line`] to read a line from the standard input -into a string, then later attempting to parse this string into a type without first trimming it, which will -always fail because the string has a trailing newline in it."##, +into a string, then later attempting to use that string for an operation that will never +work for strings with a trailing newline character in it (e.g. parsing into a `i32`)."##, }, Lint { label: "clippy::read_zero_byte_vec", @@ -12439,6 +12664,11 @@ do not change the type."##, label: "clippy::redundant_type_annotations", description: r##"Warns about needless / redundant type annotations."##, }, + Lint { + label: "clippy::ref_as_ptr", + description: r##"Checks for casts of references to pointer using `as` +and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead."##, + }, Lint { label: "clippy::ref_binding_to_reference", description: r##"Checks for `ref` bindings which create a reference to a reference."##, @@ -13090,6 +13320,11 @@ as returning a large `T` directly may be detrimental to performance."##, label: "clippy::unnecessary_cast", description: r##"Checks for casts to the same type, casts of int literals to integer types, casts of float literals to float types and casts between raw pointers without changing type or constness."##, + }, + Lint { + label: "clippy::unnecessary_clippy_cfg", + description: r##"Checks for `#[cfg_attr(clippy, allow(clippy::lint))]` +and suggests to replace it with `#[allow(clippy::lint)]`."##, }, Lint { label: "clippy::unnecessary_fallible_conversions", @@ -13114,6 +13349,10 @@ find or map operations and suggests the appropriate option."##, Specifically, this checks for `fold`s which could be replaced by `any`, `all`, `sum` or `product`."##, }, + Lint { + label: "clippy::unnecessary_get_then_check", + description: r##"Checks the usage of `.get().is_some()` or `.get().is_none()` on std map types."##, + }, Lint { label: "clippy::unnecessary_join", description: r##"Checks for usage of `.collect::>().join()` on iterators."##, @@ -13825,7 +14064,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_filter_is_ok, clippy::iter_filter_is_some, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_is_variant_and, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_as_ref_cloned, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::pub_underscore_fields, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::str_split_at_newline, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_filter_is_ok, clippy::iter_filter_is_some, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_c_str_literals, clippy::manual_instant_elapsed, clippy::manual_is_variant_and, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_as_ref_cloned, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::pub_underscore_fields, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_as_ptr, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::str_split_at_newline, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ "clippy::bool_to_int_with_if", @@ -13876,6 +14115,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::linkedlist", "clippy::macro_use_imports", "clippy::manual_assert", + "clippy::manual_c_str_literals", "clippy::manual_instant_elapsed", "clippy::manual_is_variant_and", "clippy::manual_let_else", @@ -13913,6 +14153,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::range_plus_one", "clippy::redundant_closure_for_method_calls", "clippy::redundant_else", + "clippy::ref_as_ptr", "clippy::ref_binding_to_reference", "clippy::ref_option_ref", "clippy::return_self_not_must_use", @@ -14257,7 +14498,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::incompatible_msrv, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_open_options, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion, clippy::unnecessary_result_map_or_else"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::deprecated_clippy_cfg_attr, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_docs, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::incompatible_msrv, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::mixed_attributes_style, clippy::multi_assignments, clippy::multiple_bound_locations, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_open_options, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion, clippy::unnecessary_clippy_cfg, clippy::unnecessary_get_then_check, clippy::unnecessary_result_map_or_else"##, }, children: &[ "clippy::almost_complete_range", @@ -14272,8 +14513,10 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::cast_nan_to_int", "clippy::cast_slice_from_raw_parts", "clippy::crate_in_macro_def", + "clippy::deprecated_clippy_cfg_attr", "clippy::drop_non_drop", "clippy::duplicate_mod", + "clippy::empty_docs", "clippy::empty_loop", "clippy::float_equality_without_abs", "clippy::forget_non_drop", @@ -14288,7 +14531,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::maybe_misused_cfg", "clippy::misnamed_getters", "clippy::misrefactored_assign_op", + "clippy::mixed_attributes_style", "clippy::multi_assignments", + "clippy::multiple_bound_locations", "clippy::mut_range_bound", "clippy::mutable_key_type", "clippy::no_effect_replace", @@ -14316,6 +14561,8 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::test_attr_in_doctest", "clippy::type_id_on_box", "clippy::unconditional_recursion", + "clippy::unnecessary_clippy_cfg", + "clippy::unnecessary_get_then_check", "clippy::unnecessary_result_map_or_else", ], }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index 0b5ad7060e043..4ac8a7c4c4aa3 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -64,7 +64,7 @@ pub fn visit_file_defs( cb: &mut dyn FnMut(Definition), ) { let db = sema.db; - let module = match sema.to_module_def(file_id) { + let module = match sema.file_to_module_def(file_id) { Some(it) => it, None => return, }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 3e6cb7476bbb4..be08b37bac342 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -44,7 +44,7 @@ pub mod syntax_helpers { pub use parser::LexedStr; } -pub use hir::Change; +pub use hir::ChangeWithProcMacros; use std::{fmt, mem::ManuallyDrop}; @@ -216,7 +216,6 @@ impl RootDatabase { // DefDatabase hir_db::FileItemTreeQuery - hir_db::CrateDefMapQueryQuery hir_db::BlockDefMapQuery hir_db::StructDataWithDiagnosticsQuery hir_db::UnionDataWithDiagnosticsQuery @@ -248,7 +247,6 @@ impl RootDatabase { hir_db::CrateSupportsNoStdQuery // HirDatabase - hir_db::InferQueryQuery hir_db::MirBodyQuery hir_db::BorrowckQuery hir_db::TyQuery @@ -287,7 +285,6 @@ impl RootDatabase { hir_db::FnDefVarianceQuery hir_db::AdtVarianceQuery hir_db::AssociatedTyValueQuery - hir_db::TraitSolveQueryQuery hir_db::ProgramClausesForChalkEnvQuery // SymbolsDatabase @@ -412,9 +409,3 @@ impl SnippetCap { } } } - -#[cfg(test)] -mod tests { - mod line_index; - mod sourcegen_lints; -} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index ef15f585fa2db..024e8f6ae39d2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -129,7 +129,7 @@ pub fn parallel_prime_caches( crates_currently_indexing.insert(crate_id, crate_name); } ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => { - crates_currently_indexing.remove(&crate_id); + crates_currently_indexing.swap_remove(&crate_id); crates_to_prime.mark_done(crate_id); crates_done += 1; } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index 49594aee9f354..8ab5a6ede3bd5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -11,15 +11,12 @@ pub enum Arg { Expr(String), } -/** - Add placeholders like `$1` and `$2` in place of [`Arg::Placeholder`], - and unwraps the [`Arg::Ident`] and [`Arg::Expr`] enums. - ```rust - # use ide_db::syntax_helpers::format_string_exprs::*; - assert_eq!(with_placeholders(vec![Arg::Ident("ident".to_owned()), Arg::Placeholder, Arg::Expr("expr + 2".to_owned())]), vec!["ident".to_owned(), "$1".to_owned(), "expr + 2".to_owned()]) - ``` -*/ - +/// Add placeholders like `$1` and `$2` in place of [`Arg::Placeholder`], +/// and unwraps the [`Arg::Ident`] and [`Arg::Expr`] enums. +/// ```rust +/// # use ide_db::syntax_helpers::format_string_exprs::*; +/// assert_eq!(with_placeholders(vec![Arg::Ident("ident".to_owned()), Arg::Placeholder, Arg::Expr("expr + 2".to_owned())]), vec!["ident".to_owned(), "$1".to_owned(), "expr + 2".to_owned()]) +/// ``` pub fn with_placeholders(args: Vec) -> Vec { let mut placeholder_id = 1; args.into_iter() @@ -34,18 +31,15 @@ pub fn with_placeholders(args: Vec) -> Vec { .collect() } -/** - Parser for a format-like string. It is more allowing in terms of string contents, - as we expect variable placeholders to be filled with expressions. - - Built for completions and assists, and escapes `\` and `$` in output. - (See the comments on `get_receiver_text()` for detail.) - Splits a format string that may contain expressions - like - ```rust - assert_eq!(parse("{ident} {} {expr + 42} ").unwrap(), ("{} {} {}", vec![Arg::Ident("ident"), Arg::Placeholder, Arg::Expr("expr + 42")])); - ``` -*/ +/// Parser for a format-like string. It is more allowing in terms of string contents, +/// as we expect variable placeholders to be filled with expressions. +/// +/// Splits a format string that may contain expressions +/// like +/// ```rust +/// # use ide_db::syntax_helpers::format_string_exprs::*; +/// assert_eq!(parse_format_exprs("{ident} {} {expr + 42} ").unwrap(), ("{ident} {} {} ".to_owned(), vec![Arg::Placeholder, Arg::Expr("expr + 42".to_owned())])); +/// ``` pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { #[derive(Debug, Clone, Copy, PartialEq)] enum State { @@ -79,9 +73,6 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { state = State::MaybeIncorrect; } (State::NotArg, _) => { - if matches!(chr, '\\' | '$') { - output.push('\\'); - } output.push(chr); } (State::MaybeIncorrect, '}') => { @@ -110,9 +101,6 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { state = State::FormatOpts; } (State::MaybeArg, _) => { - if matches!(chr, '\\' | '$') { - current_expr.push('\\'); - } current_expr.push(chr); // While Rust uses the unicode sets of XID_start and XID_continue for Identifiers @@ -172,9 +160,6 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { state = State::Expr; } - if matches!(chr, '\\' | '$') { - current_expr.push('\\'); - } current_expr.push(chr); } (State::FormatOpts, '}') => { @@ -182,9 +167,6 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { state = State::NotArg; } (State::FormatOpts, _) => { - if matches!(chr, '\\' | '$') { - output.push('\\'); - } output.push(chr); } } @@ -217,15 +199,15 @@ mod tests { fn format_str_parser() { let test_vector = &[ ("no expressions", expect![["no expressions"]]), - (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]), + (r"no expressions with \$0$1", expect![r"no expressions with \$0$1"]), ("{expr} is {2 + 2}", expect![["{expr} is {}; 2 + 2"]]), ("{expr:?}", expect![["{expr:?}"]]), - ("{expr:1$}", expect![[r"{expr:1\$}"]]), - ("{:1$}", expect![[r"{:1\$}; $1"]]), - ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]), + ("{expr:1$}", expect![[r"{expr:1$}"]]), + ("{:1$}", expect![[r"{:1$}; $1"]]), + ("{:>padding$}", expect![[r"{:>padding$}; $1"]]), ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]), ("{}, {}, {0:b}", expect![[r"{}, {}, {0:b}; $1, $2"]]), - ("{$0}", expect![[r"{}; \$0"]]), + ("{$0}", expect![[r"{}; $0"]]), ("{malformed", expect![["-"]]), ("malformed}", expect![["-"]]), ("{{correct", expect![["{{correct"]]), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs index 0b0fc6693526f..97b6d4a572a21 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs @@ -20,7 +20,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { let after = Position::after; let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| { - (pos(token.clone()), make::tokens::whitespace(&" ".repeat(2 * indent))) + (pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent))) }; let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| { (pos(token.clone()), make::tokens::single_space()) @@ -41,7 +41,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { if indent > 0 { mods.push(( Position::after(node.clone()), - make::tokens::whitespace(&" ".repeat(2 * indent)), + make::tokens::whitespace(&" ".repeat(4 * indent)), )); } if node.parent().is_some() { @@ -91,10 +91,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { LIFETIME_IDENT if is_next(is_text, true) => { mods.push(do_ws(after, tok)); } - MUT_KW if is_next(|it| it == SELF_KW, false) => { - mods.push(do_ws(after, tok)); - } - AS_KW | DYN_KW | IMPL_KW | CONST_KW => { + AS_KW | DYN_KW | IMPL_KW | CONST_KW | MUT_KW => { mods.push(do_ws(after, tok)); } T![;] if is_next(|it| it != R_CURLY, true) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs deleted file mode 100644 index 6b49bb2631c19..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs +++ /dev/null @@ -1,49 +0,0 @@ -use line_index::{LineCol, LineIndex, WideEncoding}; -use test_utils::skip_slow_tests; - -#[test] -fn test_every_chars() { - if skip_slow_tests() { - return; - } - - let text: String = { - let mut chars: Vec = ((0 as char)..char::MAX).collect(); // Neat! - chars.extend("\n".repeat(chars.len() / 16).chars()); - let mut rng = oorandom::Rand32::new(stdx::rand::seed()); - stdx::rand::shuffle(&mut chars, |i| rng.rand_range(0..i as u32) as usize); - chars.into_iter().collect() - }; - assert!(text.contains('💩')); // Sanity check. - - let line_index = LineIndex::new(&text); - - let mut lin_col = LineCol { line: 0, col: 0 }; - let mut col_utf16 = 0; - let mut col_utf32 = 0; - for (offset, c) in text.char_indices() { - let got_offset = line_index.offset(lin_col).unwrap(); - assert_eq!(usize::from(got_offset), offset); - - let got_lin_col = line_index.line_col(got_offset); - assert_eq!(got_lin_col, lin_col); - - for (enc, col) in [(WideEncoding::Utf16, col_utf16), (WideEncoding::Utf32, col_utf32)] { - let wide_lin_col = line_index.to_wide(enc, lin_col).unwrap(); - let got_lin_col = line_index.to_utf8(enc, wide_lin_col).unwrap(); - assert_eq!(got_lin_col, lin_col); - assert_eq!(wide_lin_col.col, col) - } - - if c == '\n' { - lin_col.line += 1; - lin_col.col = 0; - col_utf16 = 0; - col_utf32 = 0; - } else { - lin_col.col += c.len_utf8() as u32; - col_utf16 += c.len_utf16() as u32; - col_utf32 += 1; - } - } -} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index 69768041389ac..8ccea99e9e13d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -20,7 +20,6 @@ tracing.workspace = true once_cell = "1.17.0" # local deps -profile.workspace = true stdx.workspace = true syntax.workspace = true text-edit.workspace = true @@ -34,10 +33,6 @@ expect-test = "1.4.0" # local deps test-utils.workspace = true test-fixture.workspace = true -sourcegen.workspace = true - -[features] -in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 09daefd084dc2..f92ba576d3ab5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -200,7 +200,7 @@ fn get_default_constructor( } } - let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate(); + let krate = ctx.sema.file_to_module_def(d.file.original_file(ctx.sema.db))?.krate(); let module = krate.root_module(); // Look for a ::new() associated function diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 8596f5792e0fb..67daa172b27e5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -597,21 +597,19 @@ fn bang(never: !) { #[test] fn unknown_type() { - cov_mark::check_count!(validate_match_bailed_out, 1); - - check_diagnostics( + check_diagnostics_no_bails( r#" enum Option { Some(T), None } #[allow(unused)] fn main() { // `Never` is deliberately not defined so that it's an uninferred type. + // We ignore these to avoid triggering bugs in the analysis. match Option::::None { None => (), Some(never) => match never {}, } match Option::::None { - //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `None` not covered Option::Some(_never) => {}, } } @@ -619,6 +617,18 @@ fn main() { ); } + #[test] + fn arity_mismatch_issue_16746() { + check_diagnostics_with_disabled( + r#" +fn main() { + let (a, ) = (0, 0); +} +"#, + &["E0308"], + ); + } + #[test] fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { check_diagnostics_no_bails( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs index 47844876dc540..f68e698238562 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs @@ -30,6 +30,7 @@ pub(crate) fn remove_unnecessary_else( "remove unnecessary else block", display_range, ) + .experimental() .with_fixes(fixes(ctx, d)) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 9f4368b04e79b..0df6f0e0373c8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -227,6 +227,7 @@ pub struct DiagnosticsConfig { pub disable_experimental: bool, pub disabled: FxHashSet, pub expr_fill_default: ExprFillDefaultMode, + pub style_lints: bool, // FIXME: We may want to include a whole `AssistConfig` here pub insert_use: InsertUseConfig, pub prefer_no_std: bool, @@ -245,6 +246,7 @@ impl DiagnosticsConfig { disable_experimental: Default::default(), disabled: Default::default(), expr_fill_default: Default::default(), + style_lints: true, insert_use: InsertUseConfig { granularity: ImportGranularity::Preserve, enforce_granularity: false, @@ -299,7 +301,7 @@ pub fn diagnostics( let mut res = Vec::new(); // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. - res.extend(parse.errors().iter().take(128).map(|err| { + res.extend(parse.errors().into_iter().take(128).map(|err| { Diagnostic::new( DiagnosticCode::RustcHardError("syntax-error"), format!("Syntax Error: {err}"), @@ -315,7 +317,7 @@ pub fn diagnostics( handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config); } - let module = sema.to_module_def(file_id); + let module = sema.file_to_module_def(file_id); let ctx = DiagnosticsContext { config, sema, resolve }; if module.is_none() { @@ -324,7 +326,7 @@ pub fn diagnostics( let mut diags = Vec::new(); if let Some(m) = module { - m.diagnostics(db, &mut diags); + m.diagnostics(db, &mut diags, config.style_lints); } for diag in diags { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 901ceffbb266d..dcaa212089233 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -1,6 +1,4 @@ #![allow(clippy::print_stderr)] -#[cfg(not(feature = "in-rust-tree"))] -mod sourcegen; use ide_db::{ assists::AssistResolveStrategy, base_db::SourceDatabaseExt, LineIndexDatabase, RootDatabase, diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml index bb06d614450fb..aca7d613e11fc 100644 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml @@ -17,11 +17,11 @@ arrayvec.workspace = true either.workspace = true itertools.workspace = true tracing.workspace = true -oorandom = "11.1.3" -pulldown-cmark-to-cmark = "10.0.4" -pulldown-cmark = { version = "0.9.1", default-features = false } -url = "2.3.1" -dot = "0.1.4" +oorandom.workspace = true +pulldown-cmark-to-cmark.workspace = true +pulldown-cmark.workspace = true +url.workspace = true +dot.workspace = true smallvec.workspace = true triomphe.workspace = true nohash-hasher.workspace = true @@ -52,7 +52,7 @@ test-utils.workspace = true test-fixture.workspace = true [features] -in-rust-tree = ["ide-assists/in-rust-tree", "ide-diagnostics/in-rust-tree"] +in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index 17c701ad03591..4b0961cbbebaf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -189,7 +189,7 @@ fn _format( let &crate_id = db.relevant_crates(file_id).iter().next()?; let edition = db.crate_graph()[crate_id].edition; - let mut cmd = std::process::Command::new(toolchain::rustfmt()); + let mut cmd = std::process::Command::new(toolchain::Tool::Rustfmt.path()); cmd.arg("--edition"); cmd.arg(edition.to_string()); @@ -308,8 +308,8 @@ f$0oo!(); expect![[r#" foo! fn some_thing() -> u32 { - let a = 0; - a+10 + let a = 0; + a+10 }"#]], ); } @@ -342,13 +342,13 @@ fn main() { expect![[r#" match_ast! { - if let Some(it) = ast::TraitDef::cast(container.clone()){} - else if let Some(it) = ast::ImplDef::cast(container.clone()){} - else { - { - continue + if let Some(it) = ast::TraitDef::cast(container.clone()){} + else if let Some(it) = ast::ImplDef::cast(container.clone()){} + else { + { + continue + } } - } }"#]], ); } @@ -397,12 +397,12 @@ fn main() { expect![[r#" foo! { - macro_rules! bar { - () => { - 42 + macro_rules! bar { + () => { + 42 + } } - } - 42 + 42 }"#]], ); } @@ -482,16 +482,16 @@ struct Foo {} expect![[r#" Clone impl < >$crate::clone::Clone for Foo< >where { - fn clone(&self) -> Self { - match self { - Foo{} - => Foo{} - , + fn clone(&self) -> Self { + match self { + Foo{} + => Foo{} + , - } - } + } + } - }"#]], + }"#]], ); } @@ -534,16 +534,16 @@ struct Foo {} expect![[r#" Clone impl < >$crate::clone::Clone for Foo< >where { - fn clone(&self) -> Self { - match self { - Foo{} - => Foo{} - , + fn clone(&self) -> Self { + match self { + Foo{} + => Foo{} + , - } - } + } + } - }"#]], + }"#]], ); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 41148db614606..1bda15255dcd0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -536,6 +536,24 @@ fn bar() { ); } + #[test] + fn goto_definition_works_for_consts_inside_range_pattern() { + check( + r#" +//- /lib.rs +const A: u32 = 0; + //^ + +fn bar(v: u32) { + match v { + 0..=$0A => {} + _ => {} + } +} +"#, + ); + } + #[test] fn goto_def_for_use_alias() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 4a7350feb385e..8f4c629b58130 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -32,6 +32,7 @@ pub struct HoverConfig { pub documentation: bool, pub keywords: bool, pub format: HoverDocFormat, + pub max_trait_assoc_items_count: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 563e78253a8ae..d1d039534d51e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -406,7 +406,12 @@ pub(super) fn definition( config: &HoverConfig, ) -> Markup { let mod_path = definition_mod_path(db, &def); - let label = def.label(db); + let label = match def { + Definition::Trait(trait_) => { + trait_.display_limited(db, config.max_trait_assoc_items_count).to_string() + } + _ => def.label(db), + }; let docs = def.docs(db, famous_defs); let value = (|| match def { Definition::Variant(it) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index b9ae89cc18d0a..c3cd6513dc616 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -17,6 +17,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { documentation: true, format: HoverDocFormat::Markdown, keywords: true, + max_trait_assoc_items_count: None, }; fn check_hover_no_result(ra_fixture: &str) { @@ -48,6 +49,28 @@ fn check(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } +#[track_caller] +fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) { + let (analysis, position) = fixture::position(ra_fixture); + let hover = analysis + .hover( + &HoverConfig { + links_in_hover: true, + max_trait_assoc_items_count: Some(count), + ..HOVER_BASE_CONFIG + }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); + + let content = analysis.db.file_text(position.file_id); + let hovered_element = &content[hover.range]; + + let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); + expect.assert_eq(&actual) +} + fn check_hover_no_links(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis @@ -2672,26 +2695,26 @@ fn foo() -> impl Foo {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2706,39 +2729,39 @@ fn foo() -> impl Foo {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..15, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..25, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 16..25, + focus_range: 23..24, + name: "S", + kind: Struct, + description: "struct S", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2873,26 +2896,26 @@ trait Foo {} fn foo(ar$0g: &impl Foo) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3020,39 +3043,39 @@ struct S {} fn foo(ar$0g: &impl Foo) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..15, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..27, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 16..27, + focus_range: 23..24, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3070,39 +3093,39 @@ fn foo() -> B {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 42..55, - focus_range: 49..50, - name: "B", - kind: Struct, - description: "struct B {}", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::B", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 42..55, + focus_range: 49..50, + name: "B", + kind: Struct, + description: "struct B {}", }, - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3114,26 +3137,26 @@ trait Foo {} fn foo(ar$0g: &dyn Foo) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3146,39 +3169,39 @@ struct S {} fn foo(ar$0g: &dyn Foo) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..15, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..27, - focus_range: 23..24, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 16..27, + focus_range: 23..24, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3275,26 +3298,26 @@ fn test() -> impl Foo { S {} } fn main() { let s$0t = test().get(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..62, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..62, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3340,26 +3363,26 @@ trait Foo {} fn foo(t: T$0){} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -5434,13 +5457,62 @@ fn hover_feature() { The tracking issue for this feature is: None. - Intrinsics are never intended to be stable directly, but intrinsics are often + Intrinsics are rarely intended to be stable directly, but are usually exported in some sort of stable manner. Prefer using the stable interfaces to the intrinsic directly when you can. ------------------------ + ## Intrinsics with fallback logic + + Many intrinsics can be written in pure rust, albeit inefficiently or without supporting + some features that only exist on some backends. Backends can simply not implement those + intrinsics without causing any code miscompilations or failures to compile. + All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`) + by the codegen backend, but not the MIR inliner. + + ```rust + #![feature(rustc_attrs, effects)] + #![allow(internal_features)] + + #[rustc_intrinsic] + const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + ``` + + Since these are just regular functions, it is perfectly ok to create the intrinsic twice: + + ```rust + #![feature(rustc_attrs, effects)] + #![allow(internal_features)] + + #[rustc_intrinsic] + const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + + mod foo { + #[rustc_intrinsic] + const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { + panic!("noisy const dealloc") + } + } + + ``` + + The behaviour on backends that override the intrinsic is exactly the same. On other + backends, the intrinsic behaviour depends on which implementation is called, just like + with any regular function. + + ## Intrinsics lowered to MIR instructions + + Various intrinsics have native MIR operations that they correspond to. Instead of requiring + backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass + will convert the calls to the MIR operation. Backends do not need to know about these intrinsics + at all. + + ## Intrinsics without fallback logic + + These must be implemented by all backends. + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and @@ -5459,7 +5531,8 @@ fn hover_feature() { } ``` - As with any other FFI functions, these are always `unsafe` to call. + As with any other FFI functions, these are by default always `unsafe` to call. + You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. "#]], ) @@ -6277,6 +6350,151 @@ impl T for () { ); } +#[test] +fn hover_trait_show_assoc_items() { + check_assoc_count( + 0, + r#" +trait T {} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T {} + ``` + "#]], + ); + + check_assoc_count( + 1, + r#" +trait T {} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T {} + ``` + "#]], + ); + + check_assoc_count( + 0, + r#" +trait T { + fn func() {} + const FLAG: i32 = 34; + type Bar; +} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T { /* … */ } + ``` + "#]], + ); + + check_assoc_count( + 2, + r#" +trait T { + fn func() {} + const FLAG: i32 = 34; + type Bar; +} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T { + fn func(); + const FLAG: i32; + /* … */ + } + ``` + "#]], + ); + + check_assoc_count( + 3, + r#" +trait T { + fn func() {} + const FLAG: i32 = 34; + type Bar; +} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T { + fn func(); + const FLAG: i32; + type Bar; + } + ``` + "#]], + ); + + check_assoc_count( + 4, + r#" +trait T { + fn func() {} + const FLAG: i32 = 34; + type Bar; +} +impl T$0 for () {} +"#, + expect![[r#" + *T* + + ```rust + test + ``` + + ```rust + trait T { + fn func(); + const FLAG: i32; + type Bar; + } + ``` + "#]], + ); +} + #[test] fn hover_ranged_macro_call() { check_hover_range( @@ -6366,8 +6584,8 @@ fn main() { $0V; } ```rust pub const V: i8 = { - let e = 123; - f(e) + let e = 123; + f(e) } ``` "#]], @@ -6393,7 +6611,7 @@ fn main() { $0V; } ```rust pub static V: i8 = { - let e = 123; + let e = 123; } ``` "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index a076c7ca9fa43..59a7df14fd53e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -50,6 +50,7 @@ mod static_index; mod status; mod syntax_highlighting; mod syntax_tree; +mod test_explorer; mod typing; mod view_crate_graph; mod view_hir; @@ -61,7 +62,7 @@ use std::ffi::OsStr; use cfg::CfgOptions; use fetch_crates::CrateInfo; -use hir::Change; +use hir::ChangeWithProcMacros; use ide_db::{ base_db::{ salsa::{self, ParallelDatabase}, @@ -108,6 +109,7 @@ pub use crate::{ tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, HighlightConfig, HlRange, }, + test_explorer::{TestItem, TestItemKind}, }; pub use hir::Semantics; pub use ide_assists::{ @@ -184,7 +186,7 @@ impl AnalysisHost { /// Applies changes to the current state of the world. If there are /// outstanding snapshots, they will be canceled. - pub fn apply_change(&mut self, change: Change) { + pub fn apply_change(&mut self, change: ChangeWithProcMacros) { self.db.apply_change(change); } @@ -239,7 +241,7 @@ impl Analysis { file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned())); let source_root = SourceRoot::new_local(file_set); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.set_roots(vec![source_root]); let mut crate_graph = CrateGraph::default(); // FIXME: cfg options @@ -340,6 +342,18 @@ impl Analysis { self.with_db(|db| view_item_tree::view_item_tree(db, file_id)) } + pub fn discover_test_roots(&self) -> Cancellable> { + self.with_db(test_explorer::discover_test_roots) + } + + pub fn discover_tests_in_crate_by_test_id(&self, crate_id: &str) -> Cancellable> { + self.with_db(|db| test_explorer::discover_tests_in_crate_by_test_id(db, crate_id)) + } + + pub fn discover_tests_in_crate(&self, crate_id: CrateId) -> Cancellable> { + self.with_db(|db| test_explorer::discover_tests_in_crate(db, crate_id)) + } + /// Renders the crate graph to GraphViz "dot" syntax. pub fn view_crate_graph(&self, full: bool) -> Cancellable> { self.with_db(|db| view_crate_graph::view_crate_graph(db, full)) diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs index f67aea2d5b9c1..ce7a6779e27c2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs +++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs @@ -48,7 +48,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec sema - .to_module_defs(position.file_id) + .file_to_module_defs(position.file_id) .flat_map(|module| NavigationTarget::from_module_to_decl(db, module)) .collect(), } diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index f78153df38bd6..8c2ae327c7fc0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -156,7 +156,7 @@ pub(crate) fn will_rename_file( new_name_stem: &str, ) -> Option { let sema = Semantics::new(db); - let module = sema.to_module_def(file_id)?; + let module = sema.file_to_module_def(file_id)?; let def = Definition::Module(module); let mut change = if is_raw_identifier(new_name_stem) { def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()? diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index ae107a96040dc..5fe46444ff41c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -178,7 +178,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { } }); - sema.to_module_defs(file_id) + sema.file_to_module_defs(file_id) .map(|it| runnable_mod_outline_definition(&sema, it)) .for_each(|it| add_opt(it, None)); diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 2929a7522e591..fe063081f7999 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -166,6 +166,7 @@ impl StaticIndex<'_> { documentation: true, keywords: true, format: crate::HoverDocFormat::Markdown, + max_trait_assoc_items_count: None, }; let tokens = tokens.filter(|token| { matches!( diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index dfcbaf54d4f92..d2bd3bab14e48 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -223,7 +223,7 @@ fn traverse( krate: hir::Crate, range_to_highlight: TextRange, ) { - let is_unlinked = sema.to_module_def(file_id).is_none(); + let is_unlinked = sema.file_to_module_def(file_id).is_none(); let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); enum AttrOrDerive { diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs new file mode 100644 index 0000000000000..2e741021ea8bb --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs @@ -0,0 +1,135 @@ +//! Discovers tests + +use hir::{Crate, Module, ModuleDef, Semantics}; +use ide_db::{ + base_db::{CrateGraph, CrateId, FileId, SourceDatabase}, + RootDatabase, +}; +use syntax::TextRange; + +use crate::{navigation_target::ToNav, runnables::runnable_fn, Runnable, TryToNav}; + +#[derive(Debug)] +pub enum TestItemKind { + Crate, + Module, + Function, +} + +#[derive(Debug)] +pub struct TestItem { + pub id: String, + pub kind: TestItemKind, + pub label: String, + pub parent: Option, + pub file: Option, + pub text_range: Option, + pub runnable: Option, +} + +pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec { + let crate_graph = db.crate_graph(); + crate_graph + .iter() + .filter(|&id| crate_graph[id].origin.is_local()) + .filter_map(|id| Some(crate_graph[id].display_name.as_ref()?.to_string())) + .map(|id| TestItem { + kind: TestItemKind::Crate, + label: id.clone(), + id, + parent: None, + file: None, + text_range: None, + runnable: None, + }) + .collect() +} + +fn find_crate_by_id(crate_graph: &CrateGraph, crate_id: &str) -> Option { + // here, we use display_name as the crate id. This is not super ideal, but it works since we + // only show tests for the local crates. + crate_graph.iter().find(|&id| { + crate_graph[id].origin.is_local() + && crate_graph[id].display_name.as_ref().is_some_and(|x| x.to_string() == crate_id) + }) +} + +fn discover_tests_in_module(db: &RootDatabase, module: Module, prefix_id: String) -> Vec { + let sema = Semantics::new(db); + + let mut r = vec![]; + for c in module.children(db) { + let module_name = + c.name(db).as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]").to_owned(); + let module_id = format!("{prefix_id}::{module_name}"); + let module_children = discover_tests_in_module(db, c, module_id.clone()); + if !module_children.is_empty() { + let nav = c.to_nav(db).call_site; + r.push(TestItem { + id: module_id, + kind: TestItemKind::Module, + label: module_name, + parent: Some(prefix_id.clone()), + file: Some(nav.file_id), + text_range: Some(nav.focus_or_full_range()), + runnable: None, + }); + r.extend(module_children); + } + } + for def in module.declarations(db) { + let ModuleDef::Function(f) = def else { + continue; + }; + if !f.is_test(db) { + continue; + } + let nav = f.try_to_nav(db).map(|r| r.call_site); + let fn_name = f.name(db).as_str().unwrap_or("[function without name]").to_owned(); + r.push(TestItem { + id: format!("{prefix_id}::{fn_name}"), + kind: TestItemKind::Function, + label: fn_name, + parent: Some(prefix_id.clone()), + file: nav.as_ref().map(|n| n.file_id), + text_range: nav.as_ref().map(|n| n.focus_or_full_range()), + runnable: runnable_fn(&sema, f), + }); + } + r +} + +pub(crate) fn discover_tests_in_crate_by_test_id( + db: &RootDatabase, + crate_test_id: &str, +) -> Vec { + let crate_graph = db.crate_graph(); + let Some(crate_id) = find_crate_by_id(&crate_graph, crate_test_id) else { + return vec![]; + }; + discover_tests_in_crate(db, crate_id) +} + +pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> Vec { + let crate_graph = db.crate_graph(); + if !crate_graph[crate_id].origin.is_local() { + return vec![]; + } + let Some(crate_test_id) = &crate_graph[crate_id].display_name else { + return vec![]; + }; + let crate_test_id = crate_test_id.to_string(); + let crate_id: Crate = crate_id.into(); + let module = crate_id.root_module(); + let mut r = vec![TestItem { + id: crate_test_id.clone(), + kind: TestItemKind::Crate, + label: crate_test_id.clone(), + parent: None, + file: None, + text_range: None, + runnable: None, + }]; + r.extend(discover_tests_in_module(db, module, crate_test_id)); + r +} diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 2b5f515c3ad5b..a1c089520da5b 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -10,8 +10,8 @@ use hir_expand::proc_macro::{ ProcMacros, }; use ide_db::{ - base_db::{CrateGraph, Env, SourceRoot}, - prime_caches, Change, FxHashMap, RootDatabase, + base_db::{CrateGraph, Env, SourceRoot, SourceRootId}, + prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase, }; use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; @@ -231,7 +231,7 @@ impl ProjectFolders { res.load.push(entry); if root.is_local { - local_filesets.push(fsc.len()); + local_filesets.push(fsc.len() as u64); } fsc.add_file_set(file_set_roots) } @@ -246,7 +246,7 @@ impl ProjectFolders { #[derive(Default, Debug)] pub struct SourceRootConfig { pub fsc: FileSetConfig, - pub local_filesets: Vec, + pub local_filesets: Vec, } impl SourceRootConfig { @@ -256,7 +256,7 @@ impl SourceRootConfig { .into_iter() .enumerate() .map(|(idx, file_set)| { - let is_local = self.local_filesets.contains(&idx); + let is_local = self.local_filesets.contains(&(idx as u64)); if is_local { SourceRoot::new_local(file_set) } else { @@ -265,6 +265,31 @@ impl SourceRootConfig { }) .collect() } + + /// Maps local source roots to their parent source roots by bytewise comparing of root paths . + /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot`. + pub fn source_root_parent_map(&self) -> FxHashMap { + let roots = self.fsc.roots(); + let mut map = FxHashMap::::default(); + roots + .iter() + .enumerate() + .filter(|(_, (_, id))| self.local_filesets.contains(id)) + .filter_map(|(idx, (root, root_id))| { + // We are interested in parents if they are also local source roots. + // So instead of a non-local parent we may take a local ancestor as a parent to a node. + roots.iter().take(idx).find_map(|(root2, root2_id)| { + if self.local_filesets.contains(root2_id) && root.starts_with(root2) { + return Some((root_id, root2_id)); + } + None + }) + }) + .for_each(|(child, parent)| { + map.insert(SourceRootId(*child as u32), SourceRootId(*parent as u32)); + }); + map + } } /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` @@ -314,7 +339,7 @@ fn load_crate_graph( let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); let mut db = RootDatabase::new(lru_cap); - let mut analysis_change = Change::new(); + let mut analysis_change = ChangeWithProcMacros::new(); db.enable_proc_attr_macros(); @@ -397,6 +422,11 @@ mod tests { use super::*; + use ide_db::base_db::SourceRootId; + use vfs::{file_set::FileSetConfigBuilder, VfsPath}; + + use crate::SourceRootConfig; + #[test] fn test_loading_rust_analyzer() { let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); @@ -413,4 +443,124 @@ mod tests { // RA has quite a few crates, but the exact count doesn't matter assert!(n_crates > 20); } + + #[test] + fn unrelated_sources() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![]) + } + + #[test] + fn unrelated_source_sharing_dirname() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![]) + } + + #[test] + fn basic_child_parent() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc/def".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0))]) + } + + #[test] + fn basic_child_parent_with_unrelated_parents_sib() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1))]) + } + + #[test] + fn deep_sources_with_parent_missing() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/ghi".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![]) + } + + #[test] + fn ancestor_can_be_parent() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] }; + let vc = src.source_root_parent_map().into_iter().collect::>(); + + assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1))]) + } + + #[test] + fn ancestor_can_be_parent_2() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/klm".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2, 3] }; + let mut vc = src.source_root_parent_map().into_iter().collect::>(); + vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0)); + + assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1)), (SourceRootId(3), SourceRootId(1))]) + } + + #[test] + fn non_locals_are_skipped() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 3] }; + let mut vc = src.source_root_parent_map().into_iter().collect::>(); + vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0)); + + assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),]) + } + + #[test] + fn child_binds_ancestor_if_parent_nonlocal() { + let mut builder = FileSetConfigBuilder::default(); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm".to_owned())]); + builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm/jkl".to_owned())]); + let fsc = builder.build(); + let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 3] }; + let mut vc = src.source_root_parent_map().into_iter().collect::>(); + vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0)); + + assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),]) + } } diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml index e74b340126c0a..1f84e3f3af3f0 100644 --- a/src/tools/rust-analyzer/crates/parser/Cargo.toml +++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml @@ -15,6 +15,7 @@ doctest = false drop_bomb = "0.1.5" ra-ap-rustc_lexer.workspace = true limit.workspace = true +tracing = { workspace = true, optional = true } [dev-dependencies] expect-test = "1.4.0" @@ -23,6 +24,7 @@ stdx.workspace = true sourcegen.workspace = true [features] +default = ["tracing"] in-rust-tree = [] [lints] diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index 34715628f1803..4e5837312fe28 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -244,7 +244,7 @@ impl BlockLike { } } -const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]); +const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub]]); fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { if !p.at(T![pub]) { @@ -416,14 +416,12 @@ fn delimited( if !parser(p) { break; } - if !p.at(delim) { + if !p.eat(delim) { if p.at_ts(first_set) { p.error(format!("expected {:?}", delim)); } else { break; } - } else { - p.bump(delim); } } p.expect(ket); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 6b660180f8238..861fcedda2aa2 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -211,9 +211,8 @@ fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) { T![>] if p.at(T![>>]) => (9, T![>>], Left), T![>] if p.at(T![>=]) => (5, T![>=], Left), T![>] => (5, T![>], Left), - T![=] if p.at(T![=>]) => NOT_AN_OP, T![=] if p.at(T![==]) => (5, T![==], Left), - T![=] => (1, T![=], Right), + T![=] if !p.at(T![=>]) => (1, T![=], Right), T![<] if p.at(T![<=]) => (5, T![<=], Left), T![<] if p.at(T![<<=]) => (1, T![<<=], Right), T![<] if p.at(T![<<]) => (9, T![<<], Left), @@ -247,7 +246,7 @@ fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) { fn expr_bp( p: &mut Parser<'_>, m: Option, - mut r: Restrictions, + r: Restrictions, bp: u8, ) -> Option<(CompletedMarker, BlockLike)> { let m = m.unwrap_or_else(|| { @@ -295,10 +294,6 @@ fn expr_bp( let m = lhs.precede(p); p.bump(op); - // test binop_resets_statementness - // fn f() { v = {1}&2; } - r = Restrictions { prefer_stmt: false, ..r }; - if is_range { // test postfix_range // fn foo() { @@ -319,6 +314,9 @@ fn expr_bp( Associativity::Left => op_bp + 1, Associativity::Right => op_bp, }; + + // test binop_resets_statementness + // fn f() { v = {1}&2; } expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp); lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); } @@ -345,7 +343,7 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik T![&] => { m = p.start(); p.bump(T![&]); - if p.at_contextual_kw(T![raw]) && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) { + if p.at_contextual_kw(T![raw]) && [T![mut], T![const]].contains(&p.nth(1)) { p.bump_remap(T![raw]); p.bump_any(); } else { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 48600641ad05b..72848a1f2b79f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -147,7 +147,7 @@ pub(super) fn atom_expr( T![async] if la == T![move] && p.nth(2) == T!['{'] => { let m = p.start(); p.bump(T![async]); - p.eat(T![move]); + p.bump(T![move]); stmt_list(p); m.complete(p, BLOCK_EXPR) } @@ -390,8 +390,7 @@ fn if_expr(p: &mut Parser<'_>) -> CompletedMarker { p.bump(T![if]); expr_no_struct(p); block_expr(p); - if p.at(T![else]) { - p.bump(T![else]); + if p.eat(T![else]) { if p.at(T![if]) { if_expr(p); } else { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 4498daf21a3d8..6c05abc023878 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -170,7 +170,7 @@ fn type_bound(p: &mut Parser<'_>) -> bool { _ => (), } if paths::is_use_path_start(p) { - types::path_type_(p, false); + types::path_type_bounds(p, false); } else { m.abandon(p); return false; diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 243a219525a8a..25c00ccf5f33c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -70,8 +70,7 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { // macro_rules! {}; // macro_rules! () // macro_rules! [] - let no_ident = p.at_contextual_kw(T![macro_rules]) && p.nth_at(1, BANG) && !p.nth_at(2, IDENT); - if paths::is_use_path_start(p) || no_ident { + if paths::is_use_path_start(p) { macro_call(p, m); return; } @@ -156,27 +155,19 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { // impl T for Foo { // default async fn foo() {} // } - T![async] => { - let mut maybe_fn = p.nth(2); - let is_unsafe = if matches!(maybe_fn, T![unsafe]) { - // test default_async_unsafe_fn - // impl T for Foo { - // default async unsafe fn foo() {} - // } - maybe_fn = p.nth(3); - true - } else { - false - }; - - if matches!(maybe_fn, T![fn]) { - p.bump_remap(T![default]); - p.bump(T![async]); - if is_unsafe { - p.bump(T![unsafe]); - } - has_mods = true; - } + T![async] + if p.nth_at(2, T![fn]) || (p.nth_at(2, T![unsafe]) && p.nth_at(3, T![fn])) => + { + p.bump_remap(T![default]); + p.bump(T![async]); + + // test default_async_unsafe_fn + // impl T for Foo { + // default async unsafe fn foo() {} + // } + p.eat(T![unsafe]); + + has_mods = true; } _ => (), } @@ -419,11 +410,9 @@ fn fn_(p: &mut Parser<'_>, m: Marker) { // fn foo() where T: Copy {} generic_params::opt_where_clause(p); - if p.at(T![;]) { - // test fn_decl - // trait T { fn foo(); } - p.bump(T![;]); - } else { + // test fn_decl + // trait T { fn foo(); } + if !p.eat(T![;]) { expressions::block_expr(p); } m.complete(p, FN); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs index a8a1ccb15e6c2..c215185d63283 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs @@ -119,11 +119,11 @@ fn not_a_qualified_path(p: &Parser<'_>) -> bool { // we disambiguate it in favor of generics (`impl ::absolute::Path { ... }`) // because this is what almost always expected in practice, qualified paths in impls // (`impl ::AssocTy { ... }`) aren't even allowed by type checker at the moment. - if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == T![const] { + if [T![#], T![>], T![const]].contains(&p.nth(1)) { return true; } - (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT) - && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=]) + ([LIFETIME_IDENT, IDENT].contains(&p.nth(1))) + && ([T![>], T![,], T![:], T![=]].contains(&p.nth(2))) } // test_err impl_type diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs index 846da28cb0164..c535267c1656f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs @@ -76,19 +76,16 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) { m.abandon(p); if p.eat(T![,]) { continue; - } else { - break; } + break; } param(p, m, flavor); - if !p.at(T![,]) { + if !p.eat(T![,]) { if p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) { p.error("expected `,`"); } else { break; } - } else { - p.bump(T![,]); } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index 5036742337921..eff6b66404971 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -255,9 +255,7 @@ fn is_literal_pat_start(p: &Parser<'_>) -> bool { fn literal_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(is_literal_pat_start(p)); let m = p.start(); - if p.at(T![-]) { - p.bump(T![-]); - } + p.eat(T![-]); expressions::literal(p); m.complete(p, LITERAL_PAT) } @@ -468,14 +466,12 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { while !p.at(EOF) && !p.at(ket) { pattern_top(p); - if !p.at(T![,]) { + if !p.eat(T![,]) { if p.at_ts(PAT_TOP_FIRST) { p.error(format!("expected {:?}, got {:?}", T![,], p.current())); } else { break; } - } else { - p.bump(T![,]); } } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 96a6cdeaafffc..18ec570cd5697 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -48,7 +48,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { T![impl] => impl_trait_type(p), T![dyn] => dyn_trait_type(p), // Some path types are not allowed to have bounds (no plus) - T![<] => path_type_(p, allow_bounds), + T![<] => path_type_bounds(p, allow_bounds), _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), _ => { @@ -294,7 +294,7 @@ fn bare_dyn_trait_type(p: &mut Parser<'_>) { // type C = self::Foo; // type D = super::Foo; pub(super) fn path_type(p: &mut Parser<'_>) { - path_type_(p, true); + path_type_bounds(p, true); } // test macro_call_type @@ -323,7 +323,7 @@ fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { } } -pub(super) fn path_type_(p: &mut Parser<'_>, allow_bounds: bool) { +pub(super) fn path_type_bounds(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); let m = p.start(); paths::type_path(p); diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 2da9184693d97..48e4c8a6225c4 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -31,6 +31,7 @@ struct LexError { impl<'a> LexedStr<'a> { pub fn new(text: &'a str) -> LexedStr<'a> { + let _p = tracing::span!(tracing::Level::INFO, "LexedStr::new").entered(); let mut conv = Converter::new(text); if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { conv.res.push(SHEBANG, conv.offset); diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index 3ca285e787e81..86c771c00085c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -87,6 +87,7 @@ pub enum TopEntryPoint { impl TopEntryPoint { pub fn parse(&self, input: &Input) -> Output { + let _p = tracing::span!(tracing::Level::INFO, "TopEntryPoint::parse", ?self).entered(); let entry_point: fn(&'_ mut parser::Parser<'_>) = match self { TopEntryPoint::SourceFile => grammar::entry::top::source_file, TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts, diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index ef413c63754f6..051461243afcd 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -250,12 +250,9 @@ impl<'t> Parser<'t> { /// Create an error node and consume the next token. pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { - match self.current() { - T!['{'] | T!['}'] => { - self.error(message); - return; - } - _ => (), + if matches!(self.current(), T!['{'] | T!['}']) { + self.error(message); + return; } if self.at_ts(recovery) { diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs index 57005a6834c90..cc2b63d1e66a9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs +++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs @@ -26,6 +26,7 @@ pub enum StrStep<'a> { impl LexedStr<'_> { pub fn to_input(&self) -> crate::Input { + let _p = tracing::span!(tracing::Level::INFO, "LexedStr::to_input").entered(); let mut res = crate::Input::default(); let mut was_joint = false; for i in 0..self.len() { @@ -189,7 +190,7 @@ impl Builder<'_, '_> { fn do_float_split(&mut self, has_pseudo_dot: bool) { let text = &self.lexed.range_text(self.pos..self.pos + 1); - self.pos += 1; + match text.split_once('.') { Some((left, right)) => { assert!(!left.is_empty()); @@ -215,8 +216,22 @@ impl Builder<'_, '_> { self.state = State::PendingExit; } } - None => unreachable!(), + None => { + // illegal float literal which doesn't have dot in form (like 1e0) + // we should emit an error node here + (self.sink)(StrStep::Error { msg: "illegal float literal", pos: self.pos }); + (self.sink)(StrStep::Enter { kind: SyntaxKind::ERROR }); + (self.sink)(StrStep::Token { kind: SyntaxKind::FLOAT_NUMBER, text }); + (self.sink)(StrStep::Exit); + + // move up + (self.sink)(StrStep::Exit); + + self.state = if has_pseudo_dot { State::Normal } else { State::PendingExit }; + } } + + self.pos += 1; } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rast new file mode 100644 index 0000000000000..d6ad7334839d3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rast @@ -0,0 +1,88 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "S" + TUPLE_FIELD_LIST + L_PAREN "(" + TUPLE_FIELD + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + COMMA "," + WHITESPACE " " + TUPLE_FIELD + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "f" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "s" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + ARG_LIST + L_PAREN "(" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "s" + DOT "." + ERROR + FLOAT_NUMBER "1e0" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 42: illegal float literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rs new file mode 100644 index 0000000000000..648ef5e043004 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0054_float_split_scientific_notation.rs @@ -0,0 +1,5 @@ +struct S(i32, i32); +fn f() { + let s = S(1, 2); + let a = s.1e0; +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index cf01b94c0a2cb..978ad155609d5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -12,13 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -object = { version = "0.32.0", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", -] } +object.workspace = true serde.workspace = true serde_json = { workspace = true, features = ["unbounded_depth"] } tracing.workspace = true @@ -32,7 +26,6 @@ indexmap = "2.1.0" paths.workspace = true tt.workspace = true stdx.workspace = true -profile.workspace = true text-size.workspace = true span.workspace = true # Ideally this crate would not depend on salsa things, but we need span information here which wraps diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index bd7a31654584f..f8db1c6a30b49 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -12,13 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -object = { version = "0.32.0", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", -] } +object.workspace = true libloading = "0.8.0" memmap2 = "0.5.4" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml index 7977afb1cbd23..7c6a1ba46b5fa 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml @@ -11,6 +11,3 @@ doctest = false [build-dependencies] cargo_metadata = "0.18.1" - -# local deps -toolchain.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs index ff62980e4ffe3..c76c201d69e87 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs @@ -18,12 +18,12 @@ use cargo_metadata::Message; fn main() { println!("cargo:rerun-if-changed=imp"); + let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some() - || String::from_utf8( - Command::new(toolchain::cargo()).arg("--version").output().unwrap().stdout, - ) - .unwrap() - .contains("nightly"); + || String::from_utf8(Command::new(&cargo).arg("--version").output().unwrap().stdout) + .unwrap() + .contains("nightly"); let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = Path::new(&out_dir); @@ -66,7 +66,7 @@ fn main() { let target_dir = out_dir.join("target"); - let mut cmd = Command::new(toolchain::cargo()); + let mut cmd = Command::new(&cargo); cmd.current_dir(&staging_dir) .args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"]) // Explicit override the target directory to avoid using the same one which the parent @@ -96,7 +96,7 @@ fn main() { let repr = format!("{name} {version}"); // New Package Id Spec since rust-lang/cargo#13311 let pkgid = String::from_utf8( - Command::new(toolchain::cargo()) + Command::new(cargo) .current_dir(&staging_dir) .args(["pkgid", name]) .output() diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs index 3639981560635..a3fdb72a6d1d2 100644 --- a/src/tools/rust-analyzer/crates/profile/src/lib.rs +++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs @@ -23,29 +23,6 @@ pub use countme::Count; thread_local!(static IN_SCOPE: RefCell = const { RefCell::new(false) }); -/// Allows to check if the current code is within some dynamic scope, can be -/// useful during debugging to figure out why a function is called. -pub struct Scope { - prev: bool, -} - -impl Scope { - #[must_use] - pub fn enter() -> Scope { - let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); - Scope { prev } - } - pub fn is_active() -> bool { - IN_SCOPE.with(|slot| *slot.borrow()) - } -} - -impl Drop for Scope { - fn drop(&mut self) { - IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev); - } -} - /// A wrapper around google_cpu_profiler. /// /// Usage: diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml index 3552ed191628e..924a4a89e216a 100644 --- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml +++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml @@ -27,7 +27,6 @@ itertools.workspace = true base-db.workspace = true cfg.workspace = true paths.workspace = true -profile.workspace = true stdx.workspace = true toolchain.workspace = true @@ -35,4 +34,4 @@ toolchain.workspace = true expect-test = "1.4.0" [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index 27a8db40a9989..709fc03717471 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -71,8 +71,7 @@ impl WorkspaceBuildScripts { cmd } _ => { - let mut cmd = Command::new(Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); @@ -430,8 +429,7 @@ impl WorkspaceBuildScripts { } let res = (|| { let target_libdir = (|| { - let mut cargo_config = Command::new(Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); + let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); cargo_config.envs(extra_env); cargo_config .current_dir(current_dir) @@ -440,7 +438,7 @@ impl WorkspaceBuildScripts { if let Ok(it) = utf8_stdout(cargo_config) { return Ok(it); } - let mut cmd = Sysroot::rustc(sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Rustc); cmd.envs(extra_env); cmd.args(["--print", "target-libdir"]); utf8_stdout(cmd) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 609b1f67b57db..53b41ea1e87b6 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -1,8 +1,8 @@ //! See [`CargoWorkspace`]. +use std::ops; use std::path::PathBuf; use std::str::from_utf8; -use std::{ops, process::Command}; use anyhow::Context; use base_db::Edition; @@ -243,8 +243,11 @@ impl CargoWorkspace { ) -> anyhow::Result { let targets = find_list_of_build_targets(config, cargo_toml, sysroot); + let cargo = Sysroot::tool(sysroot, Tool::Cargo); let mut meta = MetadataCommand::new(); - meta.cargo_path(Tool::Cargo.path()); + meta.cargo_path(cargo.get_program()); + cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default())); + config.extra_env.iter().for_each(|(var, val)| _ = meta.env(var, val)); meta.manifest_path(cargo_toml.to_path_buf()); match &config.features { CargoFeatures::All => { @@ -291,10 +294,7 @@ impl CargoWorkspace { progress("metadata".to_owned()); (|| -> Result { - let mut command = meta.cargo_command(); - Sysroot::set_rustup_toolchain_env(&mut command, sysroot); - command.envs(&config.extra_env); - let output = command.output()?; + let output = meta.cargo_command().output()?; if !output.status.success() { return Err(cargo_metadata::Error::CargoMetadata { stderr: String::from_utf8(output.stderr)?, @@ -501,7 +501,7 @@ fn rustc_discover_host_triple( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> Option { - let mut rustc = Sysroot::rustc(sysroot); + let mut rustc = Sysroot::tool(sysroot, Tool::Rustc); rustc.envs(extra_env); rustc.current_dir(cargo_toml.parent()).arg("-vV"); tracing::debug!("Discovering host platform by {:?}", rustc); @@ -529,8 +529,7 @@ fn cargo_config_build_target( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> Vec { - let mut cargo_config = Command::new(Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); + let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs index 001296fb0002f..501b1fdc8c5b5 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs @@ -1,9 +1,8 @@ //! Runs `rustc --print cfg` to get built-in cfg flags. -use std::process::Command; - use anyhow::Context; use rustc_hash::FxHashMap; +use toolchain::Tool; use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot}; @@ -69,8 +68,8 @@ fn get_rust_cfgs( ) -> anyhow::Result { let sysroot = match config { RustcCfgConfig::Cargo(sysroot, cargo_toml) => { - let mut cmd = Command::new(toolchain::Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); + cmd.envs(extra_env); cmd.current_dir(cargo_toml.parent()) .args(["rustc", "-Z", "unstable-options", "--print", "cfg"]) @@ -90,7 +89,7 @@ fn get_rust_cfgs( RustcCfgConfig::Rustc(sysroot) => sysroot, }; - let mut cmd = Sysroot::rustc(sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Rustc); cmd.envs(extra_env); cmd.args(["--print", "cfg", "-O"]); if let Some(target) = target { diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index ea24393ed8a29..3127bae8b0c9e 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; -use toolchain::probe_for_binary; +use toolchain::{probe_for_binary, Tool}; use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; @@ -193,23 +193,26 @@ impl Sysroot { Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata)) } - pub fn set_rustup_toolchain_env(cmd: &mut Command, sysroot: Option<&Self>) { - if let Some(sysroot) = sysroot { - cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(&sysroot.root)); - } - } - - /// Returns a `Command` that is configured to run `rustc` from the sysroot if it exists, - /// otherwise returns what [toolchain::Tool::Rustc] returns. - pub fn rustc(sysroot: Option<&Self>) -> Command { - let mut cmd = Command::new(match sysroot { + /// Returns a command to run a tool preferring the cargo proxies if the sysroot exists. + pub fn tool(sysroot: Option<&Self>, tool: Tool) -> Command { + match sysroot { Some(sysroot) => { - toolchain::Tool::Rustc.path_in_or_discover(sysroot.root.join("bin").as_ref()) + // special case rustc, we can look that up directly in the sysroot's bin folder + // as it should never invoke another cargo binary + if let Tool::Rustc = tool { + if let Some(path) = + probe_for_binary(sysroot.root.join("bin").join(Tool::Rustc.name()).into()) + { + return Command::new(path); + } + } + + let mut cmd = Command::new(tool.prefer_proxy()); + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(&sysroot.root)); + cmd } - None => toolchain::Tool::Rustc.path(), - }); - Self::set_rustup_toolchain_env(&mut cmd, sysroot); - cmd + _ => Command::new(tool.path()), + } } pub fn discover_proc_macro_srv(&self) -> anyhow::Result { @@ -411,7 +414,7 @@ fn discover_sysroot_dir( current_dir: &AbsPath, extra_env: &FxHashMap, ) -> Result { - let mut rustc = Command::new(toolchain::rustc()); + let mut rustc = Command::new(Tool::Rustc.path()); rustc.envs(extra_env); rustc.current_dir(current_dir).args(["--print", "sysroot"]); tracing::debug!("Discovering sysroot by {:?}", rustc); @@ -443,7 +446,7 @@ fn discover_sysroot_src_dir_or_add_component( ) -> Result { discover_sysroot_src_dir(sysroot_path) .or_else(|| { - let mut rustup = Command::new(toolchain::rustup()); + let mut rustup = Command::new(Tool::Rustup.prefer_proxy()); rustup.envs(extra_env); rustup.current_dir(current_dir).args(["component", "add", "rust-src"]); tracing::info!("adding rust-src component by {:?}", rustup); diff --git a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs index df77541762d9e..4e810a0232ea9 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs @@ -1,7 +1,7 @@ //! Runs `rustc --print target-spec-json` to get the target_data_layout. -use std::process::Command; use rustc_hash::FxHashMap; +use toolchain::Tool; use crate::{utf8_stdout, ManifestPath, Sysroot}; @@ -28,8 +28,7 @@ pub fn get( }; let sysroot = match config { RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => { - let mut cmd = Command::new(toolchain::Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Cargo); cmd.envs(extra_env); cmd.current_dir(cargo_toml.parent()) .args([ @@ -57,7 +56,7 @@ pub fn get( RustcDataLayoutConfig::Rustc(sysroot) => sysroot, }; - let mut cmd = Sysroot::rustc(sysroot); + let mut cmd = Sysroot::tool(sysroot, Tool::Rustc); cmd.envs(extra_env) .args(["-Z", "unstable-options", "--print", "target-spec-json"]) .env("RUSTC_BOOTSTRAP", "1"); diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index adf15d45fc626..1a138b17bad41 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -2,7 +2,7 @@ //! metadata` or `rust-project.json`) into representation stored in the salsa //! database -- `CrateGraph`. -use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, sync}; +use std::{collections::VecDeque, fmt, fs, iter, str::FromStr, sync}; use anyhow::{format_err, Context}; use base_db::{ @@ -172,11 +172,13 @@ impl fmt::Debug for ProjectWorkspace { fn get_toolchain_version( current_dir: &AbsPath, - mut cmd: Command, + sysroot: Option<&Sysroot>, + tool: Tool, extra_env: &FxHashMap, prefix: &str, ) -> Result, anyhow::Error> { let cargo_version = utf8_stdout({ + let mut cmd = Sysroot::tool(sysroot, tool); cmd.envs(extra_env); cmd.arg("--version").current_dir(current_dir); cmd @@ -297,11 +299,8 @@ impl ProjectWorkspace { let toolchain = get_toolchain_version( cargo_toml.parent(), - { - let mut cmd = Command::new(toolchain::Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot_ref); - cmd - }, + sysroot_ref, + Tool::Cargo, &config.extra_env, "cargo ", )?; @@ -386,7 +385,8 @@ impl ProjectWorkspace { let data_layout_config = RustcDataLayoutConfig::Rustc(sysroot_ref); let toolchain = match get_toolchain_version( project_json.path(), - Sysroot::rustc(sysroot_ref), + sysroot_ref, + Tool::Rustc, extra_env, "rustc ", ) { @@ -433,18 +433,15 @@ impl ProjectWorkspace { }; let sysroot_ref = sysroot.as_ref().ok(); - let toolchain = match get_toolchain_version( - dir, - Sysroot::rustc(sysroot_ref), - &config.extra_env, - "rustc ", - ) { - Ok(it) => it, - Err(e) => { - tracing::error!("{e}"); - None - } - }; + let toolchain = + match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ") + { + Ok(it) => it, + Err(e) => { + tracing::error!("{e}"); + None + } + }; let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); let data_layout = target_data_layout::get( @@ -1573,8 +1570,7 @@ fn cargo_config_env( extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> FxHashMap { - let mut cargo_config = Command::new(Tool::Cargo.path()); - Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot); + let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index a212041e66b46..766606be7bea6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -85,7 +85,6 @@ force-always-assert = ["always-assert/force"] sysroot-abi = [] in-rust-tree = [ "sysroot-abi", - "ide/in-rust-tree", "syntax/in-rust-tree", "parser/in-rust-tree", "hir/in-rust-tree", diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 8762564a8f134..ef184032bfb09 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -371,7 +371,7 @@ impl flags::AnalysisStats { let parse = sema.parse(file_id); let file_txt = db.file_text(file_id); - let path = vfs.file_path(file_id).as_path().unwrap().to_owned(); + let path = vfs.file_path(file_id).as_path().unwrap(); for node in parse.syntax().descendants() { let expr = match syntax::ast::Expr::cast(node.clone()) { @@ -446,7 +446,7 @@ impl flags::AnalysisStats { edit.apply(&mut txt); if self.validate_term_search { - std::fs::write(&path, txt).unwrap(); + std::fs::write(path, txt).unwrap(); let res = ws.run_build_scripts(&cargo_config, &|_| ()).unwrap(); if let Some(err) = res.error() { @@ -495,7 +495,7 @@ impl flags::AnalysisStats { } // Revert file back to original state if self.validate_term_search { - std::fs::write(&path, file_txt.to_string()).unwrap(); + std::fs::write(path, file_txt.to_string()).unwrap(); } bar.inc(1); @@ -982,6 +982,7 @@ impl flags::AnalysisStats { }, prefer_no_std: false, prefer_prelude: true, + style_lints: false, }, ide::AssistResolveStrategy::All, file_id, @@ -1077,12 +1078,12 @@ fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: Pa format!("{path},{}:{},{}:{}", start.line + 1, start.col, end.line + 1, end.col) } -fn expr_syntax_range( +fn expr_syntax_range<'a>( db: &RootDatabase, - vfs: &Vfs, + vfs: &'a Vfs, sm: &BodySourceMap, expr_id: ExprId, -) -> Option<(VfsPath, LineCol, LineCol)> { +) -> Option<(&'a VfsPath, LineCol, LineCol)> { let src = sm.expr_syntax(expr_id); if let Ok(src) = src { let root = db.parse_or_expand(src.file_id); @@ -1098,12 +1099,12 @@ fn expr_syntax_range( None } } -fn pat_syntax_range( +fn pat_syntax_range<'a>( db: &RootDatabase, - vfs: &Vfs, + vfs: &'a Vfs, sm: &BodySourceMap, pat_id: PatId, -) -> Option<(VfsPath, LineCol, LineCol)> { +) -> Option<(&'a VfsPath, LineCol, LineCol)> { let src = sm.pat_syntax(pat_id); if let Ok(src) = src { let root = db.parse_or_expand(src.file_id); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index 31d2a67981f11..f3f5ec1ebde2f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -7,11 +7,7 @@ use ide::{ Analysis, AnalysisHost, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex, StaticIndexedFile, TokenId, TokenStaticData, }; -use ide_db::{ - base_db::salsa::{self, ParallelDatabase}, - line_index::WideEncoding, - LineIndexDatabase, -}; +use ide_db::{line_index::WideEncoding, LineIndexDatabase}; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use lsp_types::lsif; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; @@ -25,14 +21,6 @@ use crate::{ version::version, }; -/// Need to wrap Snapshot to provide `Clone` impl for `map_with` -struct Snap(DB); -impl Clone for Snap> { - fn clone(&self) -> Snap> { - Snap(self.0.snapshot()) - } -} - struct LsifManager<'a> { count: i32, token_map: FxHashMap, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 9276d241affd9..7ad87ab97fc65 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -5,7 +5,7 @@ use std::thread::Builder; use std::time::{Duration, Instant}; use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf}; -use hir::{Change, Crate}; +use hir::{ChangeWithProcMacros, Crate}; use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; use itertools::Either; use profile::StopWatch; @@ -122,7 +122,7 @@ impl Tester { FxHashMap::default() }; let text = read_to_string(&p).unwrap(); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); // Ignore unstable tests, since they move too fast and we do not intend to support all of them. let mut ignore_test = text.contains("#![feature"); // Ignore test with extern crates, as this infra don't support them yet. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 0da6101b350a8..9e81c8dd665f2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -311,6 +311,8 @@ config_data! { /// Map of prefixes to be substituted when parsing diagnostic file paths. /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. diagnostics_remapPrefix: FxHashMap = "{}", + /// Whether to run additional style lints. + diagnostics_styleLints_enable: bool = "false", /// List of warnings that should be displayed with hint severity. /// /// The warnings will be indicated by faded text or three dots in code @@ -375,6 +377,9 @@ config_data! { /// How to render the size information in a memory layout hover. hover_memoryLayout_size: Option = "\"both\"", + /// How many associated items of a trait to display when hovering a trait. + hover_show_traitAssocItems: Option = "null", + /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. imports_granularity_enforce: bool = "false", /// How imports should be grouped into use statements. @@ -518,7 +523,6 @@ config_data! { /// Exclude tests from find-all-references. references_excludeTests: bool = "false", - /// Command to be executed instead of 'cargo' for runnables. runnables_command: Option = "null", /// Additional arguments to be passed to cargo for runnables such as @@ -1142,6 +1146,10 @@ impl Config { self.experimental("colorDiagnosticOutput") } + pub fn test_explorer(&self) -> bool { + self.experimental("testExplorer") + } + pub fn publish_diagnostics(&self) -> bool { self.data.diagnostics_enable } @@ -1160,6 +1168,7 @@ impl Config { insert_use: self.insert_use_config(), prefer_no_std: self.data.imports_preferNoStd, prefer_prelude: self.data.imports_preferPrelude, + style_lints: self.data.diagnostics_styleLints_enable, } } @@ -1680,6 +1689,7 @@ impl Config { } }, keywords: self.data.hover_documentation_keywords_enable, + max_trait_assoc_items_count: self.data.hover_show_traitAssocItems, } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index b2d507491b177..0e560e54eda38 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -7,8 +7,8 @@ use std::{collections::hash_map::Entry, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; -use hir::Change; -use ide::{Analysis, AnalysisHost, Cancellable, FileId}; +use hir::ChangeWithProcMacros; +use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; use ide_db::base_db::{CrateId, ProcMacroPaths}; use load_cargo::SourceRootConfig; use lsp_types::{SemanticTokens, Url}; @@ -66,6 +66,8 @@ pub(crate) struct GlobalState { pub(crate) diagnostics: DiagnosticCollection, pub(crate) mem_docs: MemDocs, pub(crate) source_root_config: SourceRootConfig, + /// A mapping that maps a local source root's `SourceRootId` to it parent's `SourceRootId`, if it has one. + pub(crate) local_roots_parent_map: FxHashMap, pub(crate) semantic_tokens_cache: Arc>>, // status @@ -83,6 +85,9 @@ pub(crate) struct GlobalState { pub(crate) flycheck_receiver: Receiver, pub(crate) last_flycheck_error: Option, + // Test explorer + pub(crate) test_run_session: Option, + // VFS pub(crate) loader: Handle, Receiver>, pub(crate) vfs: Arc)>>, @@ -201,6 +206,7 @@ impl GlobalState { send_hint_refresh_query: false, last_reported_status: None, source_root_config: SourceRootConfig::default(), + local_roots_parent_map: FxHashMap::default(), config_errors: Default::default(), proc_macro_clients: Arc::from_iter([]), @@ -212,6 +218,8 @@ impl GlobalState { flycheck_receiver, last_flycheck_error: None, + test_run_session: None, + vfs: Arc::new(RwLock::new((vfs::Vfs::default(), IntMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, @@ -238,7 +246,7 @@ impl GlobalState { let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default(); let (change, modified_rust_files, workspace_structure_change) = { - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); let mut guard = self.vfs.write(); let changed_files = guard.0.take_changes(); if changed_files.is_empty() { @@ -297,7 +305,7 @@ impl GlobalState { let mut bytes = vec![]; let mut modified_rust_files = vec![]; for file in changed_files { - let vfs_path = &vfs.file_path(file.file_id); + let vfs_path = vfs.file_path(file.file_id); if let Some(path) = vfs_path.as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.kind()) { @@ -481,7 +489,7 @@ impl GlobalStateSnapshot { } pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url { - let mut base = self.vfs_read().file_path(path.anchor); + let mut base = self.vfs_read().file_path(path.anchor).clone(); base.pop(); let path = base.join(&path.path).unwrap(); let path = path.as_path().unwrap(); @@ -489,7 +497,7 @@ impl GlobalStateSnapshot { } pub(crate) fn file_id_to_file_path(&self, file_id: FileId) -> vfs::VfsPath { - self.vfs_read().file_path(file_id) + self.vfs_read().file_path(file_id).clone() } pub(crate) fn cargo_target_for_crate_root( @@ -497,7 +505,7 @@ impl GlobalStateSnapshot { crate_id: CrateId, ) -> Option<(&CargoWorkspace, Target)> { let file_id = self.analysis.crate_root(crate_id).ok()?; - let path = self.vfs_read().file_path(file_id); + let path = self.vfs_read().file_path(file_id).clone(); let path = path.as_path()?; self.workspaces.iter().find_map(|ws| match ws { ProjectWorkspace::Cargo { cargo, .. } => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/hack_recover_crate_name.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/hack_recover_crate_name.rs new file mode 100644 index 0000000000000..d7285653c5fa5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/hack_recover_crate_name.rs @@ -0,0 +1,25 @@ +//! Currently cargo does not emit crate name in the `cargo test --format=json`, which needs to be changed. This +//! module contains a way to recover crate names in a very hacky and wrong way. + +// FIXME(hack_recover_crate_name): Remove this module. + +use std::sync::{Mutex, MutexGuard, OnceLock}; + +use ide_db::FxHashMap; + +static STORAGE: OnceLock>> = OnceLock::new(); + +fn get_storage() -> MutexGuard<'static, FxHashMap> { + STORAGE.get_or_init(|| Mutex::new(FxHashMap::default())).lock().unwrap() +} + +pub(crate) fn insert_name(name_with_crate: String) { + let Some((_, name_without_crate)) = name_with_crate.split_once("::") else { + return; + }; + get_storage().insert(name_without_crate.to_owned(), name_with_crate); +} + +pub(crate) fn lookup_name(name_without_crate: String) -> Option { + get_storage().get(&name_without_crate).cloned() +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index cf646a2e28282..ff213748b4ff0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -16,7 +16,7 @@ use crate::{ config::Config, global_state::GlobalState, lsp::{from_proto, utils::apply_document_changes}, - lsp_ext::RunFlycheckParams, + lsp_ext::{self, RunFlycheckParams}, mem_docs::DocumentData, reload, }; @@ -373,3 +373,10 @@ pub(crate) fn handle_run_flycheck( } Ok(()) } + +pub(crate) fn handle_abort_run_test(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { + if state.test_run_session.take().is_some() { + state.send_notification::(()); + } + Ok(()) +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 04a043954299a..1d98457add330 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -39,6 +39,7 @@ use crate::{ config::{Config, RustfmtConfig, WorkspaceSymbolConfig}, diff::diff, global_state::{GlobalState, GlobalStateSnapshot}, + hack_recover_crate_name, line_index::LineEndings, lsp::{ from_proto, to_proto, @@ -192,6 +193,70 @@ pub(crate) fn handle_view_item_tree( Ok(res) } +pub(crate) fn handle_run_test( + state: &mut GlobalState, + params: lsp_ext::RunTestParams, +) -> anyhow::Result<()> { + if let Some(_session) = state.test_run_session.take() { + state.send_notification::(()); + } + // We detect the lowest common ansector of all included tests, and + // run it. We ignore excluded tests for now, the client will handle + // it for us. + let lca = match params.include { + Some(tests) => tests + .into_iter() + .reduce(|x, y| { + let mut common_prefix = "".to_owned(); + for (xc, yc) in x.chars().zip(y.chars()) { + if xc != yc { + break; + } + common_prefix.push(xc); + } + common_prefix + }) + .unwrap_or_default(), + None => "".to_owned(), + }; + let handle = if lca.is_empty() { + flycheck::CargoTestHandle::new(None) + } else if let Some((_, path)) = lca.split_once("::") { + flycheck::CargoTestHandle::new(Some(path)) + } else { + flycheck::CargoTestHandle::new(None) + }; + state.test_run_session = Some(handle?); + Ok(()) +} + +pub(crate) fn handle_discover_test( + snap: GlobalStateSnapshot, + params: lsp_ext::DiscoverTestParams, +) -> anyhow::Result { + let _p = tracing::span!(tracing::Level::INFO, "handle_discover_test").entered(); + let (tests, scope) = match params.test_id { + Some(id) => { + let crate_id = id.split_once("::").map(|it| it.0).unwrap_or(&id); + (snap.analysis.discover_tests_in_crate_by_test_id(crate_id)?, vec![crate_id.to_owned()]) + } + None => (snap.analysis.discover_test_roots()?, vec![]), + }; + for t in &tests { + hack_recover_crate_name::insert_name(t.id.clone()); + } + Ok(lsp_ext::DiscoverTestResults { + tests: tests + .into_iter() + .map(|t| { + let line_index = t.file.and_then(|f| snap.file_line_index(f).ok()); + to_proto::test_item(&snap, t, line_index.as_ref()) + }) + .collect(), + scope, + }) +} + pub(crate) fn handle_view_crate_graph( snap: GlobalStateSnapshot, params: ViewCrateGraphParams, @@ -1937,7 +2002,7 @@ fn run_rustfmt( let mut command = match snap.config.rustfmt() { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { // FIXME: Set RUSTUP_TOOLCHAIN - let mut cmd = process::Command::new(toolchain::rustfmt()); + let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path()); cmd.envs(snap.config.extra_env()); cmd.args(extra_args); @@ -2097,7 +2162,7 @@ pub(crate) fn fetch_dependency_list( .into_iter() .filter_map(|it| { let root_file_path = state.file_id_to_file_path(it.root_file_id); - crate_path(root_file_path).and_then(to_url).map(|path| CrateInfoResult { + crate_path(&root_file_path).and_then(to_url).map(|path| CrateInfoResult { name: it.name, version: it.version, path, @@ -2118,7 +2183,7 @@ pub(crate) fn fetch_dependency_list( /// An `Option` value representing the path to the directory of the crate with the given /// name, if such a crate is found. If no crate with the given name is found, this function /// returns `None`. -fn crate_path(root_file_path: VfsPath) -> Option { +fn crate_path(root_file_path: &VfsPath) -> Option { let mut current_dir = root_file_path.parent(); while let Some(path) = current_dir { let cargo_toml_path = path.join("../Cargo.toml")?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 9d692175203d9..3bba4847f9285 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -10,8 +10,10 @@ //! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line" //! which you can use to paste the command in terminal and add `--release` manually. -use hir::Change; -use ide::{AnalysisHost, CallableSnippets, CompletionConfig, FilePosition, TextSize}; +use hir::ChangeWithProcMacros; +use ide::{ + AnalysisHost, CallableSnippets, CompletionConfig, DiagnosticsConfig, FilePosition, TextSize, +}; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig}, SnippetCap, @@ -55,23 +57,25 @@ fn integrated_highlighting_benchmark() { vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}")) }; + let _g = crate::tracing::hprof::init("*>150"); + { let _it = stdx::timeit("initial"); let analysis = host.analysis(); analysis.highlight_as_html(file_id, false).unwrap(); } - crate::tracing::hprof::init("*>100"); - { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); text.push_str("\npub fn _dummy() {}\n"); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); } + let _g = crate::tracing::hprof::init("*>50"); + { let _it = stdx::timeit("after change"); let _span = profile::cpu_span(); @@ -120,7 +124,7 @@ fn integrated_completion_benchmark() { let completion_offset = patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") + "sel".len(); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); completion_offset @@ -155,7 +159,7 @@ fn integrated_completion_benchmark() { analysis.completions(&config, position, None).unwrap(); } - crate::tracing::hprof::init("*>5"); + let _g = crate::tracing::hprof::init("*"); let completion_offset = { let _it = stdx::timeit("change"); @@ -163,7 +167,7 @@ fn integrated_completion_benchmark() { let completion_offset = patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)") + ";sel".len(); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); completion_offset @@ -205,7 +209,7 @@ fn integrated_completion_benchmark() { let completion_offset = patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") + "self.".len(); - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); completion_offset @@ -242,6 +246,80 @@ fn integrated_completion_benchmark() { } } +#[test] +fn integrated_diagnostics_benchmark() { + if std::env::var("RUN_SLOW_BENCHES").is_err() { + return; + } + + // Load rust-analyzer itself. + let workspace_to_load = project_root(); + let file = "./crates/hir/src/lib.rs"; + + let cargo_config = CargoConfig { + sysroot: Some(project_model::RustLibSource::Discover), + ..CargoConfig::default() + }; + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + with_proc_macro_server: ProcMacroServerChoice::None, + prefill_caches: true, + }; + + let (db, vfs, _proc_macro) = { + let _it = stdx::timeit("workspace loading"); + load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap() + }; + let mut host = AnalysisHost::with_database(db); + + let file_id = { + let file = workspace_to_load.join(file); + let path = VfsPath::from(AbsPathBuf::assert(file)); + vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}")) + }; + + let diagnostics_config = DiagnosticsConfig { + enabled: false, + proc_macros_enabled: true, + proc_attr_macros_enabled: true, + disable_experimental: true, + disabled: Default::default(), + expr_fill_default: Default::default(), + style_lints: false, + insert_use: InsertUseConfig { + granularity: ImportGranularity::Crate, + enforce_granularity: false, + prefix_kind: hir::PrefixKind::ByCrate, + group: true, + skip_glob_imports: true, + }, + prefer_no_std: false, + prefer_prelude: false, + }; + host.analysis() + .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id) + .unwrap(); + + let _g = crate::tracing::hprof::init("*>1"); + + { + let _it = stdx::timeit("change"); + let mut text = host.analysis().file_text(file_id).unwrap().to_string(); + patch(&mut text, "db.struct_data(self.id)", "();\ndb.struct_data(self.id)"); + let mut change = ChangeWithProcMacros::new(); + change.change_file(file_id, Some(Arc::from(text))); + host.apply_change(change); + }; + + { + let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered(); + let _span = profile::cpu_span(); + host.analysis() + .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id) + .unwrap(); + } +} + fn patch(what: &mut String, from: &str, to: &str) -> usize { let idx = what.find(from).unwrap(); *what = what.replacen(from, to, 1); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 473ca991ad9b0..175ffa622ff70 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -19,6 +19,7 @@ mod diagnostics; mod diff; mod dispatch; mod global_state; +mod hack_recover_crate_name; mod line_index; mod main_loop; mod mem_docs; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index aa40728ce6cb8..86ab652f8ef5a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -163,6 +163,108 @@ impl Request for ViewItemTree { const METHOD: &'static str = "rust-analyzer/viewItemTree"; } +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DiscoverTestParams { + pub test_id: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub enum TestItemKind { + Package, + Module, + Test, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct TestItem { + pub id: String, + pub label: String, + pub kind: TestItemKind, + pub can_resolve_children: bool, + pub parent: Option, + pub text_document: Option, + pub range: Option, + pub runnable: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DiscoverTestResults { + pub tests: Vec, + pub scope: Vec, +} + +pub enum DiscoverTest {} + +impl Request for DiscoverTest { + type Params = DiscoverTestParams; + type Result = DiscoverTestResults; + const METHOD: &'static str = "experimental/discoverTest"; +} + +pub enum DiscoveredTests {} + +impl Notification for DiscoveredTests { + type Params = DiscoverTestResults; + const METHOD: &'static str = "experimental/discoveredTests"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RunTestParams { + pub include: Option>, + pub exclude: Option>, +} + +pub enum RunTest {} + +impl Request for RunTest { + type Params = RunTestParams; + type Result = (); + const METHOD: &'static str = "experimental/runTest"; +} + +pub enum EndRunTest {} + +impl Notification for EndRunTest { + type Params = (); + const METHOD: &'static str = "experimental/endRunTest"; +} + +pub enum AbortRunTest {} + +impl Notification for AbortRunTest { + type Params = (); + const METHOD: &'static str = "experimental/abortRunTest"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase", tag = "tag")] +pub enum TestState { + Passed, + Failed { message: String }, + Skipped, + Started, + Enqueued, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ChangeTestStateParams { + pub test_id: String, + pub state: TestState, +} + +pub enum ChangeTestState {} + +impl Notification for ChangeTestState { + type Params = ChangeTestStateParams; + const METHOD: &'static str = "experimental/changeTestState"; +} + pub enum ExpandMacro {} impl Request for ExpandMacro { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 481ebfefd4eed..e2b55f4a5c5b9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1498,6 +1498,32 @@ pub(crate) fn code_lens( Ok(()) } +pub(crate) fn test_item( + snap: &GlobalStateSnapshot, + test_item: ide::TestItem, + line_index: Option<&LineIndex>, +) -> lsp_ext::TestItem { + lsp_ext::TestItem { + id: test_item.id, + label: test_item.label, + kind: match test_item.kind { + ide::TestItemKind::Crate => lsp_ext::TestItemKind::Package, + ide::TestItemKind::Module => lsp_ext::TestItemKind::Module, + ide::TestItemKind::Function => lsp_ext::TestItemKind::Test, + }, + can_resolve_children: matches!( + test_item.kind, + ide::TestItemKind::Crate | ide::TestItemKind::Module + ), + parent: test_item.parent, + text_document: test_item + .file + .map(|f| lsp_types::TextDocumentIdentifier { uri: url(snap, f) }), + range: line_index.and_then(|l| Some(range(l, test_item.text_range?))), + runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()), + } +} + pub(crate) mod command { use ide::{FileRange, NavigationTarget}; use serde_json::to_value; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 72f6d0fde5fe7..bca6db19dcf91 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -1,14 +1,15 @@ //! The main loop of `rust-analyzer` responsible for dispatching LSP //! requests/replies and notifications back to the client. -use crate::lsp::ext; + use std::{ fmt, time::{Duration, Instant}, }; use always_assert::always; -use crossbeam_channel::{select, Receiver}; +use crossbeam_channel::{never, select, Receiver}; use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath}; +use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; use stdx::thread::ThreadIntent; @@ -19,8 +20,9 @@ use crate::{ diagnostics::fetch_native_diagnostics, dispatch::{NotificationDispatcher, RequestDispatcher}, global_state::{file_id_to_url, url_to_file_id, GlobalState}, + hack_recover_crate_name, lsp::{ - from_proto, + from_proto, to_proto, utils::{notification_is, Progress}, }, lsp_ext, @@ -58,6 +60,7 @@ enum Event { QueuedTask(QueuedTask), Vfs(vfs::loader::Message), Flycheck(flycheck::Message), + TestResult(flycheck::CargoTestMessage), } impl fmt::Display for Event { @@ -68,6 +71,7 @@ impl fmt::Display for Event { Event::Vfs(_) => write!(f, "Event::Vfs"), Event::Flycheck(_) => write!(f, "Event::Flycheck"), Event::QueuedTask(_) => write!(f, "Event::QueuedTask"), + Event::TestResult(_) => write!(f, "Event::TestResult"), } } } @@ -81,9 +85,10 @@ pub(crate) enum QueuedTask { #[derive(Debug)] pub(crate) enum Task { Response(lsp_server::Response), - ClientNotification(ext::UnindexedProjectParams), + ClientNotification(lsp_ext::UnindexedProjectParams), Retry(lsp_server::Request), Diagnostics(Vec<(FileId, Vec)>), + DiscoverTest(lsp_ext::DiscoverTestResults), PrimeCaches(PrimeCachesProgress), FetchWorkspace(ProjectWorkspaceProgress), FetchBuildData(BuildDataProgress), @@ -127,6 +132,7 @@ impl fmt::Debug for Event { Event::QueuedTask(it) => fmt::Debug::fmt(it, f), Event::Vfs(it) => fmt::Debug::fmt(it, f), Event::Flycheck(it) => fmt::Debug::fmt(it, f), + Event::TestResult(it) => fmt::Debug::fmt(it, f), } } } @@ -214,6 +220,10 @@ impl GlobalState { recv(self.flycheck_receiver) -> task => Some(Event::Flycheck(task.unwrap())), + + recv(self.test_run_session.as_ref().map(|s| s.receiver()).unwrap_or(&never())) -> task => + Some(Event::TestResult(task.unwrap())), + } } @@ -322,6 +332,18 @@ impl GlobalState { self.handle_flycheck_msg(message); } } + Event::TestResult(message) => { + let _p = + tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/test_result") + .entered(); + self.handle_cargo_test_msg(message); + // Coalesce many test result event into a single loop turn + while let Some(message) = + self.test_run_session.as_ref().and_then(|r| r.receiver().try_recv().ok()) + { + self.handle_cargo_test_msg(message); + } + } } let event_handling_duration = loop_start.elapsed(); @@ -364,10 +386,12 @@ impl GlobalState { } } - let update_diagnostics = (!was_quiescent || state_changed || memdocs_added_or_removed) - && self.config.publish_diagnostics(); - if update_diagnostics { - self.update_diagnostics() + let things_changed = !was_quiescent || state_changed || memdocs_added_or_removed; + if things_changed && self.config.publish_diagnostics() { + self.update_diagnostics(); + } + if things_changed && self.config.test_explorer() { + self.update_tests(); } } @@ -488,6 +512,55 @@ impl GlobalState { }); } + fn update_tests(&mut self) { + let db = self.analysis_host.raw_database(); + let subscriptions = self + .mem_docs + .iter() + .map(|path| self.vfs.read().0.file_id(path).unwrap()) + .filter(|&file_id| { + let source_root = db.file_source_root(file_id); + !db.source_root(source_root).is_library + }) + .collect::>(); + tracing::trace!("updating tests for {:?}", subscriptions); + + // Updating tests are triggered by the user typing + // so we run them on a latency sensitive thread. + self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, { + let snapshot = self.snapshot(); + move || { + let tests = subscriptions + .into_iter() + .filter_map(|f| snapshot.analysis.crates_for(f).ok()) + .flatten() + .unique() + .filter_map(|c| snapshot.analysis.discover_tests_in_crate(c).ok()) + .flatten() + .collect::>(); + for t in &tests { + hack_recover_crate_name::insert_name(t.id.clone()); + } + let scope = tests + .iter() + .filter_map(|t| Some(t.id.split_once("::")?.0)) + .unique() + .map(|it| it.to_owned()) + .collect(); + Task::DiscoverTest(lsp_ext::DiscoverTestResults { + tests: tests + .into_iter() + .map(|t| { + let line_index = t.file.and_then(|f| snapshot.file_line_index(f).ok()); + to_proto::test_item(&snapshot, t, line_index.as_ref()) + }) + .collect(), + scope, + }) + } + }); + } + fn update_status_or_notify(&mut self) { let status = self.current_status(); if self.last_reported_status.as_ref() != Some(&status) { @@ -598,6 +671,9 @@ impl GlobalState { } } Task::BuildDepsHaveChanged => self.build_deps_changed = true, + Task::DiscoverTest(tests) => { + self.send_notification::(tests); + } } } @@ -666,7 +742,7 @@ impl GlobalState { let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId"); if let Ok(crates) = &snap.analysis.crates_for(id) { if crates.is_empty() { - let params = ext::UnindexedProjectParams { + let params = lsp_ext::UnindexedProjectParams { text_documents: vec![lsp_types::TextDocumentIdentifier { uri }], }; sender.send(Task::ClientNotification(params)).unwrap(); @@ -698,6 +774,32 @@ impl GlobalState { } } + fn handle_cargo_test_msg(&mut self, message: flycheck::CargoTestMessage) { + match message { + flycheck::CargoTestMessage::Test { name, state } => { + let state = match state { + flycheck::TestState::Started => lsp_ext::TestState::Started, + flycheck::TestState::Ignored => lsp_ext::TestState::Skipped, + flycheck::TestState::Ok => lsp_ext::TestState::Passed, + flycheck::TestState::Failed { stdout } => { + lsp_ext::TestState::Failed { message: stdout } + } + }; + let Some(test_id) = hack_recover_crate_name::lookup_name(name) else { + return; + }; + self.send_notification::( + lsp_ext::ChangeTestStateParams { test_id, state }, + ); + } + flycheck::CargoTestMessage::Suite => (), + flycheck::CargoTestMessage::Finished => { + self.send_notification::(()); + self.test_run_session = None; + } + } + } + fn handle_flycheck_msg(&mut self, message: flycheck::Message) { match message { flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { @@ -803,6 +905,7 @@ impl GlobalState { .on_sync_mut::(handlers::handle_proc_macros_rebuild) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) + .on_sync_mut::(handlers::handle_run_test) // Request handlers which are related to the user typing // are run on the main thread to reduce latency: .on_sync::(handlers::handle_join_lines) @@ -843,6 +946,7 @@ impl GlobalState { .on::(handlers::handle_view_file_text) .on::(handlers::handle_view_crate_graph) .on::(handlers::handle_view_item_tree) + .on::(handlers::handle_discover_test) .on::(handlers::handle_expand_macro) .on::(handlers::handle_parent_module) .on::(handlers::handle_runnables) @@ -906,6 +1010,7 @@ impl GlobalState { .on_sync_mut::(handlers::handle_cancel_flycheck)? .on_sync_mut::(handlers::handle_clear_flycheck)? .on_sync_mut::(handlers::handle_run_flycheck)? + .on_sync_mut::(handlers::handle_abort_run_test)? .finish(); Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index f6bc032c01986..c2725e1fad919 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -16,7 +16,7 @@ use std::{iter, mem}; use flycheck::{FlycheckConfig, FlycheckHandle}; -use hir::{db::DefDatabase, Change, ProcMacros}; +use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros}; use ide::CrateId; use ide_db::{ base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version}, @@ -357,7 +357,7 @@ impl GlobalState { } pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) { - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); change.set_proc_macros(proc_macros); self.analysis_host.apply_change(change); } @@ -515,6 +515,7 @@ impl GlobalState { version: self.vfs_config_version, }); self.source_root_config = project_folders.source_root_config; + self.local_roots_parent_map = self.source_root_config.source_root_parent_map(); self.recreate_crate_graph(cause); @@ -548,7 +549,7 @@ impl GlobalState { ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load) }; - let mut change = Change::new(); + let mut change = ChangeWithProcMacros::new(); if self.config.expand_proc_macros() { change.set_proc_macros( crate_graph diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index fcdbd1e6d9b56..f77d98933044a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -4,13 +4,10 @@ use std::io; use anyhow::Context; -use tracing::{level_filters::LevelFilter, Level}; +use tracing::level_filters::LevelFilter; use tracing_subscriber::{ - filter::{self, Targets}, - fmt::{format::FmtSpan, MakeWriter}, - layer::SubscriberExt, - util::SubscriberInitExt, - Layer, Registry, + filter::Targets, fmt::MakeWriter, layer::SubscriberExt, util::SubscriberInitExt, Layer, + Registry, }; use tracing_tree::HierarchicalLayer; @@ -50,10 +47,7 @@ where let writer = self.writer; - let ra_fmt_layer = tracing_subscriber::fmt::layer() - .with_span_events(FmtSpan::CLOSE) - .with_writer(writer) - .with_filter(filter); + let ra_fmt_layer = tracing_subscriber::fmt::layer().with_writer(writer).with_filter(filter); let mut chalk_layer = None; if let Some(chalk_filter) = self.chalk_filter { @@ -74,32 +68,7 @@ where ); }; - let mut profiler_layer = None; - if let Some(spec) = self.profile_filter { - let (write_filter, allowed_names) = hprof::WriteFilter::from_spec(&spec); - - // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like - // span depth or duration are not filtered here: that only occurs at write time. - let profile_filter = filter::filter_fn(move |metadata| { - let allowed = match &allowed_names { - Some(names) => names.contains(metadata.name()), - None => true, - }; - - metadata.is_span() - && allowed - && metadata.level() >= &Level::INFO - && !metadata.target().starts_with("salsa") - && !metadata.target().starts_with("chalk") - }); - - let layer = hprof::SpanTree::default() - .aggregate(true) - .spec_filter(write_filter) - .with_filter(profile_filter); - - profiler_layer = Some(layer); - } + let profiler_layer = self.profile_filter.map(|spec| hprof::layer(&spec)); Registry::default().with(ra_fmt_layer).with(chalk_layer).with(profiler_layer).try_init()?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs index 9064987329778..73f94671f2daa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs @@ -52,7 +52,15 @@ use tracing_subscriber::{ use crate::tracing::hprof; -pub fn init(spec: &str) { +pub fn init(spec: &str) -> tracing::subscriber::DefaultGuard { + let subscriber = Registry::default().with(layer(spec)); + tracing::subscriber::set_default(subscriber) +} + +pub fn layer(spec: &str) -> impl Layer +where + S: Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, +{ let (write_filter, allowed_names) = WriteFilter::from_spec(spec); // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like @@ -63,20 +71,15 @@ pub fn init(spec: &str) { None => true, }; - metadata.is_span() - && allowed + allowed + && metadata.is_span() && metadata.level() >= &Level::INFO && !metadata.target().starts_with("salsa") + && metadata.name() != "compute_exhaustiveness_and_usefulness" && !metadata.target().starts_with("chalk") }); - let layer = hprof::SpanTree::default() - .aggregate(true) - .spec_filter(write_filter) - .with_filter(profile_filter); - - let subscriber = Registry::default().with(layer); - tracing::subscriber::set_global_default(subscriber).unwrap(); + hprof::SpanTree::default().aggregate(true).spec_filter(write_filter).with_filter(profile_filter) } #[derive(Default, Debug)] diff --git a/src/tools/rust-analyzer/crates/salsa/Cargo.toml b/src/tools/rust-analyzer/crates/salsa/Cargo.toml index 9eec21f6a15ff..0d3e1197b5c67 100644 --- a/src/tools/rust-analyzer/crates/salsa/Cargo.toml +++ b/src/tools/rust-analyzer/crates/salsa/Cargo.toml @@ -28,7 +28,6 @@ salsa-macros = { version = "0.0.0", path = "salsa-macros" } [dev-dependencies] linked-hash-map = "0.5.6" rand = "0.8.5" -test-log = "0.2.14" expect-test = "1.4.0" dissimilar = "1.0.7" diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs index a868d920b6669..5983765eec7b6 100644 --- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs +++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs @@ -235,13 +235,24 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream queries_with_storage.push(fn_name); + let tracing = if let QueryStorage::Memoized = query.storage { + let s = format!("{trait_name}::{fn_name}"); + Some(quote! { + let _p = tracing::span!(tracing::Level::DEBUG, #s, #(#key_names = tracing::field::debug(&#key_names)),*).entered(); + }) + } else { + None + } + .into_iter(); + query_fn_definitions.extend(quote! { fn #fn_name(&self, #(#key_names: #keys),*) -> #value { + #(#tracing),* // Create a shim to force the code to be monomorphized in the // query crate. Our experiments revealed that this makes a big // difference in total compilation time in rust-analyzer, though // it's not totally obvious why that should be. - fn __shim(db: &(dyn #trait_name + '_), #(#key_names: #keys),*) -> #value { + fn __shim(db: &(dyn #trait_name + '_), #(#key_names: #keys),*) -> #value { salsa::plumbing::get_query_table::<#qt>(db).get((#(#key_names),*)) } __shim(self, #(#key_names),*) diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived.rs b/src/tools/rust-analyzer/crates/salsa/src/derived.rs index 153df999f5349..3b5bd7f9e3bb2 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/derived.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/derived.rs @@ -136,7 +136,7 @@ where ) -> std::fmt::Result { let slot_map = self.slot_map.read(); let key = slot_map.get_index(index as usize).unwrap().0; - write!(fmt, "{}({:?})", Q::QUERY_NAME, key) + write!(fmt, "{}::{}({:?})", std::any::type_name::(), Q::QUERY_NAME, key) } fn maybe_changed_after( @@ -146,13 +146,13 @@ where revision: Revision, ) -> bool { debug_assert!(revision < db.salsa_runtime().current_revision()); - let read = self.slot_map.read(); - let Some((key, slot)) = read.get_index(index as usize) else { - return false; + let (key, slot) = { + let read = self.slot_map.read(); + let Some((key, slot)) = read.get_index(index as usize) else { + return false; + }; + (key.clone(), slot.clone()) }; - let (key, slot) = (key.clone(), slot.clone()); - // note: this drop is load-bearing. removing it would causes deadlocks. - drop(read); slot.maybe_changed_after(db, revision, &key) } diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs index a7d5a2457823f..e11cabfe11edc 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs @@ -595,7 +595,7 @@ impl ActiveQuery { fn remove_cycle_participants(&mut self, cycle: &Cycle) { if let Some(my_dependencies) = &mut self.dependencies { for p in cycle.participant_keys() { - my_dependencies.remove(&p); + my_dependencies.swap_remove(&p); } } } diff --git a/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs index 00ca5332440ef..ea5d15a250f59 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs @@ -2,7 +2,6 @@ use std::panic::UnwindSafe; use expect_test::expect; use salsa::{Durability, ParallelDatabase, Snapshot}; -use test_log::test; // Axes: // @@ -172,8 +171,8 @@ fn cycle_memoized() { let cycle = extract_cycle(|| db.memoized_a()); expect![[r#" [ - "memoized_a(())", - "memoized_b(())", + "cycles::MemoizedAQuery::memoized_a(())", + "cycles::MemoizedBQuery::memoized_b(())", ] "#]] .assert_debug_eq(&cycle.unexpected_participants(&db)); @@ -185,8 +184,8 @@ fn cycle_volatile() { let cycle = extract_cycle(|| db.volatile_a()); expect![[r#" [ - "volatile_a(())", - "volatile_b(())", + "cycles::VolatileAQuery::volatile_a(())", + "cycles::VolatileBQuery::volatile_b(())", ] "#]] .assert_debug_eq(&cycle.unexpected_participants(&db)); @@ -223,8 +222,8 @@ fn inner_cycle() { let cycle = err.unwrap_err().cycle; expect![[r#" [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ] "#]] .assert_debug_eq(&cycle); @@ -263,8 +262,8 @@ fn cycle_revalidate_unchanged_twice() { Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ) @@ -345,8 +344,8 @@ fn cycle_mixed_1() { Err( Error { cycle: [ - "cycle_b(())", - "cycle_c(())", + "cycles::CycleBQuery::cycle_b(())", + "cycles::CycleCQuery::cycle_c(())", ], }, ) @@ -372,9 +371,9 @@ fn cycle_mixed_2() { Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", - "cycle_c(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", + "cycles::CycleCQuery::cycle_c(())", ], }, ) @@ -401,16 +400,16 @@ fn cycle_deterministic_order() { Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ), Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ), @@ -446,24 +445,24 @@ fn cycle_multiple() { Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ), Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ), Err( Error { cycle: [ - "cycle_a(())", - "cycle_b(())", + "cycles::CycleAQuery::cycle_a(())", + "cycles::CycleBQuery::cycle_b(())", ], }, ), @@ -486,7 +485,7 @@ fn cycle_recovery_set_but_not_participating() { let r = extract_cycle(|| drop(db.cycle_a())); expect![[r#" [ - "cycle_c(())", + "cycles::CycleCQuery::cycle_c(())", ] "#]] .assert_debug_eq(&r.all_participants(&db)); diff --git a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs index 677d633ee7cc0..cad594f536f0f 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs @@ -103,10 +103,10 @@ fn on_demand_input_durability() { expect_test::expect![[r#" RefCell { value: [ - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: b(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: b(2) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::BQuery::b(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::AQuery::a(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::BQuery::b(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::AQuery::a(2) } }", ], } "#]].assert_debug_eq(&events); @@ -119,11 +119,11 @@ fn on_demand_input_durability() { expect_test::expect![[r#" RefCell { value: [ - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: c(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: b(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: c(2) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: b(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::CQuery::c(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: on_demand_inputs::BQuery::b(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::CQuery::c(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::AQuery::a(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: on_demand_inputs::BQuery::b(2) } }", ], } "#]].assert_debug_eq(&events); @@ -137,10 +137,10 @@ fn on_demand_input_durability() { expect_test::expect![[r#" RefCell { value: [ - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: c(1) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }", - "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: c(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::AQuery::a(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: on_demand_inputs::CQuery::c(1) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: on_demand_inputs::AQuery::a(2) } }", + "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: on_demand_inputs::CQuery::c(2) } }", ], } "#]].assert_debug_eq(&events); diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs index cee51b4db75e6..a13ae3418f20b 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs @@ -4,7 +4,6 @@ use crate::setup::{Knobs, ParDatabaseImpl}; use salsa::ParallelDatabase; -use test_log::test; // Recover cycle test: // diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs index f78c05c5593c8..971fe7ab12079 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs @@ -4,7 +4,6 @@ use crate::setup::{Knobs, ParDatabaseImpl}; use salsa::ParallelDatabase; -use test_log::test; // Recover cycle test: // diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs index 35fe3791182ea..2930c4e379ff8 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs @@ -5,7 +5,6 @@ use crate::setup::{Knobs, ParDatabaseImpl}; use expect_test::expect; use salsa::ParallelDatabase; -use test_log::test; #[test] fn parallel_cycle_none_recover() { @@ -28,8 +27,8 @@ fn parallel_cycle_none_recover() { if let Some(c) = err_b.downcast_ref::() { expect![[r#" [ - "a(-1)", - "b(-1)", + "parallel::parallel_cycle_none_recover::AQuery::a(-1)", + "parallel::parallel_cycle_none_recover::BQuery::b(-1)", ] "#]] .assert_debug_eq(&c.unexpected_participants(&db)); diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs index 7d3944714aef2..025fbf37477f6 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs @@ -4,7 +4,6 @@ use crate::setup::{Knobs, ParDatabaseImpl}; use salsa::ParallelDatabase; -use test_log::test; // Recover cycle test: // diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 2d98aa81e502b..332745aae6e95 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -83,24 +83,28 @@ register_ast_id_node! { Item, Adt, Enum, + Variant, Struct, + RecordField, + TupleField, Union, - Const, + AssocItem, + Const, + Fn, + MacroCall, + TypeAlias, ExternBlock, ExternCrate, - Fn, Impl, Macro, MacroDef, MacroRules, - MacroCall, Module, Static, Trait, TraitAlias, - TypeAlias, Use, - AssocItem, BlockExpr, Variant, RecordField, TupleField, ConstArg, Param, SelfParam + BlockExpr, ConstArg, Param, SelfParam } /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. diff --git a/src/tools/rust-analyzer/crates/stdx/src/process.rs b/src/tools/rust-analyzer/crates/stdx/src/process.rs index bca0cbc36d1a7..e6935f06b2ce1 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/process.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/process.rs @@ -15,6 +15,7 @@ pub fn streaming_output( err: ChildStderr, on_stdout_line: &mut dyn FnMut(&str), on_stderr_line: &mut dyn FnMut(&str), + on_eof: &mut dyn FnMut(), ) -> io::Result<(Vec, Vec)> { let mut stdout = Vec::new(); let mut stderr = Vec::new(); @@ -44,6 +45,9 @@ pub fn streaming_output( on_stderr_line(line); } } + if eof { + on_eof(); + } } })?; @@ -63,6 +67,7 @@ pub fn spawn_with_streaming_output( child.stderr.take().unwrap(), on_stdout_line, on_stderr_line, + &mut || (), )?; let status = child.wait()?; Ok(Output { status, stdout, stderr }) diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index a0fd73ee13f57..9a8d73cf7ff47 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -27,7 +27,6 @@ tracing.workspace = true ra-ap-rustc_lexer.workspace = true parser.workspace = true -profile.workspace = true stdx.workspace = true text-edit.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index f299dda4f0f42..ff18fee9bab26 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -724,7 +724,10 @@ pub fn record_pat_field_list( ) -> ast::RecordPatFieldList { let mut fields = fields.into_iter().join(", "); if let Some(rest_pat) = rest_pat { - format_to!(fields, ", {rest_pat}"); + if !fields.is_empty() { + fields.push_str(", "); + } + format_to!(fields, "{rest_pat}"); } ast_from_text(&format!("fn f(S {{ {fields} }}: ()))")) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index b755de86d32c5..1bb82cc191ffc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -97,8 +97,11 @@ impl Parse { pub fn syntax_node(&self) -> SyntaxNode { SyntaxNode::new_root(self.green.clone()) } - pub fn errors(&self) -> &[SyntaxError] { - self.errors.as_deref().unwrap_or_default() + + pub fn errors(&self) -> Vec { + let mut errors = if let Some(e) = self.errors.as_deref() { e.to_vec() } else { vec![] }; + validation::validate(&self.syntax_node(), &mut errors); + errors } } @@ -111,10 +114,10 @@ impl Parse { T::cast(self.syntax_node()).unwrap() } - pub fn ok(self) -> Result> { - match self.errors { - Some(e) => Err(e), - None => Ok(self.tree()), + pub fn ok(self) -> Result> { + match self.errors() { + errors if !errors.is_empty() => Err(errors), + _ => Ok(self.tree()), } } } @@ -132,7 +135,7 @@ impl Parse { impl Parse { pub fn debug_dump(&self) -> String { let mut buf = format!("{:#?}", self.tree().syntax()); - for err in self.errors.as_deref().into_iter().flat_map(<[_]>::iter) { + for err in self.errors() { format_to!(buf, "error {:?}: {}\n", err.range(), err); } buf @@ -168,11 +171,10 @@ pub use crate::ast::SourceFile; impl SourceFile { pub fn parse(text: &str) -> Parse { - let (green, mut errors) = parsing::parse_text(text); + let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered(); + let (green, errors) = parsing::parse_text(text); let root = SyntaxNode::new_root(green.clone()); - errors.extend(validation::validate(&root)); - assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); Parse { green, diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs index 1250b5274c189..d750476f63cb5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs @@ -10,6 +10,7 @@ use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder}; pub(crate) use crate::parsing::reparsing::incremental_reparse; pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec) { + let _p = tracing::span!(tracing::Level::INFO, "parse_text").entered(); let lexed = parser::LexedStr::new(text); let parser_input = lexed.to_input(); let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input); @@ -21,6 +22,7 @@ pub(crate) fn build_tree( lexed: parser::LexedStr<'_>, parser_output: parser::Output, ) -> (GreenNode, Vec, bool) { + let _p = tracing::span!(tracing::Level::INFO, "build_tree").entered(); let mut builder = SyntaxTreeBuilder::default(); let is_eof = lexed.intersperse_trivia(&parser_output, &mut |step| match step { diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests.rs b/src/tools/rust-analyzer/crates/syntax/src/tests.rs index 4c0a538f712f5..5400071c4b678 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests.rs @@ -39,7 +39,7 @@ fn benchmark_parser() { let tree = { let _b = bench("parsing"); let p = SourceFile::parse(&data); - assert!(p.errors.is_none()); + assert!(p.errors().is_empty()); assert_eq!(p.tree().syntax.text_range().len(), 352474.into()); p.tree() }; @@ -57,7 +57,7 @@ fn validation_tests() { dir_tests(&test_data_dir(), &["parser/validation"], "rast", |text, path| { let parse = SourceFile::parse(text); let errors = parse.errors(); - assert_errors_are_present(errors, path); + assert_errors_are_present(&errors, path); parse.debug_dump() }); } diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 5c5b26f525f66..dbfab537fe58b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -15,33 +15,32 @@ use crate::{ SyntaxNode, SyntaxToken, TextSize, T, }; -pub(crate) fn validate(root: &SyntaxNode) -> Vec { +pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec) { + let _p = tracing::span!(tracing::Level::INFO, "parser::validate").entered(); // FIXME: // * Add unescape validation of raw string literals and raw byte string literals // * Add validation of doc comments are being attached to nodes - let mut errors = Vec::new(); for node in root.descendants() { match_ast! { match node { - ast::Literal(it) => validate_literal(it, &mut errors), - ast::Const(it) => validate_const(it, &mut errors), - ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors), - ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors), - ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors), - ast::Visibility(it) => validate_visibility(it, &mut errors), - ast::RangeExpr(it) => validate_range_expr(it, &mut errors), - ast::PathSegment(it) => validate_path_keywords(it, &mut errors), - ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors), - ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors), - ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors), - ast::MacroRules(it) => validate_macro_rules(it, &mut errors), - ast::LetExpr(it) => validate_let_expr(it, &mut errors), + ast::Literal(it) => validate_literal(it, errors), + ast::Const(it) => validate_const(it, errors), + ast::BlockExpr(it) => block::validate_block_expr(it, errors), + ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), errors), + ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), errors), + ast::Visibility(it) => validate_visibility(it, errors), + ast::RangeExpr(it) => validate_range_expr(it, errors), + ast::PathSegment(it) => validate_path_keywords(it, errors), + ast::RefType(it) => validate_trait_object_ref_ty(it, errors), + ast::PtrType(it) => validate_trait_object_ptr_ty(it, errors), + ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors), + ast::MacroRules(it) => validate_macro_rules(it, errors), + ast::LetExpr(it) => validate_let_expr(it, errors), _ => (), } } } - errors } fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) { diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index e118262b4edd9..a654366c62a77 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -7,7 +7,7 @@ use base_db::{ }; use cfg::CfgOptions; use hir_expand::{ - change::Change, + change::ChangeWithProcMacros, db::ExpandDatabase, proc_macro::{ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacros, @@ -103,7 +103,7 @@ impl WithFixture for pub struct ChangeFixture { pub file_position: Option<(FileId, RangeOrOffset)>, pub files: Vec, - pub change: Change, + pub change: ChangeWithProcMacros, } const SOURCE_ROOT_PREFIX: &str = "/"; @@ -149,15 +149,15 @@ impl ChangeFixture { for entry in fixture { let text = if entry.text.contains(CURSOR_MARKER) { if entry.text.contains(ESCAPED_CURSOR_MARKER) { - entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER) + entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER).into() } else { let (range_or_offset, text) = extract_range_or_offset(&entry.text); assert!(file_position.is_none()); file_position = Some((file_id, range_or_offset)); - text + text.into() } } else { - entry.text.clone() + entry.text.as_str().into() }; let meta = FileMeta::from_fixture(entry, current_source_root_kind); @@ -195,7 +195,10 @@ impl ChangeFixture { let prev = crates.insert(crate_name.clone(), crate_id); assert!(prev.is_none(), "multiple crates with same name: {}", crate_name); for dep in meta.deps { - let prelude = meta.extern_prelude.contains(&dep); + let prelude = match &meta.extern_prelude { + Some(v) => v.contains(&dep), + None => true, + }; let dep = CrateName::normalize_dashes(&dep); crate_deps.push((crate_name.clone(), dep, prelude)) } @@ -206,7 +209,7 @@ impl ChangeFixture { default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned()))); } - source_change.change_file(file_id, Some(text.into())); + source_change.change_file(file_id, Some(text)); let path = VfsPath::new_virtual_path(meta.path); file_set.insert(file_id, path); files.push(file_id); @@ -317,7 +320,7 @@ impl ChangeFixture { }; roots.push(root); - let mut change = Change { + let mut change = ChangeWithProcMacros { source_change, proc_macros: proc_macros.is_empty().not().then_some(proc_macros), toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()), @@ -443,7 +446,7 @@ struct FileMeta { path: String, krate: Option<(String, CrateOrigin, Option)>, deps: Vec, - extern_prelude: Vec, + extern_prelude: Option>, cfg: CfgOptions, edition: Edition, env: Env, @@ -473,7 +476,7 @@ impl FileMeta { Self { path: f.path, krate: f.krate.map(|it| parse_crate(it, current_source_root_kind, f.library)), - extern_prelude: f.extern_prelude.unwrap_or_else(|| deps.clone()), + extern_prelude: f.extern_prelude, deps, cfg, edition: f.edition.map_or(Edition::CURRENT, |v| Edition::from_str(&v).unwrap()), diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 793138588a3f6..a77fed585af77 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -16,18 +16,48 @@ pub enum Tool { } impl Tool { + pub fn proxy(self) -> Option { + cargo_proxy(self.name()) + } + + /// Return a `PathBuf` to use for the given executable. + /// + /// The current implementation checks three places for an executable to use: + /// 1) `$CARGO_HOME/bin/` + /// where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) + /// example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. + /// It seems that this is a reasonable place to try for cargo, rustc, and rustup + /// 2) Appropriate environment variable (erroring if this is set but not a usable executable) + /// example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc + /// 3) $PATH/`` + /// example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the + /// first that exists + /// 4) If all else fails, we just try to use the executable name directly + pub fn prefer_proxy(self) -> PathBuf { + invoke(&[cargo_proxy, lookup_as_env_var, lookup_in_path], self.name()) + } + + /// Return a `PathBuf` to use for the given executable. + /// + /// The current implementation checks three places for an executable to use: + /// 1) Appropriate environment variable (erroring if this is set but not a usable executable) + /// example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc + /// 2) $PATH/`` + /// example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the + /// first that exists + /// 3) `$CARGO_HOME/bin/` + /// where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) + /// example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. + /// It seems that this is a reasonable place to try for cargo, rustc, and rustup + /// 4) If all else fails, we just try to use the executable name directly pub fn path(self) -> PathBuf { - get_path_for_executable(self.name()) + invoke(&[lookup_as_env_var, lookup_in_path, cargo_proxy], self.name()) } pub fn path_in(self, path: &Path) -> Option { probe_for_binary(path.join(self.name())) } - pub fn path_in_or_discover(self, path: &Path) -> PathBuf { - probe_for_binary(path.join(self.name())).unwrap_or_else(|| self.path()) - } - pub fn name(self) -> &'static str { match self { Tool::Cargo => "cargo", @@ -38,60 +68,21 @@ impl Tool { } } -pub fn cargo() -> PathBuf { - get_path_for_executable("cargo") +fn invoke(list: &[fn(&str) -> Option], executable: &str) -> PathBuf { + list.iter().find_map(|it| it(executable)).unwrap_or_else(|| executable.into()) } -pub fn rustc() -> PathBuf { - get_path_for_executable("rustc") +/// Looks up the binary as its SCREAMING upper case in the env variables. +fn lookup_as_env_var(executable_name: &str) -> Option { + env::var_os(executable_name.to_ascii_uppercase()).map(Into::into) } -pub fn rustup() -> PathBuf { - get_path_for_executable("rustup") -} - -pub fn rustfmt() -> PathBuf { - get_path_for_executable("rustfmt") -} - -/// Return a `PathBuf` to use for the given executable. -/// -/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that -/// gives a valid Cargo executable; or it may return a full path to a valid -/// Cargo. -fn get_path_for_executable(executable_name: &'static str) -> PathBuf { - // The current implementation checks three places for an executable to use: - // 1) Appropriate environment variable (erroring if this is set but not a usable executable) - // example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc - // 2) `$CARGO_HOME/bin/` - // where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) - // example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. - // It seems that this is a reasonable place to try for cargo, rustc, and rustup - // 3) `` - // example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH - let env_var = executable_name.to_ascii_uppercase(); - if let Some(path) = env::var_os(env_var) { - return path.into(); - } - - if let Some(mut path) = get_cargo_home() { - path.push("bin"); - path.push(executable_name); - if let Some(path) = probe_for_binary(path) { - return path; - } - } - - if lookup_in_path(executable_name) { - return executable_name.into(); - } - - executable_name.into() -} - -fn lookup_in_path(exec: &str) -> bool { - let paths = env::var_os("PATH").unwrap_or_default(); - env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary).is_some() +/// Looks up the binary in the cargo home directory if it exists. +fn cargo_proxy(executable_name: &str) -> Option { + let mut path = get_cargo_home()?; + path.push("bin"); + path.push(executable_name); + probe_for_binary(path) } fn get_cargo_home() -> Option { @@ -107,6 +98,11 @@ fn get_cargo_home() -> Option { None } +fn lookup_in_path(exec: &str) -> Option { + let paths = env::var_os("PATH").unwrap_or_default(); + env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary) +} + pub fn probe_for_binary(path: PathBuf) -> Option { let with_extension = match env::consts::EXE_EXTENSION { "" => None, diff --git a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs index 0392ef3cebe96..7eeb10d544af3 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs @@ -123,6 +123,11 @@ impl FileSetConfig { self.n_file_sets } + /// Get the lexicographically ordered vector of the underlying map. + pub fn roots(&self) -> Vec<(Vec, u64)> { + self.map.stream().into_byte_vec() + } + /// Returns the set index for the given `path`. /// /// `scratch_space` is used as a buffer and will be entirely replaced. diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs index 34a85818eb84b..824ce39870330 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs @@ -163,8 +163,8 @@ impl Vfs { /// # Panics /// /// Panics if the id is not present in the `Vfs`. - pub fn file_path(&self, file_id: FileId) -> VfsPath { - self.interner.lookup(file_id).clone() + pub fn file_path(&self, file_id: FileId) -> &VfsPath { + self.interner.lookup(file_id) } /// Returns an iterator over the stored ids and their corresponding paths. diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index f3100ee194e64..af5b4e51ef372 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@