]> git.lizzy.rs Git - rust.git/commitdiff
:arrow_up: rust-analyzer
authorLaurențiu Nicola <lnicola@dend.ro>
Tue, 20 Sep 2022 14:39:17 +0000 (17:39 +0300)
committerLaurențiu Nicola <lnicola@dend.ro>
Tue, 20 Sep 2022 14:39:17 +0000 (17:39 +0300)
76 files changed:
1  2 
src/tools/rust-analyzer/Cargo.lock
src/tools/rust-analyzer/crates/flycheck/Cargo.toml
src/tools/rust-analyzer/crates/flycheck/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
src/tools/rust-analyzer/crates/hir-ty/src/db.rs
src/tools/rust-analyzer/crates/hir-ty/src/display.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
src/tools/rust-analyzer/crates/ide-completion/src/config.rs
src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
src/tools/rust-analyzer/crates/ide-db/Cargo.toml
src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
src/tools/rust-analyzer/crates/ide-db/src/lib.rs
src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
src/tools/rust-analyzer/crates/ide-db/src/search.rs
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
src/tools/rust-analyzer/crates/ide/src/annotations.rs
src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
src/tools/rust-analyzer/crates/ide/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/references.rs
src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
src/tools/rust-analyzer/crates/project-model/src/tests.rs
src/tools/rust-analyzer/crates/project-model/src/workspace.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
src/tools/rust-analyzer/docs/user/generated_config.adoc
src/tools/rust-analyzer/editors/code/package.json
src/tools/rust-analyzer/editors/code/src/commands.ts
src/tools/rust-analyzer/editors/code/src/main.ts

index 9f10d92c4e3ab0dc90c60ff09287ade92fbdff6d,0000000000000000000000000000000000000000..216cf51447fadd00bd93c30d4d0698a5ab818762
mode 100644,000000..100644
--- /dev/null
@@@ -1,2120 -1,0 +1,2122 @@@
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "addr2line"
 +version = "0.17.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
 +dependencies = [
 + "gimli",
 +]
 +
 +[[package]]
 +name = "adler"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 +
 +[[package]]
 +name = "always-assert"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11"
 +dependencies = [
 + "log",
 +]
 +
 +[[package]]
 +name = "ansi_term"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "anyhow"
 +version = "1.0.62"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
 +
 +[[package]]
 +name = "anymap"
 +version = "1.0.0-beta.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72"
 +
 +[[package]]
 +name = "arbitrary"
 +version = "1.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
 +
 +[[package]]
 +name = "arrayvec"
 +version = "0.7.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
 +
 +[[package]]
 +name = "atty"
 +version = "0.2.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "backtrace"
 +version = "0.3.66"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
 +dependencies = [
 + "addr2line",
 + "cc",
 + "cfg-if",
 + "libc",
 + "miniz_oxide",
 + "object",
 + "rustc-demangle",
 +]
 +
 +[[package]]
 +name = "base-db"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "profile",
 + "rustc-hash",
 + "salsa",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tt",
 + "vfs",
 +]
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 +
 +[[package]]
 +name = "camino"
 +version = "1.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo-platform"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo_metadata"
 +version = "0.15.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
 +dependencies = [
 + "camino",
 + "cargo-platform",
 + "semver",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "cc"
 +version = "1.0.73"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 +
 +[[package]]
 +name = "cfg"
 +version = "0.0.0"
 +dependencies = [
 + "arbitrary",
 + "derive_arbitrary",
 + "expect-test",
 + "mbe",
 + "oorandom",
 + "rustc-hash",
 + "syntax",
 + "tt",
 +]
 +
 +[[package]]
 +name = "cfg-if"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 +
 +[[package]]
 +name = "chalk-derive"
 +version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "synstructure",
 +]
 +
 +[[package]]
 +name = "chalk-ir"
 +version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918"
 +dependencies = [
 + "bitflags",
 + "chalk-derive",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "chalk-recursive"
 +version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "chalk-solve",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "chalk-solve"
 +version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "ena",
 + "indexmap",
 + "itertools",
 + "petgraph",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "countme"
 +version = "3.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
 +dependencies = [
 + "dashmap",
 + "once_cell",
 + "rustc-hash",
 +]
 +
 +[[package]]
 +name = "cov-mark"
 +version = "2.0.0-pre.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a"
 +
 +[[package]]
 +name = "crc32fast"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "crossbeam-channel"
 +version = "0.5.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-deque"
 +version = "0.8.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-epoch",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-epoch"
 +version = "0.9.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
 +dependencies = [
 + "autocfg",
 + "cfg-if",
 + "crossbeam-utils",
 + "memoffset",
 + "once_cell",
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
 +version = "0.8.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
 +dependencies = [
 + "cfg-if",
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "dashmap"
 +version = "5.3.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
 +dependencies = [
 + "cfg-if",
 + "hashbrown",
 + "lock_api",
 + "parking_lot_core 0.9.3",
 +]
 +
 +[[package]]
 +name = "derive_arbitrary"
 +version = "1.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "dissimilar"
 +version = "1.0.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"
 +
 +[[package]]
 +name = "dot"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906"
 +
 +[[package]]
 +name = "drop_bomb"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
 +
 +[[package]]
 +name = "either"
 +version = "1.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
 +
 +[[package]]
 +name = "ena"
 +version = "0.14.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
 +dependencies = [
 + "log",
 +]
 +
 +[[package]]
 +name = "expect-test"
 +version = "1.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3"
 +dependencies = [
 + "dissimilar",
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "filetime"
 +version = "0.2.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
 +dependencies = [
 + "cfg-if",
 + "libc",
 + "redox_syscall",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "fixedbitset"
 +version = "0.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 +
 +[[package]]
 +name = "flate2"
 +version = "1.0.24"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
 +dependencies = [
 + "crc32fast",
 + "miniz_oxide",
 +]
 +
 +[[package]]
 +name = "flycheck"
 +version = "0.0.0"
 +dependencies = [
 + "cargo_metadata",
 + "crossbeam-channel",
 + "jod-thread",
 + "paths",
++ "rustc-hash",
 + "serde",
 + "serde_json",
 + "stdx",
 + "toolchain",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "form_urlencoded"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
 +dependencies = [
 + "matches",
 + "percent-encoding",
 +]
 +
 +[[package]]
 +name = "fs_extra"
 +version = "1.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
 +
 +[[package]]
 +name = "fsevent-sys"
 +version = "4.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "fst"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 +
 +[[package]]
 +name = "gimli"
 +version = "0.26.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.12.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 +
 +[[package]]
 +name = "heck"
 +version = "0.3.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
 +dependencies = [
 + "unicode-segmentation",
 +]
 +
 +[[package]]
 +name = "hermit-abi"
 +version = "0.1.19"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "hir"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "cfg",
 + "either",
 + "hir-def",
 + "hir-expand",
 + "hir-ty",
 + "itertools",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-def"
 +version = "0.0.0"
 +dependencies = [
 + "anymap",
 + "arrayvec",
 + "base-db",
 + "bitflags",
 + "cfg",
 + "cov-mark",
 + "dashmap",
 + "drop_bomb",
 + "either",
 + "expect-test",
 + "fst",
 + "hashbrown",
 + "hir-expand",
 + "indexmap",
 + "itertools",
 + "la-arena",
 + "limit",
 + "mbe",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-expand"
 +version = "0.0.0"
 +dependencies = [
 + "base-db",
 + "cfg",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hashbrown",
 + "itertools",
 + "la-arena",
 + "limit",
 + "mbe",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-ty"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "chalk-ir",
 + "chalk-recursive",
 + "chalk-solve",
 + "cov-mark",
 + "ena",
 + "expect-test",
 + "hir-def",
 + "hir-expand",
 + "itertools",
 + "la-arena",
 + "limit",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "scoped-tls",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tracing-subscriber",
 + "tracing-tree",
 + "typed-arena",
 +]
 +
 +[[package]]
 +name = "home"
 +version = "0.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "ide"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "cov-mark",
 + "crossbeam-channel",
 + "dot",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-assists",
 + "ide-completion",
 + "ide-db",
 + "ide-diagnostics",
 + "ide-ssr",
 + "itertools",
 + "oorandom",
 + "profile",
 + "pulldown-cmark",
 + "pulldown-cmark-to-cmark",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 + "toolchain",
 + "tracing",
 + "url",
 +]
 +
 +[[package]]
 +name = "ide-assists"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "profile",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-completion"
 +version = "0.0.0"
 +dependencies = [
 + "base-db",
 + "cov-mark",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "once_cell",
 + "profile",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-db"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "fst",
 + "hir",
 + "indexmap",
 + "itertools",
 + "limit",
++ "memchr",
 + "once_cell",
 + "parser",
 + "profile",
 + "rayon",
 + "rustc-hash",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 + "tracing",
 + "xshell",
 +]
 +
 +[[package]]
 +name = "ide-diagnostics"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "profile",
 + "serde_json",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-ssr"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "parser",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "idna"
 +version = "0.2.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
 +dependencies = [
 + "matches",
 + "unicode-bidi",
 + "unicode-normalization",
 +]
 +
 +[[package]]
 +name = "indexmap"
 +version = "1.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 +dependencies = [
 + "autocfg",
 + "hashbrown",
 +]
 +
 +[[package]]
 +name = "inotify"
 +version = "0.9.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
 +dependencies = [
 + "bitflags",
 + "inotify-sys",
 + "libc",
 +]
 +
 +[[package]]
 +name = "inotify-sys"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "instant"
 +version = "0.1.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "itertools"
 +version = "0.10.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
 +dependencies = [
 + "either",
 +]
 +
 +[[package]]
 +name = "itoa"
 +version = "1.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
 +
 +[[package]]
 +name = "jod-thread"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
 +
 +[[package]]
 +name = "kqueue"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e"
 +dependencies = [
 + "kqueue-sys",
 + "libc",
 +]
 +
 +[[package]]
 +name = "kqueue-sys"
 +version = "1.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
 +dependencies = [
 + "bitflags",
 + "libc",
 +]
 +
 +[[package]]
 +name = "la-arena"
 +version = "0.3.0"
 +
 +[[package]]
 +name = "lazy_static"
 +version = "1.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 +
 +[[package]]
 +name = "libc"
 +version = "0.2.132"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
 +
 +[[package]]
 +name = "libloading"
 +version = "0.7.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
 +dependencies = [
 + "cfg-if",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "libmimalloc-sys"
 +version = "0.1.25"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c"
 +dependencies = [
 + "cc",
 +]
 +
 +[[package]]
 +name = "limit"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "lock_api"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
 +dependencies = [
 + "autocfg",
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "log"
 +version = "0.4.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "lsp-server"
 +version = "0.6.0"
 +dependencies = [
 + "crossbeam-channel",
 + "log",
 + "lsp-types",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "lsp-types"
 +version = "0.93.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734"
 +dependencies = [
 + "bitflags",
 + "serde",
 + "serde_json",
 + "serde_repr",
 + "url",
 +]
 +
 +[[package]]
 +name = "matchers"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
 +dependencies = [
 + "regex-automata",
 +]
 +
 +[[package]]
 +name = "matches"
 +version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
 +
 +[[package]]
 +name = "mbe"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "parser",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 +
 +[[package]]
 +name = "memmap2"
 +version = "0.5.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "memoffset"
 +version = "0.6.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
 +dependencies = [
 + "autocfg",
 +]
 +
 +[[package]]
 +name = "mimalloc"
 +version = "0.1.29"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698"
 +dependencies = [
 + "libmimalloc-sys",
 +]
 +
 +[[package]]
 +name = "miniz_oxide"
 +version = "0.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
 +dependencies = [
 + "adler",
 +]
 +
 +[[package]]
 +name = "mio"
 +version = "0.8.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
 +dependencies = [
 + "libc",
 + "log",
 + "wasi",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "miow"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e"
 +dependencies = [
 + "windows-sys 0.28.0",
 +]
 +
 +[[package]]
 +name = "notify"
 +version = "5.0.0-pre.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693"
 +dependencies = [
 + "bitflags",
 + "crossbeam-channel",
 + "filetime",
 + "fsevent-sys",
 + "inotify",
 + "kqueue",
 + "libc",
 + "mio",
 + "walkdir",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "num_cpus"
 +version = "1.13.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 +]
 +
 +[[package]]
 +name = "object"
 +version = "0.29.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "once_cell"
 +version = "1.13.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
 +
 +[[package]]
 +name = "oorandom"
 +version = "11.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 +
 +[[package]]
 +name = "parking_lot"
 +version = "0.11.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
 +dependencies = [
 + "instant",
 + "lock_api",
 + "parking_lot_core 0.8.5",
 +]
 +
 +[[package]]
 +name = "parking_lot"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 +dependencies = [
 + "lock_api",
 + "parking_lot_core 0.9.3",
 +]
 +
 +[[package]]
 +name = "parking_lot_core"
 +version = "0.8.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
 +dependencies = [
 + "cfg-if",
 + "instant",
 + "libc",
 + "redox_syscall",
 + "smallvec",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "parking_lot_core"
 +version = "0.9.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
 +dependencies = [
 + "cfg-if",
 + "libc",
 + "redox_syscall",
 + "smallvec",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "parser"
 +version = "0.0.0"
 +dependencies = [
 + "drop_bomb",
 + "expect-test",
 + "limit",
 + "rustc-ap-rustc_lexer",
 + "sourcegen",
 +]
 +
 +[[package]]
 +name = "paste"
 +version = "1.0.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
 +
 +[[package]]
 +name = "paths"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "percent-encoding"
 +version = "2.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
 +
 +[[package]]
 +name = "perf-event"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66"
 +dependencies = [
 + "libc",
 + "perf-event-open-sys",
 +]
 +
 +[[package]]
 +name = "perf-event-open-sys"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "petgraph"
 +version = "0.5.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
 +dependencies = [
 + "fixedbitset",
 + "indexmap",
 +]
 +
 +[[package]]
 +name = "pin-project-lite"
 +version = "0.2.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 +
 +[[package]]
 +name = "proc-macro-api"
 +version = "0.0.0"
 +dependencies = [
 + "memmap2",
 + "object",
 + "paths",
 + "profile",
 + "serde",
 + "serde_json",
 + "snap",
 + "stdx",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv"
 +version = "0.0.0"
 +dependencies = [
 + "expect-test",
 + "libloading",
 + "mbe",
 + "memmap2",
 + "object",
 + "paths",
 + "proc-macro-api",
 + "proc-macro-test",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv-cli"
 +version = "0.0.0"
 +dependencies = [
 + "proc-macro-srv",
 +]
 +
 +[[package]]
 +name = "proc-macro-test"
 +version = "0.0.0"
 +dependencies = [
 + "cargo_metadata",
 + "proc-macro-test-impl",
 + "toolchain",
 +]
 +
 +[[package]]
 +name = "proc-macro-test-impl"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "proc-macro2"
 +version = "1.0.43"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
 +dependencies = [
 + "unicode-ident",
 +]
 +
 +[[package]]
 +name = "profile"
 +version = "0.0.0"
 +dependencies = [
 + "cfg-if",
 + "countme",
 + "la-arena",
 + "libc",
 + "once_cell",
 + "perf-event",
 + "tikv-jemalloc-ctl",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "project-model"
 +version = "0.0.0"
 +dependencies = [
 + "anyhow",
 + "base-db",
 + "cargo_metadata",
 + "cfg",
 + "expect-test",
 + "la-arena",
 + "paths",
 + "profile",
 + "rustc-hash",
 + "semver",
 + "serde",
 + "serde_json",
 + "stdx",
 + "toolchain",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "protobuf"
 +version = "3.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7"
 +dependencies = [
 + "once_cell",
 + "protobuf-support",
 + "thiserror",
 +]
 +
 +[[package]]
 +name = "protobuf-support"
 +version = "3.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c"
 +dependencies = [
 + "thiserror",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark"
 +version = "0.9.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
 +dependencies = [
 + "bitflags",
 + "memchr",
 + "unicase",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark-to-cmark"
 +version = "10.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913"
 +dependencies = [
 + "pulldown-cmark",
 +]
 +
 +[[package]]
 +name = "quote"
 +version = "1.0.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
 +dependencies = [
 + "proc-macro2",
 +]
 +
 +[[package]]
 +name = "rayon"
 +version = "1.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
 +dependencies = [
 + "autocfg",
 + "crossbeam-deque",
 + "either",
 + "rayon-core",
 +]
 +
 +[[package]]
 +name = "rayon-core"
 +version = "1.9.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
 +dependencies = [
 + "crossbeam-channel",
 + "crossbeam-deque",
 + "crossbeam-utils",
 + "num_cpus",
 +]
 +
 +[[package]]
 +name = "redox_syscall"
 +version = "0.2.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "regex"
 +version = "1.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
 +dependencies = [
 + "regex-syntax",
 +]
 +
 +[[package]]
 +name = "regex-automata"
 +version = "0.1.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 +dependencies = [
 + "regex-syntax",
 +]
 +
 +[[package]]
 +name = "regex-syntax"
 +version = "0.6.27"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 +
 +[[package]]
 +name = "rowan"
 +version = "0.15.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8"
 +dependencies = [
 + "countme",
 + "hashbrown",
 + "memoffset",
 + "rustc-hash",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "rust-analyzer"
 +version = "0.0.0"
 +dependencies = [
 + "always-assert",
 + "anyhow",
 + "cfg",
 + "crossbeam-channel",
 + "dissimilar",
 + "expect-test",
 + "flycheck",
 + "hir",
 + "hir-def",
 + "hir-ty",
 + "ide",
 + "ide-db",
 + "ide-ssr",
 + "itertools",
 + "jod-thread",
 + "lsp-server",
 + "lsp-types",
 + "mbe",
 + "mimalloc",
 + "num_cpus",
 + "oorandom",
 + "parking_lot 0.12.1",
 + "proc-macro-api",
 + "proc-macro-srv",
 + "profile",
 + "project-model",
 + "rayon",
 + "rustc-hash",
 + "scip",
 + "serde",
 + "serde_json",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "threadpool",
 + "tikv-jemallocator",
 + "toolchain",
 + "tracing",
 + "tracing-log",
 + "tracing-subscriber",
 + "tracing-tree",
 + "tt",
 + "vfs",
 + "vfs-notify",
 + "winapi",
 + "xflags",
 + "xshell",
 +]
 +
 +[[package]]
 +name = "rustc-ap-rustc_lexer"
 +version = "725.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f950742ef8a203aa7661aad3ab880438ddeb7f95d4b837c30d65db1a2c5df68e"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 +
 +[[package]]
 +name = "rustc-hash"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 +
 +[[package]]
 +name = "ryu"
 +version = "1.0.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
 +
 +[[package]]
 +name = "salsa"
 +version = "0.17.0-pre.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a"
 +dependencies = [
 + "crossbeam-utils",
 + "indexmap",
 + "lock_api",
 + "log",
 + "oorandom",
 + "parking_lot 0.11.2",
 + "rustc-hash",
 + "salsa-macros",
 + "smallvec",
 +]
 +
 +[[package]]
 +name = "salsa-macros"
 +version = "0.17.0-pre.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7"
 +dependencies = [
 + "heck",
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "same-file"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
 +dependencies = [
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "scip"
 +version = "0.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b"
 +dependencies = [
 + "protobuf",
 +]
 +
 +[[package]]
 +name = "scoped-tls"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
 +
 +[[package]]
 +name = "scopeguard"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 +
 +[[package]]
 +name = "semver"
 +version = "1.0.13"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde"
 +version = "1.0.143"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
 +version = "1.0.143"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
 +version = "1.0.83"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
 +dependencies = [
 + "indexmap",
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde_repr"
 +version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "sharded-slab"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
 +dependencies = [
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "smallvec"
 +version = "1.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
 +
 +[[package]]
 +name = "smol_str"
 +version = "0.1.23"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "snap"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451"
 +
 +[[package]]
 +name = "sourcegen"
 +version = "0.0.0"
 +dependencies = [
 + "xshell",
 +]
 +
 +[[package]]
 +name = "stdx"
 +version = "0.0.0"
 +dependencies = [
 + "always-assert",
 + "backtrace",
 + "libc",
 + "miow",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "syn"
 +version = "1.0.99"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "unicode-ident",
 +]
 +
 +[[package]]
 +name = "synstructure"
 +version = "0.12.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "syntax"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "expect-test",
 + "indexmap",
 + "itertools",
 + "once_cell",
 + "parser",
 + "proc-macro2",
 + "profile",
 + "quote",
 + "rayon",
 + "rowan",
 + "rustc-ap-rustc_lexer",
 + "rustc-hash",
 + "smol_str",
 + "sourcegen",
 + "stdx",
 + "test-utils",
 + "text-edit",
 + "ungrammar",
 +]
 +
 +[[package]]
 +name = "test-utils"
 +version = "0.0.0"
 +dependencies = [
 + "dissimilar",
 + "profile",
 + "rustc-hash",
 + "stdx",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "text-edit"
 +version = "0.0.0"
 +dependencies = [
 + "itertools",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "text-size"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
 +
 +[[package]]
 +name = "thiserror"
 +version = "1.0.31"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
 +dependencies = [
 + "thiserror-impl",
 +]
 +
 +[[package]]
 +name = "thiserror-impl"
 +version = "1.0.31"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "thread_local"
 +version = "1.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
 +dependencies = [
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "threadpool"
 +version = "1.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
 +dependencies = [
 + "num_cpus",
 +]
 +
 +[[package]]
 +name = "tikv-jemalloc-ctl"
 +version = "0.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1"
 +dependencies = [
 + "libc",
 + "paste",
 + "tikv-jemalloc-sys",
 +]
 +
 +[[package]]
 +name = "tikv-jemalloc-sys"
 +version = "0.5.1+5.3.0-patched"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261"
 +dependencies = [
 + "cc",
 + "fs_extra",
 + "libc",
 +]
 +
 +[[package]]
 +name = "tikv-jemallocator"
 +version = "0.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979"
 +dependencies = [
 + "libc",
 + "tikv-jemalloc-sys",
 +]
 +
 +[[package]]
 +name = "tinyvec"
 +version = "1.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
 +dependencies = [
 + "tinyvec_macros",
 +]
 +
 +[[package]]
 +name = "tinyvec_macros"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 +
 +[[package]]
 +name = "toolchain"
 +version = "0.0.0"
 +dependencies = [
 + "home",
 +]
 +
 +[[package]]
 +name = "tracing"
 +version = "0.1.36"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
 +dependencies = [
 + "cfg-if",
 + "pin-project-lite",
 + "tracing-attributes",
 + "tracing-core",
 +]
 +
 +[[package]]
 +name = "tracing-attributes"
 +version = "0.1.22"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "tracing-core"
 +version = "0.1.29"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
 +dependencies = [
 + "once_cell",
 + "valuable",
 +]
 +
 +[[package]]
 +name = "tracing-log"
 +version = "0.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
 +dependencies = [
 + "lazy_static",
 + "log",
 + "tracing-core",
 +]
 +
 +[[package]]
 +name = "tracing-subscriber"
 +version = "0.3.15"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
 +dependencies = [
 + "matchers",
 + "once_cell",
 + "regex",
 + "sharded-slab",
 + "thread_local",
 + "tracing",
 + "tracing-core",
 + "tracing-log",
 +]
 +
 +[[package]]
 +name = "tracing-tree"
 +version = "0.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453"
 +dependencies = [
 + "ansi_term",
 + "atty",
 + "tracing-core",
 + "tracing-log",
 + "tracing-subscriber",
 +]
 +
 +[[package]]
 +name = "tt"
 +version = "0.0.0"
 +dependencies = [
 + "smol_str",
 + "stdx",
 +]
 +
 +[[package]]
 +name = "typed-arena"
 +version = "2.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
 +
 +[[package]]
 +name = "ungrammar"
 +version = "1.16.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
 +
 +[[package]]
 +name = "unicase"
 +version = "2.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
 +dependencies = [
 + "version_check",
 +]
 +
 +[[package]]
 +name = "unicode-bidi"
 +version = "0.3.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
 +
 +[[package]]
 +name = "unicode-ident"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
 +
 +[[package]]
 +name = "unicode-normalization"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
 +dependencies = [
 + "tinyvec",
 +]
 +
 +[[package]]
 +name = "unicode-segmentation"
 +version = "1.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
 +
 +[[package]]
 +name = "unicode-xid"
 +version = "0.2.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
 +
 +[[package]]
 +name = "url"
 +version = "2.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
 +dependencies = [
 + "form_urlencoded",
 + "idna",
 + "matches",
 + "percent-encoding",
 + "serde",
 +]
 +
 +[[package]]
 +name = "valuable"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 +
 +[[package]]
 +name = "version_check"
 +version = "0.9.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 +
 +[[package]]
 +name = "vfs"
 +version = "0.0.0"
 +dependencies = [
 + "fst",
 + "indexmap",
 + "paths",
 + "rustc-hash",
 + "stdx",
 +]
 +
 +[[package]]
 +name = "vfs-notify"
 +version = "0.0.0"
 +dependencies = [
 + "crossbeam-channel",
 + "jod-thread",
 + "notify",
 + "paths",
 + "tracing",
 + "vfs",
 + "walkdir",
 +]
 +
 +[[package]]
 +name = "walkdir"
 +version = "2.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
 +dependencies = [
 + "same-file",
 + "winapi",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "wasi"
 +version = "0.11.0+wasi-snapshot-preview1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 +dependencies = [
 + "winapi-i686-pc-windows-gnu",
 + "winapi-x86_64-pc-windows-gnu",
 +]
 +
 +[[package]]
 +name = "winapi-i686-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 +
 +[[package]]
 +name = "winapi-util"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "winapi-x86_64-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 +
 +[[package]]
 +name = "windows-sys"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
 +dependencies = [
 + "windows_aarch64_msvc 0.28.0",
 + "windows_i686_gnu 0.28.0",
 + "windows_i686_msvc 0.28.0",
 + "windows_x86_64_gnu 0.28.0",
 + "windows_x86_64_msvc 0.28.0",
 +]
 +
 +[[package]]
 +name = "windows-sys"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
 +dependencies = [
 + "windows_aarch64_msvc 0.36.1",
 + "windows_i686_gnu 0.36.1",
 + "windows_i686_msvc 0.36.1",
 + "windows_x86_64_gnu 0.36.1",
 + "windows_x86_64_msvc 0.36.1",
 +]
 +
 +[[package]]
 +name = "windows_aarch64_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
 +
 +[[package]]
 +name = "windows_aarch64_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 +
 +[[package]]
 +name = "windows_i686_gnu"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
 +
 +[[package]]
 +name = "windows_i686_gnu"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 +
 +[[package]]
 +name = "windows_i686_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
 +
 +[[package]]
 +name = "windows_i686_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 +
 +[[package]]
 +name = "windows_x86_64_gnu"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
 +
 +[[package]]
 +name = "windows_x86_64_gnu"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 +
 +[[package]]
 +name = "windows_x86_64_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
 +
 +[[package]]
 +name = "windows_x86_64_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 +
 +[[package]]
 +name = "write-json"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
 +
 +[[package]]
 +name = "xflags"
 +version = "0.2.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
 +dependencies = [
 + "xflags-macros",
 +]
 +
 +[[package]]
 +name = "xflags-macros"
 +version = "0.2.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
 +
 +[[package]]
 +name = "xshell"
 +version = "0.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981"
 +dependencies = [
 + "xshell-macros",
 +]
 +
 +[[package]]
 +name = "xshell-macros"
 +version = "0.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a"
 +
 +[[package]]
 +name = "xtask"
 +version = "0.1.0"
 +dependencies = [
 + "anyhow",
 + "flate2",
 + "write-json",
 + "xflags",
 + "xshell",
 +]
index d3d180ece512a4a72f3d9dd15d2cb3643391fe44,0000000000000000000000000000000000000000..688e790c5368cdbe67c15b21287681b9e2f5fa22
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,23 @@@
 +[package]
 +name = "flycheck"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +crossbeam-channel = "0.5.5"
 +tracing = "0.1.35"
 +cargo_metadata = "0.15.0"
++rustc-hash = "1.1.0"
 +serde = { version = "1.0.137", features = ["derive"] }
 +serde_json = "1.0.81"
 +jod-thread = "0.1.2"
 +
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
index d9f4ef5b7ff578deceae41a0a1866b15d7dd9753,0000000000000000000000000000000000000000..fdc03f4053a2714b18b0364b58127eb73d195ab9
mode 100644,000000..100644
--- /dev/null
@@@ -1,421 -1,0 +1,427 @@@
-             FlycheckConfig::CustomCommand { command, args } => {
 +//! Flycheck provides the functionality needed to run `cargo check` or
 +//! another compatible command (f.x. clippy) in a background thread and provide
 +//! LSP diagnostics based on the output of the command.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +use std::{
 +    fmt, io,
 +    process::{ChildStderr, ChildStdout, Command, Stdio},
 +    time::Duration,
 +};
 +
 +use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
 +use paths::AbsPathBuf;
++use rustc_hash::FxHashMap;
 +use serde::Deserialize;
 +use stdx::{process::streaming_output, JodChild};
 +
 +pub use cargo_metadata::diagnostic::{
 +    Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
 +    DiagnosticSpanMacroExpansion,
 +};
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum FlycheckConfig {
 +    CargoCommand {
 +        command: String,
 +        target_triple: Option<String>,
 +        all_targets: bool,
 +        no_default_features: bool,
 +        all_features: bool,
 +        features: Vec<String>,
 +        extra_args: Vec<String>,
++        extra_env: FxHashMap<String, String>,
 +    },
 +    CustomCommand {
 +        command: String,
 +        args: Vec<String>,
++        extra_env: FxHashMap<String, String>,
 +    },
 +}
 +
 +impl fmt::Display for FlycheckConfig {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
-             FlycheckConfig::CustomCommand { command, args } => {
++            FlycheckConfig::CustomCommand { command, args, .. } => {
 +                write!(f, "{} {}", command, args.join(" "))
 +            }
 +        }
 +    }
 +}
 +
 +/// Flycheck wraps the shared state and communication machinery used for
 +/// running `cargo check` (or other compatible command) and providing
 +/// diagnostics based on the output.
 +/// The spawned thread is shut down when this struct is dropped.
 +#[derive(Debug)]
 +pub struct FlycheckHandle {
 +    // XXX: drop order is significant
 +    sender: Sender<Restart>,
 +    _thread: jod_thread::JoinHandle,
 +    id: usize,
 +}
 +
 +impl FlycheckHandle {
 +    pub fn spawn(
 +        id: usize,
 +        sender: Box<dyn Fn(Message) + Send>,
 +        config: FlycheckConfig,
 +        workspace_root: AbsPathBuf,
 +    ) -> FlycheckHandle {
 +        let actor = FlycheckActor::new(id, sender, config, workspace_root);
 +        let (sender, receiver) = unbounded::<Restart>();
 +        let thread = jod_thread::Builder::new()
 +            .name("Flycheck".to_owned())
 +            .spawn(move || actor.run(receiver))
 +            .expect("failed to spawn thread");
 +        FlycheckHandle { id, sender, _thread: thread }
 +    }
 +
 +    /// Schedule a re-start of the cargo check worker.
 +    pub fn restart(&self) {
 +        self.sender.send(Restart::Yes).unwrap();
 +    }
 +
 +    /// Stop this cargo check worker.
 +    pub fn cancel(&self) {
 +        self.sender.send(Restart::No).unwrap();
 +    }
 +
 +    pub fn id(&self) -> usize {
 +        self.id
 +    }
 +}
 +
 +pub enum Message {
 +    /// Request adding a diagnostic with fixes included to a file
 +    AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
 +
 +    /// Request check progress notification to client
 +    Progress {
 +        /// Flycheck instance ID
 +        id: usize,
 +        progress: Progress,
 +    },
 +}
 +
 +impl fmt::Debug for Message {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            Message::AddDiagnostic { id, workspace_root, diagnostic } => f
 +                .debug_struct("AddDiagnostic")
 +                .field("id", id)
 +                .field("workspace_root", workspace_root)
 +                .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
 +                .finish(),
 +            Message::Progress { id, progress } => {
 +                f.debug_struct("Progress").field("id", id).field("progress", progress).finish()
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum Progress {
 +    DidStart,
 +    DidCheckCrate(String),
 +    DidFinish(io::Result<()>),
 +    DidCancel,
 +    DidFailToRestart(String),
 +}
 +
 +enum Restart {
 +    Yes,
 +    No,
 +}
 +
 +struct FlycheckActor {
 +    id: usize,
 +    sender: Box<dyn Fn(Message) + Send>,
 +    config: FlycheckConfig,
 +    workspace_root: AbsPathBuf,
 +    /// CargoHandle exists to wrap around the communication needed to be able to
 +    /// run `cargo check` without blocking. Currently the Rust standard library
 +    /// 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.
 +    cargo_handle: Option<CargoHandle>,
 +}
 +
 +enum Event {
 +    Restart(Restart),
 +    CheckEvent(Option<CargoMessage>),
 +}
 +
 +impl FlycheckActor {
 +    fn new(
 +        id: usize,
 +        sender: Box<dyn Fn(Message) + Send>,
 +        config: FlycheckConfig,
 +        workspace_root: AbsPathBuf,
 +    ) -> FlycheckActor {
 +        tracing::info!(%id, ?workspace_root, "Spawning flycheck");
 +        FlycheckActor { id, sender, config, workspace_root, cargo_handle: None }
 +    }
 +    fn progress(&self, progress: Progress) {
 +        self.send(Message::Progress { id: self.id, progress });
 +    }
 +    fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
 +        let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
 +        select! {
 +            recv(inbox) -> msg => msg.ok().map(Event::Restart),
 +            recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
 +        }
 +    }
 +    fn run(mut self, inbox: Receiver<Restart>) {
 +        while let Some(event) = self.next_event(&inbox) {
 +            match event {
 +                Event::Restart(Restart::No) => {
 +                    self.cancel_check_process();
 +                }
 +                Event::Restart(Restart::Yes) => {
 +                    // Cancel the previously spawned process
 +                    self.cancel_check_process();
 +                    while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
 +
 +                    let command = self.check_command();
 +                    tracing::debug!(?command, "will restart flycheck");
 +                    match CargoHandle::spawn(command) {
 +                        Ok(cargo_handle) => {
 +                            tracing::debug!(
 +                                command = ?self.check_command(),
 +                                "did  restart flycheck"
 +                            );
 +                            self.cargo_handle = Some(cargo_handle);
 +                            self.progress(Progress::DidStart);
 +                        }
 +                        Err(error) => {
 +                            self.progress(Progress::DidFailToRestart(format!(
 +                                "Failed to run the following command: {:?} error={}",
 +                                self.check_command(),
 +                                error
 +                            )));
 +                        }
 +                    }
 +                }
 +                Event::CheckEvent(None) => {
 +                    tracing::debug!(flycheck_id = self.id, "flycheck finished");
 +
 +                    // Watcher finished
 +                    let cargo_handle = self.cargo_handle.take().unwrap();
 +                    let res = cargo_handle.join();
 +                    if res.is_err() {
 +                        tracing::error!(
 +                            "Flycheck failed to run the following command: {:?}",
 +                            self.check_command()
 +                        );
 +                    }
 +                    self.progress(Progress::DidFinish(res));
 +                }
 +                Event::CheckEvent(Some(message)) => match message {
 +                    CargoMessage::CompilerArtifact(msg) => {
 +                        self.progress(Progress::DidCheckCrate(msg.target.name));
 +                    }
 +
 +                    CargoMessage::Diagnostic(msg) => {
 +                        self.send(Message::AddDiagnostic {
 +                            id: self.id,
 +                            workspace_root: self.workspace_root.clone(),
 +                            diagnostic: msg,
 +                        });
 +                    }
 +                },
 +            }
 +        }
 +        // If we rerun the thread, we need to discard the previous check results first
 +        self.cancel_check_process();
 +    }
 +
 +    fn cancel_check_process(&mut self) {
 +        if let Some(cargo_handle) = self.cargo_handle.take() {
 +            tracing::debug!(
 +                command = ?self.check_command(),
 +                "did  cancel flycheck"
 +            );
 +            cargo_handle.cancel();
 +            self.progress(Progress::DidCancel);
 +        }
 +    }
 +
 +    fn check_command(&self) -> Command {
 +        let mut cmd = match &self.config {
 +            FlycheckConfig::CargoCommand {
 +                command,
 +                target_triple,
 +                no_default_features,
 +                all_targets,
 +                all_features,
 +                extra_args,
 +                features,
++                extra_env,
 +            } => {
 +                let mut cmd = Command::new(toolchain::cargo());
 +                cmd.arg(command);
 +                cmd.current_dir(&self.workspace_root);
 +                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
 +                    .arg(self.workspace_root.join("Cargo.toml").as_os_str());
 +
 +                if let Some(target) = target_triple {
 +                    cmd.args(&["--target", target.as_str()]);
 +                }
 +                if *all_targets {
 +                    cmd.arg("--all-targets");
 +                }
 +                if *all_features {
 +                    cmd.arg("--all-features");
 +                } else {
 +                    if *no_default_features {
 +                        cmd.arg("--no-default-features");
 +                    }
 +                    if !features.is_empty() {
 +                        cmd.arg("--features");
 +                        cmd.arg(features.join(" "));
 +                    }
 +                }
 +                cmd.args(extra_args);
++                cmd.envs(extra_env);
 +                cmd
 +            }
++            FlycheckConfig::CustomCommand { command, args, extra_env } => {
 +                let mut cmd = Command::new(command);
 +                cmd.args(args);
++                cmd.envs(extra_env);
 +                cmd
 +            }
 +        };
 +        cmd.current_dir(&self.workspace_root);
 +        cmd
 +    }
 +
 +    fn send(&self, check_task: Message) {
 +        (self.sender)(check_task);
 +    }
 +}
 +
 +/// A handle to a cargo process used for fly-checking.
 +struct CargoHandle {
 +    /// The handle to the actual cargo process. As we cannot cancel directly from with
 +    /// a read syscall dropping and therefor terminating the process is our best option.
 +    child: JodChild,
 +    thread: jod_thread::JoinHandle<io::Result<(bool, String)>>,
 +    receiver: Receiver<CargoMessage>,
 +}
 +
 +impl CargoHandle {
 +    fn spawn(mut command: Command) -> std::io::Result<CargoHandle> {
 +        command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
 +        let mut child = JodChild::spawn(command)?;
 +
 +        let stdout = child.stdout.take().unwrap();
 +        let stderr = child.stderr.take().unwrap();
 +
 +        let (sender, receiver) = unbounded();
 +        let actor = CargoActor::new(sender, stdout, stderr);
 +        let thread = jod_thread::Builder::new()
 +            .name("CargoHandle".to_owned())
 +            .spawn(move || actor.run())
 +            .expect("failed to spawn thread");
 +        Ok(CargoHandle { child, thread, receiver })
 +    }
 +
 +    fn cancel(mut self) {
 +        let _ = self.child.kill();
 +        let _ = self.child.wait();
 +    }
 +
 +    fn join(mut self) -> io::Result<()> {
 +        let _ = self.child.kill();
 +        let exit_status = self.child.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: {:?}):\n{}",
 +                exit_status, error
 +            )))
 +        }
 +    }
 +}
 +
 +struct CargoActor {
 +    sender: Sender<CargoMessage>,
 +    stdout: ChildStdout,
 +    stderr: ChildStderr,
 +}
 +
 +impl CargoActor {
 +    fn new(sender: Sender<CargoMessage>, stdout: ChildStdout, stderr: ChildStderr) -> CargoActor {
 +        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 error = String::new();
 +        let mut read_at_least_one_message = false;
 +        let output = streaming_output(
 +            self.stdout,
 +            self.stderr,
 +            &mut |line| {
 +                read_at_least_one_message = true;
 +
 +                // 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();
 +                        }
 +                    }
 +                }
 +            },
 +            &mut |line| {
 +                error.push_str(line);
 +                error.push('\n');
 +            },
 +        );
 +        match output {
 +            Ok(_) => Ok((read_at_least_one_message, error)),
 +            Err(e) => Err(io::Error::new(e.kind(), format!("{:?}: {}", e, error))),
 +        }
 +    }
 +}
 +
 +enum CargoMessage {
 +    CompilerArtifact(cargo_metadata::Artifact),
 +    Diagnostic(Diagnostic),
 +}
 +
 +#[derive(Deserialize)]
 +#[serde(untagged)]
 +enum JsonMessage {
 +    Cargo(cargo_metadata::Message),
 +    Rustc(Diagnostic),
 +}
index 89e961f84fad26f9d22374b16b1711ac2a3c659d,0000000000000000000000000000000000000000..b94b50004093ccdee496da7c23884e9a46428b5b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1134 -1,0 +1,1234 @@@
- use std::iter;
 +//! An algorithm to find a path to refer to a certain item.
 +
- pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
++use std::{cmp::Ordering, iter};
 +
 +use hir_expand::name::{known, AsName, Name};
 +use rustc_hash::FxHashSet;
 +
 +use crate::{
 +    db::DefDatabase,
 +    item_scope::ItemInNs,
 +    nameres::DefMap,
 +    path::{ModPath, PathKind},
 +    visibility::Visibility,
 +    ModuleDefId, ModuleId,
 +};
 +
 +/// Find a path that can be used to refer to a certain item. This can depend on
 +/// *from where* you're referring to the item, hence the `from` parameter.
-     find_path_inner(db, item, from, None)
++pub fn find_path(
++    db: &dyn DefDatabase,
++    item: ItemInNs,
++    from: ModuleId,
++    prefer_no_std: bool,
++) -> Option<ModPath> {
 +    let _p = profile::span("find_path");
-     find_path_inner(db, item, from, Some(prefix_kind))
++    find_path_inner(db, item, from, None, prefer_no_std)
 +}
 +
 +pub fn find_path_prefixed(
 +    db: &dyn DefDatabase,
 +    item: ItemInNs,
 +    from: ModuleId,
 +    prefix_kind: PrefixKind,
++    prefer_no_std: bool,
 +) -> Option<ModPath> {
 +    let _p = profile::span("find_path_prefixed");
- trait ModPathExt {
-     fn starts_with_std(&self) -> bool;
-     fn can_start_with_std(&self) -> bool;
- }
- impl ModPathExt for ModPath {
-     fn starts_with_std(&self) -> bool {
-         self.segments().first() == Some(&known::std)
-     }
-     // Can we replace the first segment with `std::` and still get a valid, identical path?
-     fn can_start_with_std(&self) -> bool {
-         let first_segment = self.segments().first();
-         first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
-     }
- }
- fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
-     if item == ItemInNs::Types(from.into()) {
-         // - if the item is the module we're in, use `self`
-         Some(ModPath::from_segments(PathKind::Super(0), None))
-     } else if let Some(parent_id) = def_map[from.local_id].parent {
-         // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
-         let parent_id = def_map.module_id(parent_id);
-         if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
-             Some(ModPath::from_segments(PathKind::Super(1), None))
-         } else {
-             None
-         }
-     } else {
-         None
-     }
- }
++    find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
 +}
 +
 +const MAX_PATH_LEN: usize = 15;
 +
-     // FIXME: Do fast path for std/core libs?
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum PrefixKind {
 +    /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
 +    /// This is the same as plain, just that paths will start with `self` iprepended f the path
 +    /// starts with an identifier that is not a crate.
 +    BySelf,
 +    /// Causes paths to ignore imports in the local module.
 +    Plain,
 +    /// Causes paths to start with `crate` where applicable, effectively forcing paths to be absolute.
 +    ByCrate,
 +}
 +
 +impl PrefixKind {
 +    #[inline]
 +    fn prefix(self) -> PathKind {
 +        match self {
 +            PrefixKind::BySelf => PathKind::Super(0),
 +            PrefixKind::Plain => PathKind::Plain,
 +            PrefixKind::ByCrate => PathKind::Crate,
 +        }
 +    }
 +
 +    #[inline]
 +    fn is_absolute(&self) -> bool {
 +        self == &PrefixKind::ByCrate
 +    }
 +}
++
 +/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
 +fn find_path_inner(
 +    db: &dyn DefDatabase,
 +    item: ItemInNs,
 +    from: ModuleId,
 +    prefixed: Option<PrefixKind>,
++    prefer_no_std: bool,
 +) -> Option<ModPath> {
-     let mut visited_modules = FxHashSet::default();
++    // - if the item is a builtin, it's in scope
++    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
++        return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
++    }
 +
-     find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
 +    let def_map = from.def_map(db);
- fn find_path_inner_(
++    let crate_root = def_map.crate_root(db);
++    // - if the item is a module, jump straight to module search
++    if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
++        let mut visited_modules = FxHashSet::default();
++        return find_path_for_module(
++            db,
++            &def_map,
++            &mut visited_modules,
++            crate_root,
++            from,
++            module_id,
++            MAX_PATH_LEN,
++            prefixed,
++            prefer_no_std || db.crate_supports_no_std(crate_root.krate),
++        );
++    }
++
++    // - if the item is already in scope, return the name under which it is
++    let scope_name = find_in_scope(db, &def_map, from, item);
++    if prefixed.is_none() {
++        if let Some(scope_name) = scope_name {
++            return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
++        }
++    }
++
++    // - if the item is in the prelude, return the name from there
++    if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
++        return value;
++    }
++
++    if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
++        // - if the item is an enum variant, refer to it via the enum
++        if let Some(mut path) = find_path_inner(
++            db,
++            ItemInNs::Types(variant.parent.into()),
++            from,
++            prefixed,
++            prefer_no_std,
++        ) {
++            let data = db.enum_data(variant.parent);
++            path.push_segment(data.variants[variant.local_id].name.clone());
++            return Some(path);
++        }
++        // If this doesn't work, it seems we have no way of referring to the
++        // enum; that's very weird, but there might still be a reexport of the
++        // variant somewhere
++    }
++
++    let mut visited_modules = FxHashSet::default();
++
++    calculate_best_path(
++        db,
++        &def_map,
++        &mut visited_modules,
++        crate_root,
++        MAX_PATH_LEN,
++        item,
++        from,
++        prefixed,
++        prefer_no_std || db.crate_supports_no_std(crate_root.krate),
++        scope_name,
++    )
 +}
 +
-     item: ItemInNs,
++fn find_path_for_module(
 +    db: &dyn DefDatabase,
 +    def_map: &DefMap,
++    visited_modules: &mut FxHashSet<ModuleId>,
++    crate_root: ModuleId,
 +    from: ModuleId,
-     mut prefixed: Option<PrefixKind>,
-     visited_modules: &mut FxHashSet<ModuleId>,
++    module_id: ModuleId,
 +    max_len: usize,
++    prefixed: Option<PrefixKind>,
++    prefer_no_std: bool,
 +) -> Option<ModPath> {
 +    if max_len == 0 {
 +        return None;
 +    }
 +
 +    // Base cases:
-     let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
-         def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
-     });
 +    // - if the item is already in scope, return the name under which it is
-     // - if the item is a builtin, it's in scope
-     if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
-         return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
-     }
++    let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
 +    if prefixed.is_none() {
 +        if let Some(scope_name) = scope_name {
 +            return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
 +        }
 +    }
 +
-     let crate_root = def_map.crate_root(db);
-     if item == ItemInNs::Types(ModuleDefId::ModuleId(crate_root)) {
 +    // - if the item is the crate root, return `crate`
-         if let modpath @ Some(_) = check_self_super(&def_map, item, from) {
++    if module_id == crate_root {
 +        return Some(ModPath::from_segments(PathKind::Crate, None));
 +    }
 +
++    // - if relative paths are fine, check if we are searching for a parent
 +    if prefixed.filter(PrefixKind::is_absolute).is_none() {
-     if let ItemInNs::Types(ModuleDefId::ModuleId(item)) = item {
-         for (name, &def_id) in root_def_map.extern_prelude() {
-             if item == def_id {
-                 let name = scope_name.unwrap_or_else(|| name.clone());
-                 let name_already_occupied_in_type_ns = def_map
-                     .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
-                         def_map[local_id]
-                             .scope
-                             .type_(&name)
-                             .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
-                     })
-                     .is_some();
-                 let kind = if name_already_occupied_in_type_ns {
-                     cov_mark::hit!(ambiguous_crate_start);
-                     PathKind::Abs
-                 } else {
-                     PathKind::Plain
-                 };
-                 return Some(ModPath::from_segments(kind, Some(name)));
-             }
++        if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
 +            return modpath;
 +        }
 +    }
 +
 +    // - if the item is the crate root of a dependency crate, return the name from the extern prelude
 +    let root_def_map = crate_root.def_map(db);
-     // - if the item is in the prelude, return the name from there
++    for (name, &def_id) in root_def_map.extern_prelude() {
++        if module_id == def_id {
++            let name = scope_name.unwrap_or_else(|| name.clone());
++
++            let name_already_occupied_in_type_ns = def_map
++                .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
++                    def_map[local_id]
++                        .scope
++                        .type_(&name)
++                        .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
++                })
++                .is_some();
++            let kind = if name_already_occupied_in_type_ns {
++                cov_mark::hit!(ambiguous_crate_start);
++                PathKind::Abs
++            } else {
++                PathKind::Plain
++            };
++            return Some(ModPath::from_segments(kind, Some(name)));
 +        }
 +    }
 +
-                 return Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())));
++    if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
++    {
++        return value;
++    }
++    calculate_best_path(
++        db,
++        def_map,
++        visited_modules,
++        crate_root,
++        max_len,
++        ItemInNs::Types(module_id.into()),
++        from,
++        prefixed,
++        prefer_no_std,
++        scope_name,
++    )
++}
++
++fn find_in_scope(
++    db: &dyn DefDatabase,
++    def_map: &DefMap,
++    from: ModuleId,
++    item: ItemInNs,
++) -> Option<Name> {
++    def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
++        def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
++    })
++}
++
++fn find_in_prelude(
++    db: &dyn DefDatabase,
++    root_def_map: &DefMap,
++    item: ItemInNs,
++    from: ModuleId,
++) -> Option<Option<ModPath>> {
 +    if let Some(prelude_module) = root_def_map.prelude() {
 +        // Preludes in block DefMaps are ignored, only the crate DefMap is searched
 +        let prelude_def_map = prelude_module.def_map(db);
 +        let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
 +        if let Some((name, vis)) = prelude_scope.name_of(item) {
 +            if vis.is_visible_from(db, from) {
-     // Recursive case:
-     // - if the item is an enum variant, refer to it via the enum
-     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
-         if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
-             let data = db.enum_data(variant.parent);
-             path.push_segment(data.variants[variant.local_id].name.clone());
-             return Some(path);
++                return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
 +            }
 +        }
 +    }
++    None
++}
 +
-         // If this doesn't work, it seems we have no way of referring to the
-         // enum; that's very weird, but there might still be a reexport of the
-         // variant somewhere
++fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
++    if item == from {
++        // - if the item is the module we're in, use `self`
++        Some(ModPath::from_segments(PathKind::Super(0), None))
++    } else if let Some(parent_id) = def_map[from.local_id].parent {
++        // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
++        let parent_id = def_map.module_id(parent_id);
++        if item == parent_id {
++            Some(ModPath::from_segments(PathKind::Super(1), None))
++        } else {
++            None
 +        }
-     // - otherwise, look for modules containing (reexporting) it and import it from one of those
-     let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
++    } else {
++        None
 +    }
++}
 +
-     let mut best_path_len = max_len;
++fn calculate_best_path(
++    db: &dyn DefDatabase,
++    def_map: &DefMap,
++    visited_modules: &mut FxHashSet<ModuleId>,
++    crate_root: ModuleId,
++    max_len: usize,
++    item: ItemInNs,
++    from: ModuleId,
++    mut prefixed: Option<PrefixKind>,
++    prefer_no_std: bool,
++    scope_name: Option<Name>,
++) -> Option<ModPath> {
++    if max_len <= 1 {
++        return None;
++    }
 +    let mut best_path = None;
-         // FIXME: this should have a fast path that doesn't look through the prelude again?
++    // Recursive case:
++    // - otherwise, look for modules containing (reexporting) it and import it from one of those
 +    if item.krate(db) == Some(from.krate) {
++        let mut best_path_len = max_len;
 +        // Item was defined in the same crate that wants to import it. It cannot be found in any
 +        // dependency in this case.
-             if let Some(mut path) = find_path_inner_(
 +        for (module_id, name) in find_local_import_locations(db, item, from) {
 +            if !visited_modules.insert(module_id) {
 +                cov_mark::hit!(recursive_imports);
 +                continue;
 +            }
-                 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
++            if let Some(mut path) = find_path_for_module(
 +                db,
 +                def_map,
++                visited_modules,
++                crate_root,
 +                from,
-                 visited_modules,
++                module_id,
 +                best_path_len - 1,
 +                prefixed,
-                 let mut path = find_path_inner_(
++                prefer_no_std,
 +            ) {
 +                path.push_segment(name);
 +
 +                let new_path = match best_path {
 +                    Some(best_path) => select_best_path(best_path, path, prefer_no_std),
 +                    None => path,
 +                };
 +                best_path_len = new_path.len();
 +                best_path = Some(new_path);
 +            }
 +        }
 +    } else {
 +        // Item was defined in some upstream crate. This means that it must be exported from one,
 +        // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
 +        // that wants to import it here, but we always prefer to use the external path here.
 +
 +        let crate_graph = db.crate_graph();
 +        let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
 +            let import_map = db.import_map(dep.crate_id);
 +            import_map.import_info_for(item).and_then(|info| {
 +                // Determine best path for containing module and append last segment from `info`.
 +                // FIXME: we should guide this to look up the path locally, or from the same crate again?
-                     ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
-                     best_path_len - 1,
++                let mut path = find_path_for_module(
 +                    db,
 +                    def_map,
++                    visited_modules,
 +                    from,
-                     visited_modules,
++                    crate_root,
++                    info.container,
++                    max_len - 1,
 +                    prefixed,
-     // If the item is declared inside a block expression, don't use a prefix, as we don't handle
-     // that correctly (FIXME).
-     if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
-         if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
++                    prefer_no_std,
 +                )?;
 +                cov_mark::hit!(partially_imported);
 +                path.push_segment(info.path.segments.last()?.clone());
 +                Some(path)
 +            })
 +        });
 +
 +        for path in extern_paths {
 +            let new_path = match best_path {
 +                Some(best_path) => select_best_path(best_path, path, prefer_no_std),
 +                None => path,
 +            };
 +            best_path = Some(new_path);
 +        }
 +    }
++    if let Some(module) = item.module(db) {
++        if module.def_map(db).block_id().is_some() && prefixed.is_some() {
 +            cov_mark::hit!(prefixed_in_block_expression);
 +            prefixed = Some(PrefixKind::Plain);
 +        }
 +    }
-     if old_path.starts_with_std() && new_path.can_start_with_std() {
-         if prefer_no_std {
-             cov_mark::hit!(prefer_no_std_paths);
-             new_path
-         } else {
-             cov_mark::hit!(prefer_std_paths);
-             old_path
 +    match prefixed.map(PrefixKind::prefix) {
 +        Some(prefix) => best_path.or_else(|| {
 +            scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
 +        }),
 +        None => best_path,
 +    }
 +}
 +
 +fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
-     } else if new_path.starts_with_std() && old_path.can_start_with_std() {
-         if prefer_no_std {
-             cov_mark::hit!(prefer_no_std_paths);
-             old_path
-         } else {
-             cov_mark::hit!(prefer_std_paths);
-             new_path
++    const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
++    match (old_path.segments().first(), new_path.segments().first()) {
++        (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
++            let rank = match prefer_no_std {
++                false => |name: &Name| match name {
++                    name if name == &known::core => 0,
++                    name if name == &known::alloc => 0,
++                    name if name == &known::std => 1,
++                    _ => unreachable!(),
++                },
++                true => |name: &Name| match name {
++                    name if name == &known::core => 2,
++                    name if name == &known::alloc => 1,
++                    name if name == &known::std => 0,
++                    _ => unreachable!(),
++                },
++            };
++            let nrank = rank(new);
++            let orank = rank(old);
++            match nrank.cmp(&orank) {
++                Ordering::Less => old_path,
++                Ordering::Equal => {
++                    if new_path.len() < old_path.len() {
++                        new_path
++                    } else {
++                        old_path
++                    }
++                }
++                Ordering::Greater => new_path,
++            }
 +        }
-     } else if new_path.len() < old_path.len() {
-         new_path
-     } else {
-         old_path
++        _ => {
++            if new_path.len() < old_path.len() {
++                new_path
++            } else {
++                old_path
++            }
 +        }
-         let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
 +    }
 +}
 +
++// FIXME: Remove allocations
 +/// Finds locations in `from.krate` from which `item` can be imported by `from`.
 +fn find_local_import_locations(
 +    db: &dyn DefDatabase,
 +    item: ItemInNs,
 +    from: ModuleId,
 +) -> Vec<(ModuleId, Name)> {
 +    let _p = profile::span("find_local_import_locations");
 +
 +    // `from` can import anything below `from` with visibility of at least `from`, and anything
 +    // above `from` with any visibility. That means we do not need to descend into private siblings
 +    // of `from` (and similar).
 +
 +    let def_map = from.def_map(db);
 +
 +    // Compute the initial worklist. We start with all direct child modules of `from` as well as all
 +    // of its (recursive) parent modules.
 +    let data = &def_map[from.local_id];
 +    let mut worklist =
 +        data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
 +    // FIXME: do we need to traverse out of block expressions here?
 +    for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
 +        worklist.push(ancestor);
 +    }
 +
 +    let def_map = def_map.crate_root(db).def_map(db);
 +
 +    let mut seen: FxHashSet<_> = FxHashSet::default();
 +
 +    let mut locations = Vec::new();
 +    while let Some(module) = worklist.pop() {
 +        if !seen.insert(module) {
 +            continue; // already processed this module
 +        }
 +
 +        let ext_def_map;
 +        let data = if module.krate == from.krate {
 +            if module.block.is_some() {
 +                // Re-query the block's DefMap
 +                ext_def_map = module.def_map(db);
 +                &ext_def_map[module.local_id]
 +            } else {
 +                // Reuse the root DefMap
 +                &def_map[module.local_id]
 +            }
 +        } else {
 +            // The crate might reexport a module defined in another crate.
 +            ext_def_map = module.def_map(db);
 +            &ext_def_map[module.local_id]
 +        };
 +
 +        if let Some((name, vis)) = data.scope.name_of(item) {
 +            if vis.is_visible_from(db, from) {
 +                let is_private = match vis {
 +                    Visibility::Module(private_to) => private_to.local_id == module.local_id,
 +                    Visibility::Public => false,
 +                };
 +                let is_original_def = match item.as_module_def_id() {
 +                    Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id),
 +                    None => false,
 +                };
 +
 +                // Ignore private imports. these could be used if we are
 +                // in a submodule of this module, but that's usually not
 +                // what the user wants; and if this module can import
 +                // the item and we're a submodule of it, so can we.
 +                // Also this keeps the cached data smaller.
 +                if !is_private || is_original_def {
 +                    locations.push((module, name.clone()));
 +                }
 +            }
 +        }
 +
 +        // Descend into all modules visible from `from`.
 +        for (ty, vis) in data.scope.types() {
 +            if let ModuleDefId::ModuleId(module) = ty {
 +                if vis.is_visible_from(db, from) {
 +                    worklist.push(module);
 +                }
 +            }
 +        }
 +    }
 +
 +    locations
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use base_db::fixture::WithFixture;
 +    use hir_expand::hygiene::Hygiene;
 +    use syntax::ast::AstNode;
 +
 +    use crate::test_db::TestDB;
 +
 +    use super::*;
 +
 +    /// `code` needs to contain a cursor marker; checks that `find_path` for the
 +    /// item the `path` refers to returns that same path when called from the
 +    /// module the cursor is in.
 +    fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
 +        let (db, pos) = TestDB::with_position(ra_fixture);
 +        let module = db.module_at_position(pos);
 +        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, &Hygiene::new_unhygienic()).unwrap();
 +
 +        let def_map = module.def_map(&db);
 +        let resolved = def_map
 +            .resolve_path(
 +                &db,
 +                module.local_id,
 +                &mod_path,
 +                crate::item_scope::BuiltinShadowMode::Module,
 +            )
 +            .0
 +            .take_types()
 +            .unwrap();
 +
-             "E::A",
-             "E::A",
++        let found_path =
++            find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
 +        assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
 +    }
 +
 +    fn check_found_path(
 +        ra_fixture: &str,
 +        unprefixed: &str,
 +        prefixed: &str,
 +        absolute: &str,
 +        self_prefixed: &str,
 +    ) {
 +        check_found_path_(ra_fixture, unprefixed, None);
 +        check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain));
 +        check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate));
 +        check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf));
 +    }
 +
 +    #[test]
 +    fn same_module() {
 +        check_found_path(
 +            r#"
 +struct S;
 +$0
 +        "#,
 +            "S",
 +            "S",
 +            "crate::S",
 +            "self::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_variant() {
 +        check_found_path(
 +            r#"
 +enum E { A }
 +$0
 +        "#,
 +            "E::A",
 +            "E::A",
-         cov_mark::check!(prefer_std_paths);
++            "crate::E::A",
++            "self::E::A",
 +        );
 +    }
 +
 +    #[test]
 +    fn sub_module() {
 +        check_found_path(
 +            r#"
 +mod foo {
 +    pub struct S;
 +}
 +$0
 +        "#,
 +            "foo::S",
 +            "foo::S",
 +            "crate::foo::S",
 +            "self::foo::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn super_module() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +mod foo;
 +//- /foo.rs
 +mod bar;
 +struct S;
 +//- /foo/bar.rs
 +$0
 +        "#,
 +            "super::S",
 +            "super::S",
 +            "crate::foo::S",
 +            "super::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn self_module() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +mod foo;
 +//- /foo.rs
 +$0
 +        "#,
 +            "self",
 +            "self",
 +            "crate::foo",
 +            "self",
 +        );
 +    }
 +
 +    #[test]
 +    fn crate_root() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +mod foo;
 +//- /foo.rs
 +$0
 +        "#,
 +            "crate",
 +            "crate",
 +            "crate",
 +            "crate",
 +        );
 +    }
 +
 +    #[test]
 +    fn same_crate() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +mod foo;
 +struct S;
 +//- /foo.rs
 +$0
 +        "#,
 +            "crate::S",
 +            "crate::S",
 +            "crate::S",
 +            "crate::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn different_crate() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:std
 +$0
 +//- /std.rs crate:std
 +pub struct S;
 +        "#,
 +            "std::S",
 +            "std::S",
 +            "std::S",
 +            "std::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn different_crate_renamed() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:std
 +extern crate std as std_renamed;
 +$0
 +//- /std.rs crate:std
 +pub struct S;
 +        "#,
 +            "std_renamed::S",
 +            "std_renamed::S",
 +            "std_renamed::S",
 +            "std_renamed::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn partially_imported() {
 +        cov_mark::check!(partially_imported);
 +        // Tests that short paths are used even for external items, when parts of the path are
 +        // already in scope.
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:syntax
 +
 +use syntax::ast;
 +$0
 +
 +//- /lib.rs crate:syntax
 +pub mod ast {
 +    pub enum ModuleItem {
 +        A, B, C,
 +    }
 +}
 +        "#,
 +            "ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +        );
 +
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:syntax
 +$0
 +
 +//- /lib.rs crate:syntax
 +pub mod ast {
 +    pub enum ModuleItem {
 +        A, B, C,
 +    }
 +}
 +        "#,
 +            "syntax::ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +            "syntax::ast::ModuleItem",
 +        );
 +    }
 +
 +    #[test]
 +    fn same_crate_reexport() {
 +        check_found_path(
 +            r#"
 +mod bar {
 +    mod foo { pub(super) struct S; }
 +    pub(crate) use foo::*;
 +}
 +$0
 +        "#,
 +            "bar::S",
 +            "bar::S",
 +            "crate::bar::S",
 +            "self::bar::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn same_crate_reexport_rename() {
 +        check_found_path(
 +            r#"
 +mod bar {
 +    mod foo { pub(super) struct S; }
 +    pub(crate) use foo::S as U;
 +}
 +$0
 +        "#,
 +            "bar::U",
 +            "bar::U",
 +            "crate::bar::U",
 +            "self::bar::U",
 +        );
 +    }
 +
 +    #[test]
 +    fn different_crate_reexport() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:std
 +$0
 +//- /std.rs crate:std deps:core
 +pub use core::S;
 +//- /core.rs crate:core
 +pub struct S;
 +        "#,
 +            "std::S",
 +            "std::S",
 +            "std::S",
 +            "std::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn prelude() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:std
 +$0
 +//- /std.rs crate:std
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub struct S;
 +    }
 +}
 +        "#,
 +            "S",
 +            "S",
 +            "S",
 +            "S",
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_variant_from_prelude() {
 +        let code = r#"
 +//- /main.rs crate:main deps:std
 +$0
 +//- /std.rs crate:std
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub enum Option<T> { Some(T), None }
 +        pub use Option::*;
 +    }
 +}
 +        "#;
 +        check_found_path(code, "None", "None", "None", "None");
 +        check_found_path(code, "Some", "Some", "Some", "Some");
 +    }
 +
 +    #[test]
 +    fn shortest_path() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +pub mod foo;
 +pub mod baz;
 +struct S;
 +$0
 +//- /foo.rs
 +pub mod bar { pub struct S; }
 +//- /baz.rs
 +pub use crate::foo::bar::S;
 +        "#,
 +            "baz::S",
 +            "baz::S",
 +            "crate::baz::S",
 +            "self::baz::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn discount_private_imports() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +mod foo;
 +pub mod bar { pub struct S; }
 +use bar::S;
 +//- /foo.rs
 +$0
 +        "#,
 +            // crate::S would be shorter, but using private imports seems wrong
 +            "crate::bar::S",
 +            "crate::bar::S",
 +            "crate::bar::S",
 +            "crate::bar::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn import_cycle() {
 +        check_found_path(
 +            r#"
 +//- /main.rs
 +pub mod foo;
 +pub mod bar;
 +pub mod baz;
 +//- /bar.rs
 +$0
 +//- /foo.rs
 +pub use super::baz;
 +pub struct S;
 +//- /baz.rs
 +pub use super::foo;
 +        "#,
 +            "crate::foo::S",
 +            "crate::foo::S",
 +            "crate::foo::S",
 +            "crate::foo::S",
 +        );
 +    }
 +
 +    #[test]
 +    fn prefer_std_paths_over_alloc() {
-         cov_mark::check!(prefer_no_std_paths);
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:alloc,std
 +$0
 +
 +//- /std.rs crate:std deps:alloc
 +pub mod sync {
 +    pub use alloc::sync::Arc;
 +}
 +
 +//- /zzz.rs crate:alloc
 +pub mod sync {
 +    pub struct Arc;
 +}
 +        "#,
 +            "std::sync::Arc",
 +            "std::sync::Arc",
 +            "std::sync::Arc",
 +            "std::sync::Arc",
 +        );
 +    }
 +
 +    #[test]
 +    fn prefer_core_paths_over_std() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:core,std
 +#![no_std]
 +
 +$0
 +
 +//- /std.rs crate:std deps:core
 +
 +pub mod fmt {
 +    pub use core::fmt::Error;
 +}
 +
 +//- /zzz.rs crate:core
 +
 +pub mod fmt {
 +    pub struct Error;
 +}
 +        "#,
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +        );
 +
 +        // Should also work (on a best-effort basis) if `no_std` is conditional.
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:core,std
 +#![cfg_attr(not(test), no_std)]
 +
 +$0
 +
 +//- /std.rs crate:std deps:core
 +
 +pub mod fmt {
 +    pub use core::fmt::Error;
 +}
 +
 +//- /zzz.rs crate:core
 +
 +pub mod fmt {
 +    pub struct Error;
 +}
 +        "#,
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +            "core::fmt::Error",
 +        );
 +    }
 +
 +    #[test]
 +    fn prefer_alloc_paths_over_std() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:alloc,std
 +#![no_std]
 +
 +$0
 +
 +//- /std.rs crate:std deps:alloc
 +
 +pub mod sync {
 +    pub use alloc::sync::Arc;
 +}
 +
 +//- /zzz.rs crate:alloc
 +
 +pub mod sync {
 +    pub struct Arc;
 +}
 +            "#,
 +            "alloc::sync::Arc",
 +            "alloc::sync::Arc",
 +            "alloc::sync::Arc",
 +            "alloc::sync::Arc",
 +        );
 +    }
 +
 +    #[test]
 +    fn prefer_shorter_paths_if_not_alloc() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:megaalloc,std
 +$0
 +
 +//- /std.rs crate:std deps:megaalloc
 +pub mod sync {
 +    pub use megaalloc::sync::Arc;
 +}
 +
 +//- /zzz.rs crate:megaalloc
 +pub struct Arc;
 +            "#,
 +            "megaalloc::Arc",
 +            "megaalloc::Arc",
 +            "megaalloc::Arc",
 +            "megaalloc::Arc",
 +        );
 +    }
 +
 +    #[test]
 +    fn builtins_are_in_scope() {
 +        let code = r#"
 +$0
 +
 +pub mod primitive {
 +    pub use u8;
 +}
 +        "#;
 +        check_found_path(code, "u8", "u8", "u8", "u8");
 +        check_found_path(code, "u16", "u16", "u16", "u16");
 +    }
 +
 +    #[test]
 +    fn inner_items() {
 +        check_found_path(
 +            r#"
 +fn main() {
 +    struct Inner {}
 +    $0
 +}
 +        "#,
 +            "Inner",
 +            "Inner",
 +            "Inner",
 +            "Inner",
 +        );
 +    }
 +
 +    #[test]
 +    fn inner_items_from_outer_scope() {
 +        check_found_path(
 +            r#"
 +fn main() {
 +    struct Struct {}
 +    {
 +        $0
 +    }
 +}
 +        "#,
 +            "Struct",
 +            "Struct",
 +            "Struct",
 +            "Struct",
 +        );
 +    }
 +
 +    #[test]
 +    fn inner_items_from_inner_module() {
 +        cov_mark::check!(prefixed_in_block_expression);
 +        check_found_path(
 +            r#"
 +fn main() {
 +    mod module {
 +        struct Struct {}
 +    }
 +    {
 +        $0
 +    }
 +}
 +        "#,
 +            "module::Struct",
 +            "module::Struct",
 +            "module::Struct",
 +            "module::Struct",
 +        );
 +    }
 +
 +    #[test]
 +    fn outer_items_with_inner_items_present() {
 +        check_found_path(
 +            r#"
 +mod module {
 +    pub struct CompleteMe;
 +}
 +
 +fn main() {
 +    fn inner() {}
 +    $0
 +}
 +            "#,
 +            // FIXME: these could use fewer/better prefixes
 +            "module::CompleteMe",
 +            "crate::module::CompleteMe",
 +            "crate::module::CompleteMe",
 +            "crate::module::CompleteMe",
 +        )
 +    }
 +
 +    #[test]
 +    fn from_inside_module() {
 +        // This worked correctly, but the test suite logic was broken.
 +        cov_mark::check!(submodule_in_testdb);
 +        check_found_path(
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    fn bar() {
 +        $0
 +    }
 +}
 +            "#,
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +        )
 +    }
 +
 +    #[test]
 +    fn from_inside_module_with_inner_items() {
 +        check_found_path(
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    fn bar() {
 +        fn inner() {}
 +        $0
 +    }
 +}
 +            "#,
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +            "crate::baz::Foo",
 +        )
 +    }
 +
 +    #[test]
 +    fn recursive_pub_mod_reexport() {
 +        cov_mark::check!(recursive_imports);
 +        check_found_path(
 +            r#"
 +fn main() {
 +    let _ = 22_i32.as_name$0();
 +}
 +
 +pub mod name {
 +    pub trait AsName {
 +        fn as_name(&self) -> String;
 +    }
 +    impl AsName for i32 {
 +        fn as_name(&self) -> String {
 +            format!("Name: {}", self)
 +        }
 +    }
 +    pub use crate::name;
 +}
 +"#,
 +            "name::AsName",
 +            "name::AsName",
 +            "crate::name::AsName",
 +            "self::name::AsName",
 +        );
 +    }
 +
 +    #[test]
 +    fn extern_crate() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:dep
 +$0
 +//- /dep.rs crate:dep
 +"#,
 +            "dep",
 +            "dep",
 +            "dep",
 +            "dep",
 +        );
 +
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn f() {
 +    fn inner() {}
 +    $0
 +}
 +//- /dep.rs crate:dep
 +"#,
 +            "dep",
 +            "dep",
 +            "dep",
 +            "dep",
 +        );
 +    }
 +
 +    #[test]
 +    fn prelude_with_inner_items() {
 +        check_found_path(
 +            r#"
 +//- /main.rs crate:main deps:std
 +fn f() {
 +    fn inner() {}
 +    $0
 +}
 +//- /std.rs crate:std
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub enum Option { None }
 +        pub use Option::*;
 +    }
 +}
 +        "#,
 +            "None",
 +            "None",
 +            "None",
 +            "None",
 +        );
 +    }
 +}
index a11a92204c15c29c788a4d134e71e681595e466c,0000000000000000000000000000000000000000..7721221c444758a23d2d4d45c06d692657fbe6fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,464 -1,0 +1,471 @@@
- #[derive(Copy, Clone)]
 +//! Describes items defined or visible (ie, imported) in a certain scope.
 +//! This is shared between modules and blocks.
 +
 +use std::collections::hash_map::Entry;
 +
 +use base_db::CrateId;
 +use hir_expand::{name::Name, AstId, MacroCallId};
 +use itertools::Itertools;
 +use once_cell::sync::Lazy;
 +use profile::Count;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use smallvec::{smallvec, SmallVec};
 +use stdx::format_to;
 +use syntax::ast;
 +
 +use crate::{
 +    attr::AttrId, db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType,
 +    ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
 +};
 +
-                             if $glob_imports.$field.contains(&$lookup)
-                                 && matches!($def_import_type, ImportType::Named) =>
++#[derive(Copy, Clone, Debug)]
 +pub(crate) enum ImportType {
 +    Glob,
 +    Named,
 +}
 +
 +#[derive(Debug, Default)]
 +pub struct PerNsGlobImports {
 +    types: FxHashSet<(LocalModuleId, Name)>,
 +    values: FxHashSet<(LocalModuleId, Name)>,
 +    macros: FxHashSet<(LocalModuleId, Name)>,
 +}
 +
 +#[derive(Debug, Default, PartialEq, Eq)]
 +pub struct ItemScope {
 +    _c: Count<Self>,
 +
 +    /// Defs visible in this scope. This includes `declarations`, but also
 +    /// imports.
 +    types: FxHashMap<Name, (ModuleDefId, Visibility)>,
 +    values: FxHashMap<Name, (ModuleDefId, Visibility)>,
 +    macros: FxHashMap<Name, (MacroId, Visibility)>,
 +    unresolved: FxHashSet<Name>,
 +
 +    /// The defs declared in this scope. Each def has a single scope where it is
 +    /// declared.
 +    declarations: Vec<ModuleDefId>,
 +
 +    impls: Vec<ImplId>,
 +    unnamed_consts: Vec<ConstId>,
 +    /// Traits imported via `use Trait as _;`.
 +    unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
 +    /// Macros visible in current module in legacy textual scope
 +    ///
 +    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
 +    /// If it yields no result, then it turns to module scoped `macros`.
 +    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
 +    /// and only normal scoped `macros` will be searched in.
 +    ///
 +    /// Note that this automatically inherit macros defined textually before the definition of module itself.
 +    ///
 +    /// Module scoped macros will be inserted into `items` instead of here.
 +    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
 +    // be all resolved to the last one defined if shadowing happens.
 +    legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>,
 +    /// The derive macro invocations in this scope.
 +    attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
 +    /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
 +    /// paired with the derive macro invocations for the specific attribute.
 +    derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +struct DeriveMacroInvocation {
 +    attr_id: AttrId,
 +    attr_call_id: MacroCallId,
 +    derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
 +}
 +
 +pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
 +    BuiltinType::ALL
 +        .iter()
 +        .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
 +        .collect()
 +});
 +
 +/// Shadow mode for builtin type which can be shadowed by module.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 +pub(crate) enum BuiltinShadowMode {
 +    /// Prefer user-defined modules (or other types) over builtins.
 +    Module,
 +    /// Prefer builtins over user-defined modules (but not other types).
 +    Other,
 +}
 +
 +/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
 +/// Other methods will only resolve values, types and module scoped macros only.
 +impl ItemScope {
 +    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
 +        // FIXME: shadowing
 +        self.types
 +            .keys()
 +            .chain(self.values.keys())
 +            .chain(self.macros.keys())
 +            .chain(self.unresolved.iter())
 +            .sorted()
 +            .unique()
 +            .map(move |name| (name, self.get(name)))
 +    }
 +
 +    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
 +        self.declarations.iter().copied()
 +    }
 +
 +    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
 +        self.impls.iter().copied()
 +    }
 +
 +    pub fn values(
 +        &self,
 +    ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
 +        self.values.values().copied()
 +    }
 +
 +    pub fn types(
 +        &self,
 +    ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
 +        self.types.values().copied()
 +    }
 +
 +    pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
 +        self.unnamed_consts.iter().copied()
 +    }
 +
 +    /// Iterate over all module scoped macros
 +    pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
 +        self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
 +    }
 +
 +    /// Iterate over all legacy textual scoped macros visible at the end of the module
 +    pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
 +        self.legacy_macros.iter().map(|(name, def)| (name, &**def))
 +    }
 +
 +    /// Get a name from current module scope, legacy macros are not included
 +    pub(crate) fn get(&self, name: &Name) -> PerNs {
 +        PerNs {
 +            types: self.types.get(name).copied(),
 +            values: self.values.get(name).copied(),
 +            macros: self.macros.get(name).copied(),
 +        }
 +    }
 +
 +    pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
 +        self.types.get(name).copied()
 +    }
 +
 +    /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
 +    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
 +        let (def, mut iter) = match item {
 +            ItemInNs::Macros(def) => {
 +                return self
 +                    .macros
 +                    .iter()
 +                    .find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)));
 +            }
 +            ItemInNs::Types(def) => (def, self.types.iter()),
 +            ItemInNs::Values(def) => (def, self.values.iter()),
 +        };
 +        iter.find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)))
 +    }
 +
 +    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
 +        self.types
 +            .values()
 +            .filter_map(|&(def, _)| match def {
 +                ModuleDefId::TraitId(t) => Some(t),
 +                _ => None,
 +            })
 +            .chain(self.unnamed_trait_imports.keys().copied())
 +    }
 +
 +    pub(crate) fn declare(&mut self, def: ModuleDefId) {
 +        self.declarations.push(def)
 +    }
 +
 +    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
 +        self.legacy_macros.get(name).map(|it| &**it)
 +    }
 +
 +    pub(crate) fn define_impl(&mut self, imp: ImplId) {
 +        self.impls.push(imp)
 +    }
 +
 +    pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
 +        self.unnamed_consts.push(konst);
 +    }
 +
 +    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroId) {
 +        self.legacy_macros.entry(name).or_default().push(mac);
 +    }
 +
 +    pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
 +        self.attr_macros.insert(item, call);
 +    }
 +
 +    pub(crate) fn attr_macro_invocs(
 +        &self,
 +    ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
 +        self.attr_macros.iter().map(|(k, v)| (*k, *v))
 +    }
 +
 +    pub(crate) fn set_derive_macro_invoc(
 +        &mut self,
 +        adt: AstId<ast::Adt>,
 +        call: MacroCallId,
 +        id: AttrId,
 +        idx: usize,
 +    ) {
 +        if let Some(derives) = self.derive_macros.get_mut(&adt) {
 +            if let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
 +                derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id)
 +            {
 +                derive_call_ids[idx] = Some(call);
 +            }
 +        }
 +    }
 +
 +    /// We are required to set this up front as derive invocation recording happens out of order
 +    /// due to the fixed pointer iteration loop being able to record some derives later than others
 +    /// independent of their indices.
 +    pub(crate) fn init_derive_attribute(
 +        &mut self,
 +        adt: AstId<ast::Adt>,
 +        attr_id: AttrId,
 +        attr_call_id: MacroCallId,
 +        len: usize,
 +    ) {
 +        self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
 +            attr_id,
 +            attr_call_id,
 +            derive_call_ids: smallvec![None; len],
 +        });
 +    }
 +
 +    pub(crate) fn derive_macro_invocs(
 +        &self,
 +    ) -> impl Iterator<
 +        Item = (
 +            AstId<ast::Adt>,
 +            impl Iterator<Item = (AttrId, MacroCallId, &[Option<MacroCallId>])>,
 +        ),
 +    > + '_ {
 +        self.derive_macros.iter().map(|(k, v)| {
 +            (
 +                *k,
 +                v.iter().map(|DeriveMacroInvocation { attr_id, attr_call_id, derive_call_ids }| {
 +                    (*attr_id, *attr_call_id, &**derive_call_ids)
 +                }),
 +            )
 +        })
 +    }
 +
 +    pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
 +        self.unnamed_trait_imports.get(&tr).copied()
 +    }
 +
 +    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
 +        self.unnamed_trait_imports.insert(tr, vis);
 +    }
 +
 +    pub(crate) fn push_res_with_import(
 +        &mut self,
 +        glob_imports: &mut PerNsGlobImports,
 +        lookup: (LocalModuleId, Name),
 +        def: PerNs,
 +        def_import_type: ImportType,
 +    ) -> bool {
 +        let mut changed = false;
 +
 +        macro_rules! check_changed {
 +            (
 +                $changed:ident,
 +                ( $this:ident / $def:ident ) . $field:ident,
 +                $glob_imports:ident [ $lookup:ident ],
 +                $def_import_type:ident
 +            ) => {{
 +                if let Some(fld) = $def.$field {
 +                    let existing = $this.$field.entry($lookup.1.clone());
 +                    match existing {
 +                        Entry::Vacant(entry) => {
 +                            match $def_import_type {
 +                                ImportType::Glob => {
 +                                    $glob_imports.$field.insert($lookup.clone());
 +                                }
 +                                ImportType::Named => {
 +                                    $glob_imports.$field.remove(&$lookup);
 +                                }
 +                            }
 +
 +                            entry.insert(fld);
 +                            $changed = true;
 +                        }
 +                        Entry::Occupied(mut entry)
-                             cov_mark::hit!(import_shadowed);
-                             $glob_imports.$field.remove(&$lookup);
-                             entry.insert(fld);
-                             $changed = true;
++                            if matches!($def_import_type, ImportType::Named) =>
 +                        {
-             ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
++                            if $glob_imports.$field.remove(&$lookup) {
++                                cov_mark::hit!(import_shadowed);
++                                entry.insert(fld);
++                                $changed = true;
++                            }
 +                        }
 +                        _ => {}
 +                    }
 +                }
 +            }};
 +        }
 +
 +        check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
 +        check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
 +        check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
 +
 +        if def.is_none() && self.unresolved.insert(lookup.1) {
 +            changed = true;
 +        }
 +
 +        changed
 +    }
 +
 +    pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
 +        self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
 +            self.unnamed_trait_imports
 +                .iter()
 +                .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
 +        )
 +    }
 +
 +    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, SmallVec<[MacroId; 1]>> {
 +        self.legacy_macros.clone()
 +    }
 +
 +    /// Marks everything that is not a procedural macro as private to `this_module`.
 +    pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
 +        self.types
 +            .values_mut()
 +            .chain(self.values.values_mut())
 +            .map(|(_, v)| v)
 +            .chain(self.unnamed_trait_imports.values_mut())
 +            .for_each(|vis| *vis = Visibility::Module(this_module));
 +
 +        for (mac, vis) in self.macros.values_mut() {
 +            if let MacroId::ProcMacroId(_) = mac {
 +                // FIXME: Technically this is insufficient since reexports of proc macros are also
 +                // forbidden. Practically nobody does that.
 +                continue;
 +            }
 +
 +            *vis = Visibility::Module(this_module);
 +        }
 +    }
 +
 +    pub(crate) fn dump(&self, buf: &mut String) {
 +        let mut entries: Vec<_> = self.resolutions().collect();
 +        entries.sort_by_key(|(name, _)| name.clone());
 +
 +        for (name, def) in entries {
 +            format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
 +
 +            if def.types.is_some() {
 +                buf.push_str(" t");
 +            }
 +            if def.values.is_some() {
 +                buf.push_str(" v");
 +            }
 +            if def.macros.is_some() {
 +                buf.push_str(" m");
 +            }
 +            if def.is_none() {
 +                buf.push_str(" _");
 +            }
 +
 +            buf.push('\n');
 +        }
 +    }
 +
 +    pub(crate) fn shrink_to_fit(&mut self) {
 +        // Exhaustive match to require handling new fields.
 +        let Self {
 +            _c: _,
 +            types,
 +            values,
 +            macros,
 +            unresolved,
 +            declarations,
 +            impls,
 +            unnamed_consts,
 +            unnamed_trait_imports,
 +            legacy_macros,
 +            attr_macros,
 +            derive_macros,
 +        } = self;
 +        types.shrink_to_fit();
 +        values.shrink_to_fit();
 +        macros.shrink_to_fit();
 +        unresolved.shrink_to_fit();
 +        declarations.shrink_to_fit();
 +        impls.shrink_to_fit();
 +        unnamed_consts.shrink_to_fit();
 +        unnamed_trait_imports.shrink_to_fit();
 +        legacy_macros.shrink_to_fit();
 +        attr_macros.shrink_to_fit();
 +        derive_macros.shrink_to_fit();
 +    }
 +}
 +
 +impl PerNs {
 +    pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
 +        match def {
 +            ModuleDefId::ModuleId(_) => PerNs::types(def, v),
 +            ModuleDefId::FunctionId(_) => PerNs::values(def, v),
 +            ModuleDefId::AdtId(adt) => match adt {
 +                AdtId::UnionId(_) => PerNs::types(def, v),
 +                AdtId::EnumId(_) => PerNs::types(def, v),
 +                AdtId::StructId(_) => {
 +                    if has_constructor {
 +                        PerNs::both(def, def, v)
 +                    } else {
 +                        PerNs::types(def, v)
 +                    }
 +                }
 +            },
 +            ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
 +            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
 +            ModuleDefId::TraitId(_) => PerNs::types(def, v),
 +            ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
 +            ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
 +            ModuleDefId::MacroId(mac) => PerNs::macros(mac, v),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum ItemInNs {
 +    Types(ModuleDefId),
 +    Values(ModuleDefId),
 +    Macros(MacroId),
 +}
 +
 +impl ItemInNs {
 +    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
 +        match self {
 +            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
 +            ItemInNs::Macros(_) => None,
 +        }
 +    }
 +
 +    /// Returns the crate defining this item (or `None` if `self` is built-in).
 +    pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
 +        match self {
++            ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate),
 +        }
 +    }
++
++    pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
++        match self {
++            ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
++            ItemInNs::Macros(id) => Some(id.module(db)),
++        }
++    }
 +}
index 495bbe4579f00780774fc970110130f7fdd0ddb3,0000000000000000000000000000000000000000..9242b48c59319a89cad17f21d4b431eccf52fa4d
mode 100644,000000..100644
--- /dev/null
@@@ -1,2214 -1,0 +1,2215 @@@
 +//! The core of the module-level name resolution algorithm.
 +//!
 +//! `DefCollector::collect` contains the fixed-point iteration loop which
 +//! resolves imports and expands macros.
 +
 +use std::{iter, mem};
 +
 +use base_db::{CrateId, Edition, FileId};
 +use cfg::{CfgExpr, CfgOptions};
 +use either::Either;
 +use hir_expand::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::find_builtin_attr,
 +    builtin_derive_macro::find_builtin_derive,
 +    builtin_fn_macro::find_builtin_macro,
 +    name::{name, AsName, Name},
 +    proc_macro::ProcMacroExpander,
 +    ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
 +    MacroDefKind,
 +};
 +use itertools::{izip, Itertools};
 +use la_arena::Idx;
 +use limit::Limit;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::always;
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    attr::{Attr, AttrId, Attrs},
 +    attr_macro_as_call_id,
 +    db::DefDatabase,
 +    derive_macro_as_call_id,
 +    item_scope::{ImportType, PerNsGlobImports},
 +    item_tree::{
 +        self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
 +        MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
 +    },
 +    macro_call_as_call_id, macro_id_to_def_id,
 +    nameres::{
 +        diagnostics::DefDiagnostic,
 +        mod_resolution::ModDir,
 +        path_resolution::ReachedFixedPoint,
 +        proc_macro::{ProcMacroDef, ProcMacroKind},
 +        BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
 +    },
 +    path::{ImportAlias, ModPath, PathKind},
 +    per_ns::PerNs,
 +    visibility::{RawVisibility, Visibility},
 +    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
 +    FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
 +    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId,
 +    ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro,
 +};
 +
 +static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
 +static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128);
 +static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
 +
 +pub(super) fn collect_defs(db: &dyn DefDatabase, mut 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];
 +    for dep in &krate.dependencies {
 +        tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
 +        let dep_def_map = db.crate_def_map(dep.crate_id);
 +        let dep_root = dep_def_map.module_id(dep_def_map.root);
 +
 +        deps.insert(dep.as_name(), dep_root.into());
 +
 +        if dep.is_prelude() && !tree_id.is_block() {
 +            def_map.extern_prelude.insert(dep.as_name(), dep_root);
 +        }
 +    }
 +
 +    let cfg_options = &krate.cfg_options;
 +    let proc_macros = match &krate.proc_macro {
 +        Ok(proc_macros) => {
 +            proc_macros
 +                .iter()
 +                .enumerate()
 +                .map(|(idx, it)| {
 +                    // FIXME: a hacky way to create a Name from string.
 +                    let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
 +                    (
 +                        name.as_name(),
 +                        ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
 +                    )
 +                })
 +                .collect()
 +        }
 +        Err(e) => {
 +            def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str());
 +            Vec::new()
 +        }
 +    };
 +    let is_proc_macro = krate.is_proc_macro;
 +
 +    let mut collector = DefCollector {
 +        db,
 +        def_map,
 +        deps,
 +        glob_imports: FxHashMap::default(),
 +        unresolved_imports: Vec::new(),
 +        indeterminate_imports: Vec::new(),
 +        unresolved_macros: Vec::new(),
 +        mod_dirs: FxHashMap::default(),
 +        cfg_options,
 +        proc_macros,
 +        from_glob_import: Default::default(),
 +        skip_attrs: Default::default(),
 +        is_proc_macro,
 +    };
 +    if tree_id.is_block() {
 +        collector.seed_with_inner(tree_id);
 +    } else {
 +        collector.seed_with_top_level();
 +    }
 +    collector.collect();
 +    let mut def_map = collector.finish();
 +    def_map.shrink_to_fit();
 +    def_map
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +enum PartialResolvedImport {
 +    /// None of any namespaces is resolved
 +    Unresolved,
 +    /// One of namespaces is resolved
 +    Indeterminate(PerNs),
 +    /// All namespaces are resolved, OR it comes from other crate
 +    Resolved(PerNs),
 +}
 +
 +impl PartialResolvedImport {
 +    fn namespaces(self) -> PerNs {
 +        match self {
 +            PartialResolvedImport::Unresolved => PerNs::none(),
 +            PartialResolvedImport::Indeterminate(ns) | PartialResolvedImport::Resolved(ns) => ns,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +enum ImportSource {
 +    Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
 +    ExternCrate(ItemTreeId<item_tree::ExternCrate>),
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +struct Import {
 +    path: ModPath,
 +    alias: Option<ImportAlias>,
 +    visibility: RawVisibility,
 +    kind: ImportKind,
 +    is_prelude: bool,
 +    is_extern_crate: bool,
 +    is_macro_use: bool,
 +    source: ImportSource,
 +}
 +
 +impl Import {
 +    fn from_use(
 +        db: &dyn DefDatabase,
 +        krate: CrateId,
 +        tree: &ItemTree,
 +        id: ItemTreeId<item_tree::Import>,
 +    ) -> Vec<Self> {
 +        let it = &tree[id.value];
 +        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
 +        let visibility = &tree[it.visibility];
 +        let is_prelude = attrs.by_key("prelude_import").exists();
 +
 +        let mut res = Vec::new();
 +        it.use_tree.expand(|idx, path, kind, alias| {
 +            res.push(Self {
 +                path,
 +                alias,
 +                visibility: visibility.clone(),
 +                kind,
 +                is_prelude,
 +                is_extern_crate: false,
 +                is_macro_use: false,
 +                source: ImportSource::Import { id, use_tree: idx },
 +            });
 +        });
 +        res
 +    }
 +
 +    fn from_extern_crate(
 +        db: &dyn DefDatabase,
 +        krate: CrateId,
 +        tree: &ItemTree,
 +        id: ItemTreeId<item_tree::ExternCrate>,
 +    ) -> Self {
 +        let it = &tree[id.value];
 +        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
 +        let visibility = &tree[it.visibility];
 +        Self {
 +            path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
 +            alias: it.alias.clone(),
 +            visibility: visibility.clone(),
 +            kind: ImportKind::Plain,
 +            is_prelude: false,
 +            is_extern_crate: true,
 +            is_macro_use: attrs.by_key("macro_use").exists(),
 +            source: ImportSource::ExternCrate(id),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +struct ImportDirective {
 +    module_id: LocalModuleId,
 +    import: Import,
 +    status: PartialResolvedImport,
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +struct MacroDirective {
 +    module_id: LocalModuleId,
 +    depth: usize,
 +    kind: MacroDirectiveKind,
 +    container: ItemContainerId,
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +enum MacroDirectiveKind {
 +    FnLike { ast_id: AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo },
 +    Derive { ast_id: AstIdWithPath<ast::Adt>, derive_attr: AttrId, derive_pos: usize },
 +    Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem, tree: TreeId },
 +}
 +
 +/// Walks the tree of module recursively
 +struct DefCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    def_map: DefMap,
 +    deps: FxHashMap<Name, ModuleId>,
 +    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
 +    unresolved_imports: Vec<ImportDirective>,
 +    indeterminate_imports: Vec<ImportDirective>,
 +    unresolved_macros: Vec<MacroDirective>,
 +    mod_dirs: FxHashMap<LocalModuleId, ModDir>,
 +    cfg_options: &'a CfgOptions,
 +    /// List of procedural macros defined by this crate. This is read from the dynamic library
 +    /// built by the build system, and is the list of proc. macros we can actually expand. It is
 +    /// empty when proc. macro support is disabled (in which case we still do name resolution for
 +    /// them).
 +    proc_macros: Vec<(Name, ProcMacroExpander)>,
 +    is_proc_macro: bool,
 +    from_glob_import: PerNsGlobImports,
 +    /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
 +    /// This map is used to skip all attributes up to and including the one that failed to resolve,
 +    /// in order to not expand them twice.
 +    ///
 +    /// This also stores the attributes to skip when we resolve derive helpers and non-macro
 +    /// non-builtin attributes in general.
 +    skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
 +}
 +
 +impl DefCollector<'_> {
 +    fn seed_with_top_level(&mut self) {
 +        let _p = profile::span("seed_with_top_level");
 +
 +        let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
 +        let item_tree = self.db.file_item_tree(file_id.into());
 +        let module_id = self.def_map.root;
 +
 +        let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
 +        if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
 +            self.inject_prelude(&attrs);
 +
 +            // Process other crate-level attributes.
 +            for attr in &*attrs {
 +                let attr_name = match attr.path.as_ident() {
 +                    Some(name) => name,
 +                    None => continue,
 +                };
 +
 +                if *attr_name == hir_expand::name![recursion_limit] {
 +                    if let Some(limit) = attr.string_value() {
 +                        if let Ok(limit) = limit.parse() {
 +                            self.def_map.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;
 +                    }
 +                    continue;
 +                }
 +
 +                if *attr_name == hir_expand::name![feature] {
 +                    let features =
 +                        attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
 +                            |feat| match feat.segments() {
 +                                [name] => Some(name.to_smol_str()),
 +                                _ => None,
 +                            },
 +                        );
 +                    self.def_map.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] {
 +                    self.def_map.registered_attrs.push(registered_name.to_smol_str());
 +                    cov_mark::hit!(register_attr);
 +                } else {
 +                    self.def_map.registered_tools.push(registered_name.to_smol_str());
 +                    cov_mark::hit!(register_tool);
 +                }
 +            }
 +
 +            ModCollector {
 +                def_collector: self,
 +                macro_depth: 0,
 +                module_id,
 +                tree_id: TreeId::new(file_id.into(), None),
 +                item_tree: &item_tree,
 +                mod_dir: ModDir::root(),
 +            }
 +            .collect_in_top_module(item_tree.top_level_items());
 +        }
 +    }
 +
 +    fn seed_with_inner(&mut self, tree_id: TreeId) {
 +        let item_tree = tree_id.item_tree(self.db);
 +        let module_id = self.def_map.root;
 +
 +        let is_cfg_enabled = item_tree
 +            .top_level_attrs(self.db, self.def_map.krate)
 +            .cfg()
 +            .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false));
 +        if is_cfg_enabled {
 +            ModCollector {
 +                def_collector: self,
 +                macro_depth: 0,
 +                module_id,
 +                tree_id,
 +                item_tree: &item_tree,
 +                mod_dir: ModDir::root(),
 +            }
 +            .collect_in_top_module(item_tree.top_level_items());
 +        }
 +    }
 +
 +    fn resolution_loop(&mut self) {
 +        let _p = profile::span("DefCollector::resolution_loop");
 +
 +        // main name resolution fixed-point loop.
 +        let mut i = 0;
 +        'resolve_attr: loop {
 +            'resolve_macros: loop {
 +                self.db.unwind_if_cancelled();
 +
 +                {
 +                    let _p = profile::span("resolve_imports loop");
 +
 +                    'resolve_imports: loop {
 +                        if self.resolve_imports() == ReachedFixedPoint::Yes {
 +                            break 'resolve_imports;
 +                        }
 +                    }
 +                }
 +                if self.resolve_macros() == ReachedFixedPoint::Yes {
 +                    break 'resolve_macros;
 +                }
 +
 +                i += 1;
 +                if FIXED_POINT_LIMIT.check(i).is_err() {
 +                    tracing::error!("name resolution is stuck");
 +                    break 'resolve_attr;
 +                }
 +            }
 +
 +            if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
 +                break 'resolve_attr;
 +            }
 +        }
 +    }
 +
 +    fn collect(&mut self) {
 +        let _p = profile::span("DefCollector::collect");
 +
 +        self.resolution_loop();
 +
 +        // Resolve all indeterminate resolved imports again
 +        // As some of the macros will expand newly import shadowing partial resolved imports
 +        // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
 +        // correctly
 +        let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| {
 +            ImportDirective { status: PartialResolvedImport::Unresolved, ..directive }
 +        });
 +        self.unresolved_imports.extend(partial_resolved);
 +        self.resolve_imports();
 +
 +        let unresolved_imports = mem::take(&mut self.unresolved_imports);
 +        // show unresolved imports in completion, etc
 +        for directive in &unresolved_imports {
 +            self.record_resolved_import(directive);
 +        }
 +        self.unresolved_imports = unresolved_imports;
 +
 +        if self.is_proc_macro {
 +            // A crate exporting procedural macros is not allowed to export anything else.
 +            //
 +            // 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 = self.def_map.root;
 +            let module_id = self.def_map.module_id(root);
 +            let root = &mut self.def_map.modules[root];
 +            root.scope.censor_non_proc_macros(module_id);
 +        }
 +    }
 +
 +    /// When the fixed-point loop reaches a stable state, we might still have
 +    /// some unresolved attributes left over. This takes one of them, and feeds
 +    /// the item it's applied to back into name resolution.
 +    ///
 +    /// This effectively ignores the fact that the macro is there and just treats the items as
 +    /// normal code.
 +    ///
 +    /// This improves UX for unresolved attributes, and replicates the
 +    /// behavior before we supported proc. attribute macros.
 +    fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
 +        cov_mark::hit!(unresolved_attribute_fallback);
 +
 +        let unresolved_attr =
 +            self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
 +                .kind
 +            {
 +                MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
 +                    self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                        directive.module_id,
 +                        MacroCallKind::Attr {
 +                            ast_id: ast_id.ast_id,
 +                            attr_args: Default::default(),
 +                            invoc_attr_index: attr.id.ast_index,
 +                            is_derive: false,
 +                        },
 +                        attr.path().clone(),
 +                    ));
 +
 +                    self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
 +
 +                    Some((idx, directive, *mod_item, *tree))
 +                }
 +                _ => None,
 +            });
 +
 +        match unresolved_attr {
 +            Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
 +                let item_tree = &tree_id.item_tree(self.db);
 +                let mod_dir = self.mod_dirs[&module_id].clone();
 +                ModCollector {
 +                    def_collector: self,
 +                    macro_depth: depth,
 +                    module_id,
 +                    tree_id,
 +                    item_tree,
 +                    mod_dir,
 +                }
 +                .collect(&[mod_item], container);
 +
 +                self.unresolved_macros.swap_remove(pos);
 +                // Continue name resolution with the new data.
 +                ReachedFixedPoint::No
 +            }
 +            None => ReachedFixedPoint::Yes,
 +        }
 +    }
 +
 +    fn inject_prelude(&mut self, crate_attrs: &Attrs) {
 +        // See compiler/rustc_builtin_macros/src/standard_library_imports.rs
 +
 +        if crate_attrs.by_key("no_core").exists() {
 +            // libcore does not get a prelude.
 +            return;
 +        }
 +
 +        let krate = if crate_attrs.by_key("no_std").exists() {
 +            name![core]
 +        } else {
 +            let std = name![std];
 +            if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
 +                std
 +            } else {
 +                // If `std` does not exist for some reason, fall back to core. This mostly helps
 +                // keep r-a's own tests minimal.
 +                name![core]
 +            }
 +        };
 +
 +        let edition = match self.def_map.edition {
 +            Edition::Edition2015 => name![rust_2015],
 +            Edition::Edition2018 => name![rust_2018],
 +            Edition::Edition2021 => name![rust_2021],
 +        };
 +
 +        let path_kind = match self.def_map.edition {
 +            Edition::Edition2015 => PathKind::Plain,
 +            _ => PathKind::Abs,
 +        };
 +        let path =
 +            ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
 +        // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
 +        // FIXME remove this fallback
 +        let fallback_path =
 +            ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter());
 +
 +        for path in &[path, fallback_path] {
 +            let (per_ns, _) = self.def_map.resolve_path(
 +                self.db,
 +                self.def_map.root,
 +                path,
 +                BuiltinShadowMode::Other,
 +            );
 +
 +            match per_ns.types {
 +                Some((ModuleDefId::ModuleId(m), _)) => {
 +                    self.def_map.prelude = Some(m);
++                    break;
 +                }
 +                types => {
 +                    tracing::debug!(
 +                        "could not resolve prelude path `{}` to module (resolved to {:?})",
 +                        path,
 +                        types
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Adds a definition of procedural macro `name` to the root module.
 +    ///
 +    /// # Notes on procedural macro resolution
 +    ///
 +    /// Procedural macro functionality is provided by the build system: It has to build the proc
 +    /// macro and pass the resulting dynamic library to rust-analyzer.
 +    ///
 +    /// When procedural macro support is enabled, the list of proc macros exported by a crate is
 +    /// known before we resolve names in the crate. This list is stored in `self.proc_macros` and is
 +    /// derived from the dynamic library.
 +    ///
 +    /// However, we *also* would like to be able to at least *resolve* macros on our own, without
 +    /// help by the build system. So, when the macro isn't found in `self.proc_macros`, we instead
 +    /// use a dummy expander that always errors. This comes with the drawback of macros potentially
 +    /// going out of sync with what the build system sees (since we resolve using VFS state, but
 +    /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
 +    fn export_proc_macro(
 +        &mut self,
 +        def: ProcMacroDef,
 +        id: ItemTreeId<item_tree::Function>,
 +        fn_id: FunctionId,
 +        module_id: ModuleId,
 +    ) {
 +        let kind = def.kind.to_basedb_kind();
 +        let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
 +            Some(&(_, expander)) => (expander, kind),
 +            None => (ProcMacroExpander::dummy(self.def_map.krate), kind),
 +        };
 +
 +        let proc_macro_id =
 +            ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db);
 +        self.define_proc_macro(def.name.clone(), proc_macro_id);
 +        if let ProcMacroKind::CustomDerive { helpers } = def.kind {
 +            self.def_map
 +                .exported_derives
 +                .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers);
 +        }
 +        self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
 +    }
 +
 +    /// Define a macro with `macro_rules`.
 +    ///
 +    /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
 +    /// then it is also defined in the root module scope.
 +    /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
 +    ///
 +    /// It is surprising that the macro will never be in the current module scope.
 +    /// These code fails with "unresolved import/macro",
 +    /// ```rust,compile_fail
 +    /// mod m { macro_rules! foo { () => {} } }
 +    /// use m::foo as bar;
 +    /// ```
 +    ///
 +    /// ```rust,compile_fail
 +    /// macro_rules! foo { () => {} }
 +    /// self::foo!();
 +    /// crate::foo!();
 +    /// ```
 +    ///
 +    /// Well, this code compiles, because the plain path `foo` in `use` is searched
 +    /// in the legacy textual scope only.
 +    /// ```rust
 +    /// macro_rules! foo { () => {} }
 +    /// use foo as bar;
 +    /// ```
 +    fn define_macro_rules(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        name: Name,
 +        macro_: MacroRulesId,
 +        export: bool,
 +    ) {
 +        // Textual scoping
 +        self.define_legacy_macro(module_id, name.clone(), macro_.into());
 +
 +        // Module scoping
 +        // In Rust, `#[macro_export]` macros are unconditionally visible at the
 +        // crate root, even if the parent modules is **not** visible.
 +        if export {
 +            let module_id = self.def_map.root;
 +            self.def_map.modules[module_id].scope.declare(macro_.into());
 +            self.update(
 +                module_id,
 +                &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +                Visibility::Public,
 +                ImportType::Named,
 +            );
 +        }
 +    }
 +
 +    /// Define a legacy textual scoped macro in module
 +    ///
 +    /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
 +    /// It will clone all macros from parent legacy scope, whose definition is prior to
 +    /// the definition of current module.
 +    /// And also, `macro_use` on a module will import all legacy macros visible inside to
 +    /// current legacy scope, with possible shadowing.
 +    fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) {
 +        // Always shadowing
 +        self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
 +    }
 +
 +    /// Define a macro 2.0 macro
 +    ///
 +    /// The scoped of macro 2.0 macro is equal to normal function
 +    fn define_macro_def(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        name: Name,
 +        macro_: Macro2Id,
 +        vis: &RawVisibility,
 +    ) {
 +        let vis =
 +            self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
 +        self.def_map.modules[module_id].scope.declare(macro_.into());
 +        self.update(
 +            module_id,
 +            &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +            vis,
 +            ImportType::Named,
 +        );
 +    }
 +
 +    /// Define a proc macro
 +    ///
 +    /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
 +    /// And unconditionally exported.
 +    fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
 +        let module_id = self.def_map.root;
 +        self.def_map.modules[module_id].scope.declare(macro_.into());
 +        self.update(
 +            module_id,
 +            &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +            Visibility::Public,
 +            ImportType::Named,
 +        );
 +    }
 +
 +    /// Import macros from `#[macro_use] extern crate`.
 +    fn import_macros_from_extern_crate(
 +        &mut self,
 +        current_module_id: LocalModuleId,
 +        extern_crate: &item_tree::ExternCrate,
 +    ) {
 +        tracing::debug!(
 +            "importing macros from extern crate: {:?} ({:?})",
 +            extern_crate,
 +            self.def_map.edition,
 +        );
 +
 +        if let Some(m) = self.resolve_extern_crate(&extern_crate.name) {
 +            if m == self.def_map.module_id(current_module_id) {
 +                cov_mark::hit!(ignore_macro_use_extern_crate_self);
 +                return;
 +            }
 +
 +            cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
 +            self.import_all_macros_exported(current_module_id, m.krate);
 +        }
 +    }
 +
 +    /// Import all exported macros from another crate
 +    ///
 +    /// Exported macros are just all macros in the root module scope.
 +    /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
 +    /// created by `use` in the root module, ignoring the visibility of `use`.
 +    fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
 +        let def_map = self.db.crate_def_map(krate);
 +        for (name, def) in def_map[def_map.root].scope.macros() {
 +            // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
 +            self.define_legacy_macro(current_module_id, name.clone(), def);
 +        }
 +    }
 +
 +    /// Tries to resolve every currently unresolved import.
 +    fn resolve_imports(&mut self) -> ReachedFixedPoint {
 +        let mut res = ReachedFixedPoint::Yes;
 +        let imports = mem::take(&mut self.unresolved_imports);
 +
 +        self.unresolved_imports = imports
 +            .into_iter()
 +            .filter_map(|mut directive| {
 +                directive.status = self.resolve_import(directive.module_id, &directive.import);
 +                match directive.status {
 +                    PartialResolvedImport::Indeterminate(_) => {
 +                        self.record_resolved_import(&directive);
 +                        self.indeterminate_imports.push(directive);
 +                        res = ReachedFixedPoint::No;
 +                        None
 +                    }
 +                    PartialResolvedImport::Resolved(_) => {
 +                        self.record_resolved_import(&directive);
 +                        res = ReachedFixedPoint::No;
 +                        None
 +                    }
 +                    PartialResolvedImport::Unresolved => Some(directive),
 +                }
 +            })
 +            .collect();
 +        res
 +    }
 +
 +    fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
 +        let _p = profile::span("resolve_import").detail(|| format!("{}", import.path));
 +        tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
 +        if import.is_extern_crate {
 +            let name = import
 +                .path
 +                .as_ident()
 +                .expect("extern crate should have been desugared to one-element path");
 +
 +            let res = self.resolve_extern_crate(name);
 +
 +            match res {
 +                Some(res) => {
 +                    PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
 +                }
 +                None => PartialResolvedImport::Unresolved,
 +            }
 +        } else {
 +            let res = self.def_map.resolve_path_fp_with_macro(
 +                self.db,
 +                ResolveMode::Import,
 +                module_id,
 +                &import.path,
 +                BuiltinShadowMode::Module,
 +            );
 +
 +            let def = res.resolved_def;
 +            if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
 +                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)),
 +                    );
 +                }
 +            }
 +
 +            // Check whether all namespace is resolved
 +            if def.take_types().is_some()
 +                && def.take_values().is_some()
 +                && def.take_macros().is_some()
 +            {
 +                PartialResolvedImport::Resolved(def)
 +            } else {
 +                PartialResolvedImport::Indeterminate(def)
 +            }
 +        }
 +    }
 +
 +    fn resolve_extern_crate(&self, name: &Name) -> Option<ModuleId> {
 +        if *name == name!(self) {
 +            cov_mark::hit!(extern_crate_self_as);
 +            let root = match self.def_map.block {
 +                Some(_) => {
 +                    let def_map = self.def_map.crate_root(self.db).def_map(self.db);
 +                    def_map.module_id(def_map.root())
 +                }
 +                None => self.def_map.module_id(self.def_map.root()),
 +            };
 +            Some(root)
 +        } else {
 +            self.deps.get(name).copied()
 +        }
 +    }
 +
 +    fn record_resolved_import(&mut self, directive: &ImportDirective) {
 +        let _p = profile::span("record_resolved_import");
 +
 +        let module_id = directive.module_id;
 +        let import = &directive.import;
 +        let mut def = directive.status.namespaces();
 +        let vis = self
 +            .def_map
 +            .resolve_visibility(self.db, module_id, &directive.import.visibility)
 +            .unwrap_or(Visibility::Public);
 +
 +        match import.kind {
 +            ImportKind::Plain | ImportKind::TypeOnly => {
 +                let name = match &import.alias {
 +                    Some(ImportAlias::Alias(name)) => Some(name),
 +                    Some(ImportAlias::Underscore) => None,
 +                    None => match import.path.segments().last() {
 +                        Some(last_segment) => Some(last_segment),
 +                        None => {
 +                            cov_mark::hit!(bogus_paths);
 +                            return;
 +                        }
 +                    },
 +                };
 +
 +                if import.kind == ImportKind::TypeOnly {
 +                    def.values = None;
 +                    def.macros = None;
 +                }
 +
 +                tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 +
 +                // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
 +                if import.is_extern_crate
 +                    && self.def_map.block.is_none()
 +                    && module_id == self.def_map.root
 +                {
 +                    if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
 +                    {
 +                        self.def_map.extern_prelude.insert(name.clone(), def);
 +                    }
 +                }
 +
 +                self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named);
 +            }
 +            ImportKind::Glob => {
 +                tracing::debug!("glob import: {:?}", import);
 +                match def.take_types() {
 +                    Some(ModuleDefId::ModuleId(m)) => {
 +                        if import.is_prelude {
 +                            // Note: This dodgily overrides the injected prelude. The rustc
 +                            // implementation seems to work the same though.
 +                            cov_mark::hit!(std_prelude);
 +                            self.def_map.prelude = Some(m);
 +                        } else if m.krate != self.def_map.krate {
 +                            cov_mark::hit!(glob_across_crates);
 +                            // glob import from other crate => we can just import everything once
 +                            let item_map = m.def_map(self.db);
 +                            let scope = &item_map[m.local_id].scope;
 +
 +                            // Module scoped macros is included
 +                            let items = scope
 +                                .resolutions()
 +                                // only keep visible names...
 +                                .map(|(n, res)| {
 +                                    (n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
 +                                })
 +                                .filter(|(_, res)| !res.is_none())
 +                                .collect::<Vec<_>>();
 +
 +                            self.update(module_id, &items, vis, ImportType::Glob);
 +                        } else {
 +                            // glob import from same crate => we do an initial
 +                            // import, and then need to propagate any further
 +                            // additions
 +                            let def_map;
 +                            let scope = if m.block == self.def_map.block_id() {
 +                                &self.def_map[m.local_id].scope
 +                            } else {
 +                                def_map = m.def_map(self.db);
 +                                &def_map[m.local_id].scope
 +                            };
 +
 +                            // Module scoped macros is included
 +                            let items = scope
 +                                .resolutions()
 +                                // only keep visible names...
 +                                .map(|(n, res)| {
 +                                    (
 +                                        n,
 +                                        res.filter_visibility(|v| {
 +                                            v.is_visible_from_def_map(
 +                                                self.db,
 +                                                &self.def_map,
 +                                                module_id,
 +                                            )
 +                                        }),
 +                                    )
 +                                })
 +                                .filter(|(_, res)| !res.is_none())
 +                                .collect::<Vec<_>>();
 +
 +                            self.update(module_id, &items, vis, ImportType::Glob);
 +                            // record the glob import in case we add further items
 +                            let glob = self.glob_imports.entry(m.local_id).or_default();
 +                            if !glob.iter().any(|(mid, _)| *mid == module_id) {
 +                                glob.push((module_id, vis));
 +                            }
 +                        }
 +                    }
 +                    Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
 +                        cov_mark::hit!(glob_enum);
 +                        // glob import from enum => just import all the variants
 +
 +                        // XXX: urgh, so this works by accident! Here, we look at
 +                        // the enum data, and, in theory, this might require us to
 +                        // look back at the crate_def_map, creating a cycle. For
 +                        // example, `enum E { crate::some_macro!(); }`. Luckily, the
 +                        // only kind of macro that is allowed inside enum is a
 +                        // `cfg_macro`, and we don't need to run name resolution for
 +                        // it, but this is sheer luck!
 +                        let enum_data = self.db.enum_data(e);
 +                        let resolutions = enum_data
 +                            .variants
 +                            .iter()
 +                            .map(|(local_id, variant_data)| {
 +                                let name = variant_data.name.clone();
 +                                let variant = EnumVariantId { parent: e, local_id };
 +                                let res = PerNs::both(variant.into(), variant.into(), vis);
 +                                (Some(name), res)
 +                            })
 +                            .collect::<Vec<_>>();
 +                        self.update(module_id, &resolutions, vis, ImportType::Glob);
 +                    }
 +                    Some(d) => {
 +                        tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
 +                    }
 +                    None => {
 +                        tracing::debug!("glob import {:?} didn't resolve as type", import);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn update(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        resolutions: &[(Option<Name>, PerNs)],
 +        vis: Visibility,
 +        import_type: ImportType,
 +    ) {
 +        self.db.unwind_if_cancelled();
 +        self.update_recursive(module_id, resolutions, vis, import_type, 0)
 +    }
 +
 +    fn update_recursive(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        resolutions: &[(Option<Name>, PerNs)],
 +        // All resolutions are imported with this visibility; the visibilities in
 +        // the `PerNs` values are ignored and overwritten
 +        vis: Visibility,
 +        import_type: ImportType,
 +        depth: usize,
 +    ) {
 +        if GLOB_RECURSION_LIMIT.check(depth).is_err() {
 +            // prevent stack overflows (but this shouldn't be possible)
 +            panic!("infinite recursion in glob imports!");
 +        }
 +        let mut changed = false;
 +
 +        for (name, res) in resolutions {
 +            match name {
 +                Some(name) => {
 +                    let scope = &mut self.def_map.modules[module_id].scope;
 +                    changed |= scope.push_res_with_import(
 +                        &mut self.from_glob_import,
 +                        (module_id, name.clone()),
 +                        res.with_visibility(vis),
 +                        import_type,
 +                    );
 +                }
 +                None => {
 +                    let tr = match res.take_types() {
 +                        Some(ModuleDefId::TraitId(tr)) => tr,
 +                        Some(other) => {
 +                            tracing::debug!("non-trait `_` import of {:?}", other);
 +                            continue;
 +                        }
 +                        None => continue,
 +                    };
 +                    let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
 +                    let should_update = match old_vis {
 +                        None => true,
 +                        Some(old_vis) => {
 +                            let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
 +                                panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
 +                            });
 +
 +                            if max_vis == old_vis {
 +                                false
 +                            } else {
 +                                cov_mark::hit!(upgrade_underscore_visibility);
 +                                true
 +                            }
 +                        }
 +                    };
 +
 +                    if should_update {
 +                        changed = true;
 +                        self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
 +                    }
 +                }
 +            }
 +        }
 +
 +        if !changed {
 +            return;
 +        }
 +        let glob_imports = self
 +            .glob_imports
 +            .get(&module_id)
 +            .into_iter()
 +            .flatten()
 +            .filter(|(glob_importing_module, _)| {
 +                // we know all resolutions have the same visibility (`vis`), so we
 +                // just need to check that once
 +                vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
 +            })
 +            .cloned()
 +            .collect::<Vec<_>>();
 +
 +        for (glob_importing_module, glob_import_vis) in glob_imports {
 +            self.update_recursive(
 +                glob_importing_module,
 +                resolutions,
 +                glob_import_vis,
 +                ImportType::Glob,
 +                depth + 1,
 +            );
 +        }
 +    }
 +
 +    fn resolve_macros(&mut self) -> ReachedFixedPoint {
 +        let mut macros = mem::take(&mut self.unresolved_macros);
 +        let mut resolved = Vec::new();
 +        let mut push_resolved = |directive: &MacroDirective, call_id| {
 +            resolved.push((directive.module_id, directive.depth, directive.container, call_id));
 +        };
 +        let mut res = ReachedFixedPoint::Yes;
 +        macros.retain(|directive| {
 +            let resolver = |path| {
 +                let resolved_res = self.def_map.resolve_path_fp_with_macro(
 +                    self.db,
 +                    ResolveMode::Other,
 +                    directive.module_id,
 +                    &path,
 +                    BuiltinShadowMode::Module,
 +                );
 +                resolved_res
 +                    .resolved_def
 +                    .take_macros()
 +                    .map(|it| (it, macro_id_to_def_id(self.db, it)))
 +            };
 +            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 +
 +            match &directive.kind {
 +                MacroDirectiveKind::FnLike { ast_id, expand_to } => {
 +                    let call_id = macro_call_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *expand_to,
 +                        self.def_map.krate,
 +                        &resolver_def_id,
 +                        &mut |_err| (),
 +                    );
 +                    if let Ok(Ok(call_id)) = call_id {
 +                        push_resolved(directive, call_id);
 +                        res = ReachedFixedPoint::No;
 +                        return false;
 +                    }
 +                }
 +                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
 +                    let id = derive_macro_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *derive_attr,
 +                        *derive_pos as u32,
 +                        self.def_map.krate,
 +                        &resolver,
 +                    );
 +
 +                    if let Ok((macro_id, def_id, call_id)) = id {
 +                        self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc(
 +                            ast_id.ast_id,
 +                            call_id,
 +                            *derive_attr,
 +                            *derive_pos,
 +                        );
 +                        // Record its helper attributes.
 +                        if def_id.krate != self.def_map.krate {
 +                            let def_map = self.db.crate_def_map(def_id.krate);
 +                            if let Some(helpers) = def_map.exported_derives.get(&def_id) {
 +                                self.def_map
 +                                    .derive_helpers_in_scope
 +                                    .entry(ast_id.ast_id.map(|it| it.upcast()))
 +                                    .or_default()
 +                                    .extend(izip!(
 +                                        helpers.iter().cloned(),
 +                                        iter::repeat(macro_id),
 +                                        iter::repeat(call_id),
 +                                    ));
 +                            }
 +                        }
 +
 +                        push_resolved(directive, call_id);
 +                        res = ReachedFixedPoint::No;
 +                        return false;
 +                    }
 +                }
 +                MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
 +                    let &AstIdWithPath { ast_id, ref path } = file_ast_id;
 +                    let file_id = ast_id.file_id;
 +
 +                    let mut recollect_without = |collector: &mut Self| {
 +                        // Remove the original directive since we resolved it.
 +                        let mod_dir = collector.mod_dirs[&directive.module_id].clone();
 +                        collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
 +
 +                        let item_tree = tree.item_tree(self.db);
 +                        ModCollector {
 +                            def_collector: collector,
 +                            macro_depth: directive.depth,
 +                            module_id: directive.module_id,
 +                            tree_id: *tree,
 +                            item_tree: &item_tree,
 +                            mod_dir,
 +                        }
 +                        .collect(&[*mod_item], directive.container);
 +                        res = ReachedFixedPoint::No;
 +                        false
 +                    };
 +
 +                    if let Some(ident) = path.as_ident() {
 +                        if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) {
 +                            if helpers.iter().any(|(it, ..)| it == ident) {
 +                                cov_mark::hit!(resolved_derive_helper);
 +                                // Resolved to derive helper. Collect the item's attributes again,
 +                                // starting after the derive helper.
 +                                return recollect_without(self);
 +                            }
 +                        }
 +                    }
 +
 +                    let def = match resolver_def_id(path.clone()) {
 +                        Some(def) if def.is_attribute() => def,
 +                        _ => return true,
 +                    };
 +                    if matches!(
 +                        def,
 +                        MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. }
 +                        if expander.is_derive()
 +                    ) {
 +                        // Resolved to `#[derive]`
 +
 +                        let item_tree = tree.item_tree(self.db);
 +                        let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
 +                            ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(),
 +                            ModItem::Union(union) => item_tree[union].ast_id().upcast(),
 +                            ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(),
 +                            _ => {
 +                                let diag = DefDiagnostic::invalid_derive_target(
 +                                    directive.module_id,
 +                                    ast_id,
 +                                    attr.id,
 +                                );
 +                                self.def_map.diagnostics.push(diag);
 +                                return recollect_without(self);
 +                            }
 +                        };
 +                        let ast_id = ast_id.with_value(ast_adt_id);
 +
 +                        match attr.parse_path_comma_token_tree() {
 +                            Some(derive_macros) => {
 +                                let mut len = 0;
 +                                for (idx, path) in derive_macros.enumerate() {
 +                                    let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
 +                                    self.unresolved_macros.push(MacroDirective {
 +                                        module_id: directive.module_id,
 +                                        depth: directive.depth + 1,
 +                                        kind: MacroDirectiveKind::Derive {
 +                                            ast_id,
 +                                            derive_attr: attr.id,
 +                                            derive_pos: idx,
 +                                        },
 +                                        container: directive.container,
 +                                    });
 +                                    len = idx;
 +                                }
 +
 +                                // We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
 +                                // This is just a trick to be able to resolve the input to derives as proper paths.
 +                                // Check the comment in [`builtin_attr_macro`].
 +                                let call_id = attr_macro_as_call_id(
 +                                    self.db,
 +                                    file_ast_id,
 +                                    attr,
 +                                    self.def_map.krate,
 +                                    def,
 +                                    true,
 +                                );
 +                                self.def_map.modules[directive.module_id]
 +                                    .scope
 +                                    .init_derive_attribute(ast_id, attr.id, call_id, len + 1);
 +                            }
 +                            None => {
 +                                let diag = DefDiagnostic::malformed_derive(
 +                                    directive.module_id,
 +                                    ast_id,
 +                                    attr.id,
 +                                );
 +                                self.def_map.diagnostics.push(diag);
 +                            }
 +                        }
 +
 +                        return recollect_without(self);
 +                    }
 +
 +                    // Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
 +                    let call_id = attr_macro_as_call_id(
 +                        self.db,
 +                        file_ast_id,
 +                        attr,
 +                        self.def_map.krate,
 +                        def,
 +                        false,
 +                    );
 +                    let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id);
 +
 +                    // If proc attribute macro expansion is disabled, skip expanding it here
 +                    if !self.db.enable_proc_attr_macros() {
 +                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
 +                            directive.module_id,
 +                            loc.kind,
 +                            loc.def.krate,
 +                        ));
 +                        return recollect_without(self);
 +                    }
 +
 +                    // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
 +                    // due to duplicating functions into macro expansions
 +                    if matches!(
 +                        loc.def.kind,
 +                        MacroDefKind::BuiltInAttr(expander, _)
 +                        if expander.is_test() || expander.is_bench()
 +                    ) {
 +                        return recollect_without(self);
 +                    }
 +
 +                    if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
 +                        if exp.is_dummy() {
 +                            // If there's no expander for the proc macro (e.g.
 +                            // because proc macros are disabled, or building the
 +                            // proc macro crate failed), report this and skip
 +                            // expansion like we would if it was disabled
 +                            self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
 +                                directive.module_id,
 +                                loc.kind,
 +                                loc.def.krate,
 +                            ));
 +
 +                            return recollect_without(self);
 +                        }
 +                    }
 +
 +                    self.def_map.modules[directive.module_id]
 +                        .scope
 +                        .add_attr_macro_invoc(ast_id, call_id);
 +
 +                    push_resolved(directive, call_id);
 +                    res = ReachedFixedPoint::No;
 +                    return false;
 +                }
 +            }
 +
 +            true
 +        });
 +        // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
 +        macros.extend(mem::take(&mut self.unresolved_macros));
 +        self.unresolved_macros = macros;
 +
 +        for (module_id, depth, container, macro_call_id) in resolved {
 +            self.collect_macro_expansion(module_id, macro_call_id, depth, container);
 +        }
 +
 +        res
 +    }
 +
 +    fn collect_macro_expansion(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        macro_call_id: MacroCallId,
 +        depth: usize,
 +        container: ItemContainerId,
 +    ) {
 +        if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
 +            cov_mark::hit!(macro_expansion_overflow);
 +            tracing::warn!("macro expansion is too deep");
 +            return;
 +        }
 +        let file_id = macro_call_id.as_file();
 +
 +        // First, fetch the raw expansion result for purposes of error reporting. This goes through
 +        // `macro_expand_error` to avoid depending on the full expansion result (to improve
 +        // incrementality).
 +        let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
 +        let err = self.db.macro_expand_error(macro_call_id);
 +        if let Some(err) = err {
 +            let diag = match err {
 +                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
 +                    always!(krate == loc.def.krate);
 +                    // Missing proc macros are non-fatal, so they are handled specially.
 +                    DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
 +                }
 +                _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
 +            };
 +
 +            self.def_map.diagnostics.push(diag);
 +        }
 +
 +        // Then, fetch and process the item tree. This will reuse the expansion result from above.
 +        let item_tree = self.db.file_item_tree(file_id);
 +        let mod_dir = self.mod_dirs[&module_id].clone();
 +        ModCollector {
 +            def_collector: &mut *self,
 +            macro_depth: depth,
 +            tree_id: TreeId::new(file_id, None),
 +            module_id,
 +            item_tree: &item_tree,
 +            mod_dir,
 +        }
 +        .collect(item_tree.top_level_items(), container);
 +    }
 +
 +    fn finish(mut self) -> DefMap {
 +        // Emit diagnostics for all remaining unexpanded macros.
 +
 +        let _p = profile::span("DefCollector::finish");
 +
 +        for directive in &self.unresolved_macros {
 +            match &directive.kind {
 +                MacroDirectiveKind::FnLike { ast_id, expand_to } => {
 +                    let macro_call_as_call_id = macro_call_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *expand_to,
 +                        self.def_map.krate,
 +                        |path| {
 +                            let resolved_res = self.def_map.resolve_path_fp_with_macro(
 +                                self.db,
 +                                ResolveMode::Other,
 +                                directive.module_id,
 +                                &path,
 +                                BuiltinShadowMode::Module,
 +                            );
 +                            resolved_res
 +                                .resolved_def
 +                                .take_macros()
 +                                .map(|it| macro_id_to_def_id(self.db, it))
 +                        },
 +                        &mut |_| (),
 +                    );
 +                    if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
 +                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                            directive.module_id,
 +                            MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
 +                            path,
 +                        ));
 +                    }
 +                }
 +                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
 +                    self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                        directive.module_id,
 +                        MacroCallKind::Derive {
 +                            ast_id: ast_id.ast_id,
 +                            derive_attr_index: derive_attr.ast_index,
 +                            derive_index: *derive_pos as u32,
 +                        },
 +                        ast_id.path.clone(),
 +                    ));
 +                }
 +                // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them
 +                MacroDirectiveKind::Attr { .. } => {}
 +            }
 +        }
 +
 +        // Emit diagnostics for all remaining unresolved imports.
 +
 +        // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
 +        // resolve. We first emit diagnostics for unresolved extern crates and collect the missing
 +        // crate names. Then we emit diagnostics for unresolved imports, but only if the import
 +        // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
 +        // heuristic, but it works in practice.
 +        let mut diagnosed_extern_crates = FxHashSet::default();
 +        for directive in &self.unresolved_imports {
 +            if let ImportSource::ExternCrate(krate) = directive.import.source {
 +                let item_tree = krate.item_tree(self.db);
 +                let extern_crate = &item_tree[krate.value];
 +
 +                diagnosed_extern_crates.insert(extern_crate.name.clone());
 +
 +                self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
 +                    directive.module_id,
 +                    InFile::new(krate.file_id(), extern_crate.ast_id),
 +                ));
 +            }
 +        }
 +
 +        for directive in &self.unresolved_imports {
 +            if let ImportSource::Import { id: import, use_tree } = directive.import.source {
 +                if matches!(
 +                    (directive.import.path.segments().first(), &directive.import.path.kind),
 +                    (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
 +                ) {
 +                    continue;
 +                }
 +
 +                self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
 +                    directive.module_id,
 +                    import,
 +                    use_tree,
 +                ));
 +            }
 +        }
 +
 +        self.def_map
 +    }
 +}
 +
 +/// Walks a single module, populating defs, imports and macros
 +struct ModCollector<'a, 'b> {
 +    def_collector: &'a mut DefCollector<'b>,
 +    macro_depth: usize,
 +    module_id: LocalModuleId,
 +    tree_id: TreeId,
 +    item_tree: &'a ItemTree,
 +    mod_dir: ModDir,
 +}
 +
 +impl ModCollector<'_, '_> {
 +    fn collect_in_top_module(&mut self, items: &[ModItem]) {
 +        let module = self.def_collector.def_map.module_id(self.module_id);
 +        self.collect(items, module.into())
 +    }
 +
 +    fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
 +        let krate = self.def_collector.def_map.krate;
 +
 +        // Note: don't assert that inserted value is fresh: it's simply not true
 +        // for macros.
 +        self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
 +
 +        // Prelude module is always considered to be `#[macro_use]`.
 +        if let Some(prelude_module) = self.def_collector.def_map.prelude {
 +            if prelude_module.krate != krate {
 +                cov_mark::hit!(prelude_is_macro_use);
 +                self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
 +            }
 +        }
 +
 +        // This should be processed eagerly instead of deferred to resolving.
 +        // `#[macro_use] extern crate` is hoisted to imports macros before collecting
 +        // any other items.
 +        for &item in items {
 +            let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
 +            if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
 +                if let ModItem::ExternCrate(id) = item {
 +                    let import = &self.item_tree[id];
 +                    let attrs = self.item_tree.attrs(
 +                        self.def_collector.db,
 +                        krate,
 +                        ModItem::from(id).into(),
 +                    );
 +                    if attrs.by_key("macro_use").exists() {
 +                        self.def_collector.import_macros_from_extern_crate(self.module_id, import);
 +                    }
 +                }
 +            }
 +        }
 +
 +        for &item in items {
 +            let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
 +            if let Some(cfg) = attrs.cfg() {
 +                if !self.is_cfg_enabled(&cfg) {
 +                    self.emit_unconfigured_diagnostic(item, &cfg);
 +                    continue;
 +                }
 +            }
 +
 +            if let Err(()) = self.resolve_attributes(&attrs, item, container) {
 +                // Do not process the item. It has at least one non-builtin attribute, so the
 +                // fixed-point algorithm is required to resolve the rest of them.
 +                continue;
 +            }
 +
 +            let db = self.def_collector.db;
 +            let module = self.def_collector.def_map.module_id(self.module_id);
 +            let def_map = &mut self.def_collector.def_map;
 +            let update_def =
 +                |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
 +                    def_collector.def_map.modules[self.module_id].scope.declare(id);
 +                    def_collector.update(
 +                        self.module_id,
 +                        &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
 +                        vis,
 +                        ImportType::Named,
 +                    )
 +                };
 +            let resolve_vis = |def_map: &DefMap, visibility| {
 +                def_map
 +                    .resolve_visibility(db, self.module_id, visibility)
 +                    .unwrap_or(Visibility::Public)
 +            };
 +
 +            match item {
 +                ModItem::Mod(m) => self.collect_module(m, &attrs),
 +                ModItem::Import(import_id) => {
 +                    let imports = Import::from_use(
 +                        db,
 +                        krate,
 +                        self.item_tree,
 +                        ItemTreeId::new(self.tree_id, import_id),
 +                    );
 +                    self.def_collector.unresolved_imports.extend(imports.into_iter().map(
 +                        |import| ImportDirective {
 +                            module_id: self.module_id,
 +                            import,
 +                            status: PartialResolvedImport::Unresolved,
 +                        },
 +                    ));
 +                }
 +                ModItem::ExternCrate(import_id) => {
 +                    self.def_collector.unresolved_imports.push(ImportDirective {
 +                        module_id: self.module_id,
 +                        import: Import::from_extern_crate(
 +                            db,
 +                            krate,
 +                            self.item_tree,
 +                            ItemTreeId::new(self.tree_id, import_id),
 +                        ),
 +                        status: PartialResolvedImport::Unresolved,
 +                    })
 +                }
 +                ModItem::ExternBlock(block) => self.collect(
 +                    &self.item_tree[block].children,
 +                    ItemContainerId::ExternBlockId(
 +                        ExternBlockLoc {
 +                            container: module,
 +                            id: ItemTreeId::new(self.tree_id, block),
 +                        }
 +                        .intern(db),
 +                    ),
 +                ),
 +                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
 +                ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
 +                ModItem::MacroDef(id) => self.collect_macro_def(id, module),
 +                ModItem::Impl(imp) => {
 +                    let impl_id =
 +                        ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
 +                            .intern(db);
 +                    self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
 +                }
 +                ModItem::Function(id) => {
 +                    let it = &self.item_tree[id];
 +                    let fn_id =
 +                        FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    if self.def_collector.is_proc_macro {
 +                        if self.module_id == def_map.root {
 +                            if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
 +                                let crate_root = def_map.module_id(def_map.root);
 +                                self.def_collector.export_proc_macro(
 +                                    proc_macro,
 +                                    ItemTreeId::new(self.tree_id, id),
 +                                    fn_id,
 +                                    crate_root,
 +                                );
 +                            }
 +                        }
 +                    }
 +
 +                    update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
 +                }
 +                ModItem::Struct(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        !matches!(it.fields, Fields::Record(_)),
 +                    );
 +                }
 +                ModItem::Union(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Enum(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Const(id) => {
 +                    let it = &self.item_tree[id];
 +                    let const_id =
 +                        ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 +
 +                    match &it.name {
 +                        Some(name) => {
 +                            let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                            update_def(self.def_collector, const_id.into(), name, vis, false);
 +                        }
 +                        None => {
 +                            // const _: T = ...;
 +                            self.def_collector.def_map.modules[self.module_id]
 +                                .scope
 +                                .define_unnamed_const(const_id);
 +                        }
 +                    }
 +                }
 +                ModItem::Static(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Trait(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::TypeAlias(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
 +        let path_attr = attrs.by_key("path").string_value();
 +        let is_macro_use = attrs.by_key("macro_use").exists();
 +        let module = &self.item_tree[module_id];
 +        match &module.kind {
 +            // inline module, just recurse
 +            ModKind::Inline { items } => {
 +                let module_id = self.push_child_module(
 +                    module.name.clone(),
 +                    AstId::new(self.file_id(), module.ast_id),
 +                    None,
 +                    &self.item_tree[module.visibility],
 +                    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);
 +                    }
 +                }
 +            }
 +            // out of line module, resolve, parse and recurse
 +            ModKind::Outline => {
 +                let ast_id = AstId::new(self.tree_id.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)
 +                {
 +                    Ok((file_id, is_mod_rs, mod_dir)) => {
 +                        let item_tree = db.file_item_tree(file_id.into());
 +                        let krate = self.def_collector.def_map.krate;
 +                        let is_enabled = item_tree
 +                            .top_level_attrs(db, krate)
 +                            .cfg()
 +                            .map_or(true, |cfg| self.is_cfg_enabled(&cfg));
 +                        if is_enabled {
 +                            let module_id = self.push_child_module(
 +                                module.name.clone(),
 +                                ast_id,
 +                                Some((file_id, is_mod_rs)),
 +                                &self.item_tree[module.visibility],
 +                                module_id,
 +                            );
 +                            ModCollector {
 +                                def_collector: self.def_collector,
 +                                macro_depth: self.macro_depth,
 +                                module_id,
 +                                tree_id: TreeId::new(file_id.into(), None),
 +                                item_tree: &item_tree,
 +                                mod_dir,
 +                            }
 +                            .collect_in_top_module(item_tree.top_level_items());
 +                            let is_macro_use = is_macro_use
 +                                || item_tree
 +                                    .top_level_attrs(db, krate)
 +                                    .by_key("macro_use")
 +                                    .exists();
 +                            if is_macro_use {
 +                                self.import_all_legacy_macros(module_id);
 +                            }
 +                        }
 +                    }
 +                    Err(candidates) => {
 +                        self.push_child_module(
 +                            module.name.clone(),
 +                            ast_id,
 +                            None,
 +                            &self.item_tree[module.visibility],
 +                            module_id,
 +                        );
 +                        self.def_collector.def_map.diagnostics.push(
 +                            DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
 +                        );
 +                    }
 +                };
 +            }
 +        }
 +    }
 +
 +    fn push_child_module(
 +        &mut self,
 +        name: Name,
 +        declaration: AstId<ast::Module>,
 +        definition: Option<(FileId, bool)>,
 +        visibility: &crate::visibility::RawVisibility,
 +        mod_tree_id: FileItemTreeId<Mod>,
 +    ) -> LocalModuleId {
 +        let def_map = &mut self.def_collector.def_map;
 +        let vis = def_map
 +            .resolve_visibility(self.def_collector.db, self.module_id, visibility)
 +            .unwrap_or(Visibility::Public);
 +        let modules = &mut def_map.modules;
 +        let origin = match definition {
 +            None => ModuleOrigin::Inline {
 +                definition: declaration,
 +                definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
 +            },
 +            Some((definition, is_mod_rs)) => ModuleOrigin::File {
 +                declaration,
 +                definition,
 +                is_mod_rs,
 +                declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
 +            },
 +        };
 +
 +        let res = modules.alloc(ModuleData::new(origin, vis));
 +        modules[res].parent = Some(self.module_id);
 +        for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
 +            for &mac in &mac {
 +                modules[res].scope.define_legacy_macro(name.clone(), mac);
 +            }
 +        }
 +        modules[self.module_id].children.insert(name.clone(), res);
 +
 +        let module = def_map.module_id(res);
 +        let def = ModuleDefId::from(module);
 +
 +        def_map.modules[self.module_id].scope.declare(def);
 +        self.def_collector.update(
 +            self.module_id,
 +            &[(Some(name), PerNs::from_def(def, vis, false))],
 +            vis,
 +            ImportType::Named,
 +        );
 +        res
 +    }
 +
 +    /// Resolves attributes on an item.
 +    ///
 +    /// Returns `Err` when some attributes could not be resolved to builtins and have been
 +    /// registered as unresolved.
 +    ///
 +    /// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
 +    /// assumed to be resolved already.
 +    fn resolve_attributes(
 +        &mut self,
 +        attrs: &Attrs,
 +        mod_item: ModItem,
 +        container: ItemContainerId,
 +    ) -> Result<(), ()> {
 +        let mut ignore_up_to =
 +            self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
 +        let iter = attrs
 +            .iter()
 +            .dedup_by(|a, b| {
 +                // FIXME: this should not be required, all attributes on an item should have a
 +                // unique ID!
 +                // Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes:
 +                //     #[cfg_attr(not(off), unresolved, unresolved)]
 +                //     struct S;
 +                // We should come up with a different way to ID attributes.
 +                a.id == b.id
 +            })
 +            .skip_while(|attr| match ignore_up_to {
 +                Some(id) if attr.id == id => {
 +                    ignore_up_to = None;
 +                    true
 +                }
 +                Some(_) => true,
 +                None => false,
 +            });
 +
 +        for attr in iter {
 +            if self.def_collector.def_map.is_builtin_or_registered_attr(&attr.path) {
 +                continue;
 +            }
 +            tracing::debug!("non-builtin attribute {}", attr.path);
 +
 +            let ast_id = AstIdWithPath::new(
 +                self.file_id(),
 +                mod_item.ast_id(self.item_tree),
 +                attr.path.as_ref().clone(),
 +            );
 +            self.def_collector.unresolved_macros.push(MacroDirective {
 +                module_id: self.module_id,
 +                depth: self.macro_depth + 1,
 +                kind: MacroDirectiveKind::Attr {
 +                    ast_id,
 +                    attr: attr.clone(),
 +                    mod_item,
 +                    tree: self.tree_id,
 +                },
 +                container,
 +            });
 +
 +            return Err(());
 +        }
 +
 +        Ok(())
 +    }
 +
 +    fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
 +        let krate = self.def_collector.def_map.krate;
 +        let mac = &self.item_tree[id];
 +        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
 +        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
 +
 +        let export_attr = attrs.by_key("macro_export");
 +
 +        let is_export = export_attr.exists();
 +        let local_inner = if is_export {
 +            export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
 +                tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
 +                    ident.text.contains("local_inner_macros")
 +                }
 +                _ => false,
 +            })
 +        } else {
 +            false
 +        };
 +
 +        // Case 1: builtin macros
 +        let expander = if attrs.by_key("rustc_builtin_macro").exists() {
 +            // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
 +            let name;
 +            let name = match attrs.by_key("rustc_builtin_macro").string_value() {
 +                Some(it) => {
 +                    // FIXME: a hacky way to create a Name from string.
 +                    name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
 +                    &name
 +                }
 +                None => {
 +                    let explicit_name =
 +                        attrs.by_key("rustc_builtin_macro").tt_values().next().and_then(|tt| {
 +                            match tt.token_trees.first() {
 +                                Some(tt::TokenTree::Leaf(tt::Leaf::Ident(name))) => Some(name),
 +                                _ => None,
 +                            }
 +                        });
 +                    match explicit_name {
 +                        Some(ident) => {
 +                            name = ident.as_name();
 +                            &name
 +                        }
 +                        None => &mac.name,
 +                    }
 +                }
 +            };
 +            match find_builtin_macro(name) {
 +                Some(Either::Left(it)) => MacroExpander::BuiltIn(it),
 +                Some(Either::Right(it)) => MacroExpander::BuiltInEager(it),
 +                None => {
 +                    self.def_collector
 +                        .def_map
 +                        .diagnostics
 +                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
 +                    return;
 +                }
 +            }
 +        } else {
 +            // Case 2: normal `macro_rules!` macro
 +            MacroExpander::Declarative
 +        };
 +
 +        let macro_id = MacroRulesLoc {
 +            container: module,
 +            id: ItemTreeId::new(self.tree_id, id),
 +            local_inner,
 +            expander,
 +        }
 +        .intern(self.def_collector.db);
 +        self.def_collector.define_macro_rules(
 +            self.module_id,
 +            mac.name.clone(),
 +            macro_id,
 +            is_export,
 +        );
 +    }
 +
 +    fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId) {
 +        let krate = self.def_collector.def_map.krate;
 +        let mac = &self.item_tree[id];
 +        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
 +
 +        // Case 1: builtin macros
 +        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
 +        let expander = if attrs.by_key("rustc_builtin_macro").exists() {
 +            if let Some(expander) = find_builtin_macro(&mac.name) {
 +                match expander {
 +                    Either::Left(it) => MacroExpander::BuiltIn(it),
 +                    Either::Right(it) => MacroExpander::BuiltInEager(it),
 +                }
 +            } else if let Some(expander) = find_builtin_derive(&mac.name) {
 +                MacroExpander::BuiltInDerive(expander)
 +            } else if let Some(expander) = find_builtin_attr(&mac.name) {
 +                MacroExpander::BuiltInAttr(expander)
 +            } else {
 +                self.def_collector
 +                    .def_map
 +                    .diagnostics
 +                    .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
 +                return;
 +            }
 +        } else {
 +            // Case 2: normal `macro`
 +            MacroExpander::Declarative
 +        };
 +
 +        let macro_id =
 +            Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander }
 +                .intern(self.def_collector.db);
 +        self.def_collector.define_macro_def(
 +            self.module_id,
 +            mac.name.clone(),
 +            macro_id,
 +            &self.item_tree[mac.visibility],
 +        );
 +    }
 +
 +    fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
 +        let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
 +
 +        // Case 1: try to resolve in legacy scope and expand macro_rules
 +        let mut error = None;
 +        match macro_call_as_call_id(
 +            self.def_collector.db,
 +            &ast_id,
 +            mac.expand_to,
 +            self.def_collector.def_map.krate,
 +            |path| {
 +                path.as_ident().and_then(|name| {
 +                    self.def_collector.def_map.with_ancestor_maps(
 +                        self.def_collector.db,
 +                        self.module_id,
 +                        &mut |map, module| {
 +                            map[module]
 +                                .scope
 +                                .get_legacy_macro(name)
 +                                .and_then(|it| it.last())
 +                                .map(|&it| macro_id_to_def_id(self.def_collector.db, it.into()))
 +                        },
 +                    )
 +                })
 +            },
 +            &mut |err| {
 +                error.get_or_insert(err);
 +            },
 +        ) {
 +            Ok(Ok(macro_call_id)) => {
 +                // Legacy macros need to be expanded immediately, so that any macros they produce
 +                // are in scope.
 +                self.def_collector.collect_macro_expansion(
 +                    self.module_id,
 +                    macro_call_id,
 +                    self.macro_depth + 1,
 +                    container,
 +                );
 +
 +                if let Some(err) = error {
 +                    self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
 +                        self.module_id,
 +                        MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
 +                        err.to_string(),
 +                    ));
 +                }
 +
 +                return;
 +            }
 +            Ok(Err(_)) => {
 +                // Built-in macro failed eager expansion.
 +
 +                self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
 +                    self.module_id,
 +                    MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
 +                    error.unwrap().to_string(),
 +                ));
 +                return;
 +            }
 +            Err(UnresolvedMacro { .. }) => (),
 +        }
 +
 +        // Case 2: resolve in module scope, expand during name resolution.
 +        self.def_collector.unresolved_macros.push(MacroDirective {
 +            module_id: self.module_id,
 +            depth: self.macro_depth + 1,
 +            kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
 +            container,
 +        });
 +    }
 +
 +    fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
 +        let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
 +        for (name, macs) in macros {
 +            macs.last().map(|&mac| {
 +                self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac)
 +            });
 +        }
 +    }
 +
 +    fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
 +        self.def_collector.cfg_options.check(cfg) != Some(false)
 +    }
 +
 +    fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
 +        let ast_id = item.ast_id(self.item_tree);
 +
 +        let ast_id = InFile::new(self.file_id(), ast_id);
 +        self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
 +            self.module_id,
 +            ast_id,
 +            cfg.clone(),
 +            self.def_collector.cfg_options.clone(),
 +        ));
 +    }
 +
 +    fn file_id(&self) -> HirFileId {
 +        self.tree_id.file_id()
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::{db::DefDatabase, test_db::TestDB};
 +    use base_db::{fixture::WithFixture, SourceDatabase};
 +
 +    use super::*;
 +
 +    fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
 +        let mut collector = DefCollector {
 +            db,
 +            def_map,
 +            deps: FxHashMap::default(),
 +            glob_imports: FxHashMap::default(),
 +            unresolved_imports: Vec::new(),
 +            indeterminate_imports: Vec::new(),
 +            unresolved_macros: Vec::new(),
 +            mod_dirs: FxHashMap::default(),
 +            cfg_options: &CfgOptions::default(),
 +            proc_macros: Default::default(),
 +            from_glob_import: Default::default(),
 +            skip_attrs: Default::default(),
 +            is_proc_macro: false,
 +        };
 +        collector.seed_with_top_level();
 +        collector.collect();
 +        collector.def_map
 +    }
 +
 +    fn do_resolve(not_ra_fixture: &str) -> DefMap {
 +        let (db, file_id) = TestDB::with_single_file(not_ra_fixture);
 +        let krate = db.test_crate();
 +
 +        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));
 +        do_collect_defs(&db, def_map)
 +    }
 +
 +    #[test]
 +    fn test_macro_expand_will_stop_1() {
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!($($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!(() $($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +    }
 +
 +    #[ignore]
 +    #[test]
 +    fn test_macro_expand_will_stop_2() {
 +        // FIXME: this test does succeed, but takes quite a while: 90 seconds in
 +        // the release mode. That's why the argument is not an ra_fixture --
 +        // otherwise injection highlighting gets stuck.
 +        //
 +        // We need to find a way to fail this faster.
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +    }
 +}
index b385b1cafaefd09f3db05d293cb88fb0737e1f6b,0000000000000000000000000000000000000000..69283e55a4c2cb0e6acce24fe7f2ac73c11d2410
mode 100644,000000..100644
--- /dev/null
@@@ -1,225 -1,0 +1,233 @@@
 +//! The home of `HirDatabase`, which is the Salsa database containing all the
 +//! type inference-related queries.
 +
 +use std::sync::Arc;
 +
 +use arrayvec::ArrayVec;
 +use base_db::{impl_intern_key, salsa, CrateId, Upcast};
 +use hir_def::{
 +    db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
 +    GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
 +};
 +use la_arena::ArenaMap;
 +
 +use crate::{
 +    chalk_db,
 +    consteval::{ComputedExpr, ConstEvalError},
 +    method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
 +    Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
 +    QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
 +};
 +use hir_expand::name::Name;
 +
 +#[salsa::query_group(HirDatabaseStorage)]
 +pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
 +    #[salsa::invoke(infer_wait)]
 +    #[salsa::transparent]
 +    fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
 +
 +    #[salsa::invoke(crate::infer::infer_query)]
 +    fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
 +
 +    #[salsa::invoke(crate::lower::ty_query)]
 +    #[salsa::cycle(crate::lower::ty_recover)]
 +    fn ty(&self, def: TyDefId) -> Binders<Ty>;
 +
 +    #[salsa::invoke(crate::lower::value_ty_query)]
 +    fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
 +
 +    #[salsa::invoke(crate::lower::impl_self_ty_query)]
 +    #[salsa::cycle(crate::lower::impl_self_ty_recover)]
 +    fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
 +
 +    #[salsa::invoke(crate::lower::const_param_ty_query)]
 +    fn const_param_ty(&self, def: ConstParamId) -> Ty;
 +
 +    #[salsa::invoke(crate::consteval::const_eval_query)]
 +    #[salsa::cycle(crate::consteval::const_eval_recover)]
 +    fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
 +
 +    #[salsa::invoke(crate::lower::impl_trait_query)]
 +    fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
 +
 +    #[salsa::invoke(crate::lower::field_types_query)]
 +    fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
 +
 +    #[salsa::invoke(crate::lower::callable_item_sig)]
 +    fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
 +
 +    #[salsa::invoke(crate::lower::return_type_impl_traits)]
 +    fn return_type_impl_traits(
 +        &self,
 +        def: FunctionId,
 +    ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
 +
 +    #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
 +    #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
 +    fn generic_predicates_for_param(
 +        &self,
 +        def: GenericDefId,
 +        param_id: TypeOrConstParamId,
 +        assoc_name: Option<Name>,
 +    ) -> Arc<[Binders<QuantifiedWhereClause>]>;
 +
 +    #[salsa::invoke(crate::lower::generic_predicates_query)]
 +    fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<QuantifiedWhereClause>]>;
 +
 +    #[salsa::invoke(crate::lower::trait_environment_query)]
 +    fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>;
 +
 +    #[salsa::invoke(crate::lower::generic_defaults_query)]
 +    #[salsa::cycle(crate::lower::generic_defaults_recover)]
 +    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
 +
 +    #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
 +    fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
 +
 +    #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
 +    fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
 +
 +    /// Collects all crates in the dependency graph that have impls for the
 +    /// given fingerprint. This is only used for primitive types; for
 +    /// user-defined types we just look at the crate where the type is defined.
 +    #[salsa::invoke(crate::method_resolution::inherent_impl_crates_query)]
 +    fn inherent_impl_crates(&self, krate: CrateId, fp: TyFingerprint) -> ArrayVec<CrateId, 2>;
 +
 +    #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
 +    fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
 +
 +    #[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
 +    fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
 +
 +    #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
 +    fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
 +
 +    // Interned IDs for Chalk integration
 +    #[salsa::interned]
 +    fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
 +    #[salsa::interned]
 +    fn intern_type_or_const_param_id(
 +        &self,
 +        param_id: TypeOrConstParamId,
 +    ) -> InternedTypeOrConstParamId;
 +    #[salsa::interned]
 +    fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
 +    #[salsa::interned]
 +    fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
 +    #[salsa::interned]
 +    fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
 +
 +    #[salsa::invoke(chalk_db::associated_ty_data_query)]
 +    fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
 +
 +    #[salsa::invoke(chalk_db::trait_datum_query)]
 +    fn trait_datum(&self, krate: CrateId, trait_id: chalk_db::TraitId)
 +        -> Arc<chalk_db::TraitDatum>;
 +
 +    #[salsa::invoke(chalk_db::struct_datum_query)]
 +    fn struct_datum(
 +        &self,
 +        krate: CrateId,
 +        struct_id: chalk_db::AdtId,
 +    ) -> Arc<chalk_db::StructDatum>;
 +
 +    #[salsa::invoke(chalk_db::impl_datum_query)]
 +    fn impl_datum(&self, krate: CrateId, impl_id: chalk_db::ImplId) -> Arc<chalk_db::ImplDatum>;
 +
 +    #[salsa::invoke(chalk_db::fn_def_datum_query)]
 +    fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>;
 +
 +    #[salsa::invoke(chalk_db::fn_def_variance_query)]
 +    fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances;
 +
 +    #[salsa::invoke(chalk_db::adt_variance_query)]
 +    fn adt_variance(&self, adt_id: chalk_db::AdtId) -> chalk_db::Variances;
 +
 +    #[salsa::invoke(chalk_db::associated_ty_value_query)]
 +    fn associated_ty_value(
 +        &self,
 +        krate: CrateId,
 +        id: chalk_db::AssociatedTyValueId,
 +    ) -> Arc<chalk_db::AssociatedTyValue>;
 +
++    #[salsa::invoke(crate::traits::normalize_projection_query)]
++    #[salsa::transparent]
++    fn normalize_projection(
++        &self,
++        projection: crate::ProjectionTy,
++        env: Arc<crate::TraitEnvironment>,
++    ) -> Ty;
++
 +    #[salsa::invoke(trait_solve_wait)]
 +    #[salsa::transparent]
 +    fn trait_solve(
 +        &self,
 +        krate: CrateId,
 +        goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
 +    ) -> Option<crate::Solution>;
 +
 +    #[salsa::invoke(crate::traits::trait_solve_query)]
 +    fn trait_solve_query(
 +        &self,
 +        krate: CrateId,
 +        goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
 +    ) -> Option<crate::Solution>;
 +
 +    #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
 +    fn program_clauses_for_chalk_env(
 +        &self,
 +        krate: CrateId,
 +        env: chalk_ir::Environment<Interner>,
 +    ) -> chalk_ir::ProgramClauses<Interner>;
 +}
 +
 +fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
 +    let _p = profile::span("infer:wait").detail(|| match def {
 +        DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(),
 +        DefWithBodyId::StaticId(it) => db.static_data(it).name.clone().to_string(),
 +        DefWithBodyId::ConstId(it) => {
 +            db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
 +        }
 +    });
 +    db.infer_query(def)
 +}
 +
 +fn trait_solve_wait(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
 +) -> Option<crate::Solution> {
 +    let _p = profile::span("trait_solve::wait");
 +    db.trait_solve_query(krate, goal)
 +}
 +
 +#[test]
 +fn hir_database_is_object_safe() {
 +    fn _assert_object_safe(_: &dyn HirDatabase) {}
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct InternedTypeOrConstParamId(salsa::InternId);
 +impl_intern_key!(InternedTypeOrConstParamId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct InternedLifetimeParamId(salsa::InternId);
 +impl_intern_key!(InternedLifetimeParamId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct InternedConstParamId(salsa::InternId);
 +impl_intern_key!(InternedConstParamId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct InternedOpaqueTyId(salsa::InternId);
 +impl_intern_key!(InternedOpaqueTyId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct InternedClosureId(salsa::InternId);
 +impl_intern_key!(InternedClosureId);
 +
 +/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
 +/// we have different IDs for struct and enum variant constructors.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct InternedCallableDefId(salsa::InternId);
 +impl_intern_key!(InternedCallableDefId);
index d2f9c2b8b1e1dae302ce60ec0d0b493cab9b0829,0000000000000000000000000000000000000000..874abdaea8370f4ef2a8e3bc1c28abab3d5c6dcc
mode 100644,000000..100644
--- /dev/null
@@@ -1,1315 -1,0 +1,1316 @@@
 +//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
 +//! HIR back into source code, and just displaying them for debugging/testing
 +//! purposes.
 +
 +use std::fmt::{self, Debug};
 +
 +use base_db::CrateId;
 +use chalk_ir::BoundVar;
 +use hir_def::{
 +    body,
 +    db::DefDatabase,
 +    find_path,
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    intern::{Internable, Interned},
 +    item_scope::ItemInNs,
 +    path::{Path, PathKind},
 +    type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
 +    visibility::Visibility,
 +    HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
 +};
 +use hir_expand::{hygiene::Hygiene, name::Name};
 +use itertools::Itertools;
 +use syntax::SmolStr;
 +
 +use crate::{
 +    db::HirDatabase,
 +    from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
 +    mapping::from_chalk,
 +    primitive, subst_prefix, to_assoc_type_id,
 +    utils::{self, generics},
 +    AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
 +    GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
 +    OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef,
 +    TraitRefExt, Ty, TyExt, TyKind, WhereClause,
 +};
 +
 +pub struct HirFormatter<'a> {
 +    pub db: &'a dyn HirDatabase,
 +    fmt: &'a mut dyn fmt::Write,
 +    buf: String,
 +    curr_size: usize,
 +    pub(crate) max_size: Option<usize>,
 +    omit_verbose_types: bool,
 +    display_target: DisplayTarget,
 +}
 +
 +pub trait HirDisplay {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
 +
 +    /// Returns a `Display`able type that is human-readable.
 +    fn into_displayable<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        max_size: Option<usize>,
 +        omit_verbose_types: bool,
 +        display_target: DisplayTarget,
 +    ) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        assert!(
 +            !matches!(display_target, DisplayTarget::SourceCode { .. }),
 +            "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
 +        );
 +        HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
 +    }
 +
 +    /// Returns a `Display`able type that is human-readable.
 +    /// Use this for showing types to the user (e.g. diagnostics)
 +    fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::Diagnostics,
 +        }
 +    }
 +
 +    /// Returns a `Display`able type that is human-readable and tries to be succinct.
 +    /// Use this for showing types to the user where space is constrained (e.g. doc popups)
 +    fn display_truncated<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        max_size: Option<usize>,
 +    ) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size,
 +            omit_verbose_types: true,
 +            display_target: DisplayTarget::Diagnostics,
 +        }
 +    }
 +
 +    /// Returns a String representation of `self` that can be inserted into the given module.
 +    /// Use this when generating code (e.g. assists)
 +    fn display_source_code<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        module_id: ModuleId,
 +    ) -> Result<String, DisplaySourceCodeError> {
 +        let mut result = String::new();
 +        match self.hir_fmt(&mut HirFormatter {
 +            db,
 +            fmt: &mut result,
 +            buf: String::with_capacity(20),
 +            curr_size: 0,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::SourceCode { module_id },
 +        }) {
 +            Ok(()) => {}
 +            Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
 +            Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
 +        };
 +        Ok(result)
 +    }
 +
 +    /// Returns a String representation of `self` for test purposes
 +    fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::Test,
 +        }
 +    }
 +}
 +
 +impl<'a> HirFormatter<'a> {
 +    pub fn write_joined<T: HirDisplay>(
 +        &mut self,
 +        iter: impl IntoIterator<Item = T>,
 +        sep: &str,
 +    ) -> Result<(), HirDisplayError> {
 +        let mut first = true;
 +        for e in iter {
 +            if !first {
 +                write!(self, "{}", sep)?;
 +            }
 +            first = false;
 +
 +            // Abbreviate multiple omitted types with a single ellipsis.
 +            if self.should_truncate() {
 +                return write!(self, "{}", TYPE_HINT_TRUNCATION);
 +            }
 +
 +            e.hir_fmt(self)?;
 +        }
 +        Ok(())
 +    }
 +
 +    /// This allows using the `write!` macro directly with a `HirFormatter`.
 +    pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> {
 +        // We write to a buffer first to track output size
 +        self.buf.clear();
 +        fmt::write(&mut self.buf, args)?;
 +        self.curr_size += self.buf.len();
 +
 +        // Then we write to the internal formatter from the buffer
 +        self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
 +    }
 +
 +    pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> {
 +        self.fmt.write_str(s)?;
 +        Ok(())
 +    }
 +
 +    pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> {
 +        self.fmt.write_char(c)?;
 +        Ok(())
 +    }
 +
 +    pub fn should_truncate(&self) -> bool {
 +        match self.max_size {
 +            Some(max_size) => self.curr_size >= max_size,
 +            None => false,
 +        }
 +    }
 +
 +    pub fn omit_verbose_types(&self) -> bool {
 +        self.omit_verbose_types
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum DisplayTarget {
 +    /// Display types for inlays, doc popups, autocompletion, etc...
 +    /// Showing `{unknown}` or not qualifying paths is fine here.
 +    /// There's no reason for this to fail.
 +    Diagnostics,
 +    /// Display types for inserting them in source files.
 +    /// The generated code should compile, so paths need to be qualified.
 +    SourceCode { module_id: ModuleId },
 +    /// Only for test purpose to keep real types
 +    Test,
 +}
 +
 +impl DisplayTarget {
 +    fn is_source_code(&self) -> bool {
 +        matches!(self, Self::SourceCode { .. })
 +    }
 +    fn is_test(&self) -> bool {
 +        matches!(self, Self::Test)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum DisplaySourceCodeError {
 +    PathNotFound,
 +    UnknownType,
 +    Closure,
 +}
 +
 +pub enum HirDisplayError {
 +    /// Errors that can occur when generating source code
 +    DisplaySourceCodeError(DisplaySourceCodeError),
 +    /// `FmtError` is required to be compatible with std::fmt::Display
 +    FmtError,
 +}
 +impl From<fmt::Error> for HirDisplayError {
 +    fn from(_: fmt::Error) -> Self {
 +        Self::FmtError
 +    }
 +}
 +
 +pub struct HirDisplayWrapper<'a, T> {
 +    db: &'a dyn HirDatabase,
 +    t: &'a T,
 +    max_size: Option<usize>,
 +    omit_verbose_types: bool,
 +    display_target: DisplayTarget,
 +}
 +
 +impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
 +where
 +    T: HirDisplay,
 +{
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self.t.hir_fmt(&mut HirFormatter {
 +            db: self.db,
 +            fmt: f,
 +            buf: String::with_capacity(20),
 +            curr_size: 0,
 +            max_size: self.max_size,
 +            omit_verbose_types: self.omit_verbose_types,
 +            display_target: self.display_target,
 +        }) {
 +            Ok(()) => Ok(()),
 +            Err(HirDisplayError::FmtError) => Err(fmt::Error),
 +            Err(HirDisplayError::DisplaySourceCodeError(_)) => {
 +                // This should never happen
 +                panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
 +            }
 +        }
 +    }
 +}
 +
 +const TYPE_HINT_TRUNCATION: &str = "…";
 +
 +impl<T: HirDisplay> HirDisplay for &'_ T {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        HirDisplay::hir_fmt(*self, f)
 +    }
 +}
 +
 +impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        HirDisplay::hir_fmt(self.as_ref(), f)
 +    }
 +}
 +
 +impl HirDisplay for ProjectionTy {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        let trait_ = f.db.trait_data(self.trait_(f.db));
 +        write!(f, "<")?;
 +        self.self_type_parameter(Interner).hir_fmt(f)?;
 +        write!(f, " as {}", trait_.name)?;
 +        if self.substitution.len(Interner) > 1 {
 +            write!(f, "<")?;
 +            f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
 +            write!(f, ">")?;
 +        }
 +        write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for OpaqueTy {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        self.substitution.at(Interner, 0).hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for GenericArg {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self.interned() {
 +            crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
 +            crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
 +            crate::GenericArgData::Const(c) => c.hir_fmt(f),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for Const {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        let data = self.interned();
 +        match data.value {
 +            ConstValue::BoundVar(idx) => idx.hir_fmt(f),
 +            ConstValue::InferenceVar(..) => write!(f, "#c#"),
 +            ConstValue::Placeholder(idx) => {
 +                let id = from_placeholder_idx(f.db, idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.type_or_consts[id.local_id];
 +                write!(f, "{}", param_data.name().unwrap())
 +            }
 +            ConstValue::Concrete(c) => write!(f, "{}", c.interned),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for BoundVar {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        write!(f, "?{}.{}", self.debruijn.depth(), self.index)
 +    }
 +}
 +
 +impl HirDisplay for Ty {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        match self.kind(Interner) {
 +            TyKind::Never => write!(f, "!")?,
 +            TyKind::Str => write!(f, "str")?,
 +            TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
 +            TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
 +            &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
 +            &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
 +            &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
 +            TyKind::Slice(t) => {
 +                write!(f, "[")?;
 +                t.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TyKind::Array(t, c) => {
 +                write!(f, "[")?;
 +                t.hir_fmt(f)?;
 +                write!(f, "; ")?;
 +                c.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
 +                if matches!(self.kind(Interner), TyKind::Raw(..)) {
 +                    write!(
 +                        f,
 +                        "*{}",
 +                        match m {
 +                            Mutability::Not => "const ",
 +                            Mutability::Mut => "mut ",
 +                        }
 +                    )?;
 +                } else {
 +                    write!(
 +                        f,
 +                        "&{}",
 +                        match m {
 +                            Mutability::Not => "",
 +                            Mutability::Mut => "mut ",
 +                        }
 +                    )?;
 +                }
 +
 +                // FIXME: all this just to decide whether to use parentheses...
 +                let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
 +                    bounds.iter().any(|bound| {
 +                        if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
 +                            let trait_ = trait_ref.hir_trait_id();
 +                            fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
 +                        } else {
 +                            false
 +                        }
 +                    })
 +                };
 +                let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) {
 +                    TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
 +                        let bounds = dyn_ty.bounds.skip_binders().interned();
 +                        (bounds.len(), contains_impl_fn(bounds))
 +                    }
 +                    TyKind::Alias(AliasTy::Opaque(OpaqueTy {
 +                        opaque_ty_id,
 +                        substitution: parameters,
 +                    }))
 +                    | TyKind::OpaqueType(opaque_ty_id, parameters) => {
 +                        let impl_trait_id =
 +                            f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
 +                        if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
 +                            let datas =
 +                                f.db.return_type_impl_traits(func)
 +                                    .expect("impl trait id without data");
 +                            let data = (*datas)
 +                                .as_ref()
 +                                .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                            let bounds = data.substitute(Interner, parameters);
 +                            let mut len = bounds.skip_binders().len();
 +
 +                            // Don't count Sized but count when it absent
 +                            // (i.e. when explicit ?Sized bound is set).
 +                            let default_sized = SizedByDefault::Sized {
 +                                anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
 +                            };
 +                            let sized_bounds = bounds
 +                                .skip_binders()
 +                                .iter()
 +                                .filter(|b| {
 +                                    matches!(
 +                                        b.skip_binders(),
 +                                        WhereClause::Implemented(trait_ref)
 +                                            if default_sized.is_sized_trait(
 +                                                trait_ref.hir_trait_id(),
 +                                                f.db.upcast(),
 +                                            ),
 +                                    )
 +                                })
 +                                .count();
 +                            match sized_bounds {
 +                                0 => len += 1,
 +                                _ => {
 +                                    len = len.saturating_sub(sized_bounds);
 +                                }
 +                            }
 +
 +                            (len, contains_impl_fn(bounds.skip_binders()))
 +                        } else {
 +                            (0, false)
 +                        }
 +                    }
 +                    _ => (0, false),
 +                };
 +
 +                if has_impl_fn_pred && preds_to_print <= 2 {
 +                    return t.hir_fmt(f);
 +                }
 +
 +                if preds_to_print > 1 {
 +                    write!(f, "(")?;
 +                    t.hir_fmt(f)?;
 +                    write!(f, ")")?;
 +                } else {
 +                    t.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Tuple(_, substs) => {
 +                if substs.len(Interner) == 1 {
 +                    write!(f, "(")?;
 +                    substs.at(Interner, 0).hir_fmt(f)?;
 +                    write!(f, ",)")?;
 +                } else {
 +                    write!(f, "(")?;
 +                    f.write_joined(&*substs.as_slice(Interner), ", ")?;
 +                    write!(f, ")")?;
 +                }
 +            }
 +            TyKind::Function(fn_ptr) => {
 +                let sig = CallableSig::from_fn_ptr(fn_ptr);
 +                sig.hir_fmt(f)?;
 +            }
 +            TyKind::FnDef(def, parameters) => {
 +                let def = from_chalk(f.db, *def);
 +                let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
 +                match def {
 +                    CallableDefId::FunctionId(ff) => {
 +                        write!(f, "fn {}", f.db.function_data(ff).name)?
 +                    }
 +                    CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
 +                    CallableDefId::EnumVariantId(e) => {
 +                        write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
 +                    }
 +                };
 +                if parameters.len(Interner) > 0 {
 +                    let generics = generics(f.db.upcast(), def.into());
 +                    let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
 +                        generics.provenance_split();
 +                    let total_len = parent_params + self_param + type_params + const_params;
 +                    // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
 +                    if total_len > 0 {
 +                        write!(f, "<")?;
 +                        f.write_joined(&parameters.as_slice(Interner)[..total_len], ", ")?;
 +                        write!(f, ">")?;
 +                    }
 +                }
 +                write!(f, "(")?;
 +                f.write_joined(sig.params(), ", ")?;
 +                write!(f, ")")?;
 +                let ret = sig.ret();
 +                if !ret.is_unit() {
 +                    write!(f, " -> ")?;
 +                    ret.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Adt(AdtId(def_id), parameters) => {
 +                match f.display_target {
 +                    DisplayTarget::Diagnostics | DisplayTarget::Test => {
 +                        let name = match *def_id {
 +                            hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
 +                            hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
 +                            hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
 +                        };
 +                        write!(f, "{}", name)?;
 +                    }
 +                    DisplayTarget::SourceCode { module_id } => {
 +                        if let Some(path) = find_path::find_path(
 +                            f.db.upcast(),
 +                            ItemInNs::Types((*def_id).into()),
 +                            module_id,
++                            false,
 +                        ) {
 +                            write!(f, "{}", path)?;
 +                        } else {
 +                            return Err(HirDisplayError::DisplaySourceCodeError(
 +                                DisplaySourceCodeError::PathNotFound,
 +                            ));
 +                        }
 +                    }
 +                }
 +
 +                if parameters.len(Interner) > 0 {
 +                    let parameters_to_write = if f.display_target.is_source_code()
 +                        || f.omit_verbose_types()
 +                    {
 +                        match self
 +                            .as_generic_def(f.db)
 +                            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
 +                            .filter(|defaults| !defaults.is_empty())
 +                        {
 +                            None => parameters.as_slice(Interner),
 +                            Some(default_parameters) => {
 +                                fn should_show(
 +                                    parameter: &GenericArg,
 +                                    default_parameters: &[Binders<GenericArg>],
 +                                    i: usize,
 +                                    parameters: &Substitution,
 +                                ) -> bool {
 +                                    if parameter.ty(Interner).map(|x| x.kind(Interner))
 +                                        == Some(&TyKind::Error)
 +                                    {
 +                                        return true;
 +                                    }
 +                                    if let Some(ConstValue::Concrete(c)) =
 +                                        parameter.constant(Interner).map(|x| x.data(Interner).value)
 +                                    {
 +                                        if c.interned == ConstScalar::Unknown {
 +                                            return true;
 +                                        }
 +                                    }
 +                                    let default_parameter = match default_parameters.get(i) {
 +                                        Some(x) => x,
 +                                        None => return true,
 +                                    };
 +                                    let actual_default = default_parameter
 +                                        .clone()
 +                                        .substitute(Interner, &subst_prefix(parameters, i));
 +                                    parameter != &actual_default
 +                                }
 +                                let mut default_from = 0;
 +                                for (i, parameter) in parameters.iter(Interner).enumerate() {
 +                                    if should_show(parameter, &default_parameters, i, parameters) {
 +                                        default_from = i + 1;
 +                                    }
 +                                }
 +                                &parameters.as_slice(Interner)[0..default_from]
 +                            }
 +                        }
 +                    } else {
 +                        parameters.as_slice(Interner)
 +                    };
 +                    if !parameters_to_write.is_empty() {
 +                        write!(f, "<")?;
 +
 +                        if f.display_target.is_source_code() {
 +                            let mut first = true;
 +                            for generic_arg in parameters_to_write {
 +                                if !first {
 +                                    write!(f, ", ")?;
 +                                }
 +                                first = false;
 +
 +                                if generic_arg.ty(Interner).map(|ty| ty.kind(Interner))
 +                                    == Some(&TyKind::Error)
 +                                {
 +                                    write!(f, "_")?;
 +                                } else {
 +                                    generic_arg.hir_fmt(f)?;
 +                                }
 +                            }
 +                        } else {
 +                            f.write_joined(parameters_to_write, ", ")?;
 +                        }
 +
 +                        write!(f, ">")?;
 +                    }
 +                }
 +            }
 +            TyKind::AssociatedType(assoc_type_id, parameters) => {
 +                let type_alias = from_assoc_type_id(*assoc_type_id);
 +                let trait_ = match type_alias.lookup(f.db.upcast()).container {
 +                    ItemContainerId::TraitId(it) => it,
 +                    _ => panic!("not an associated type"),
 +                };
 +                let trait_ = f.db.trait_data(trait_);
 +                let type_alias_data = f.db.type_alias_data(type_alias);
 +
 +                // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
 +                if f.display_target.is_test() {
 +                    write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
 +                    if parameters.len(Interner) > 0 {
 +                        write!(f, "<")?;
 +                        f.write_joined(&*parameters.as_slice(Interner), ", ")?;
 +                        write!(f, ">")?;
 +                    }
 +                } else {
 +                    let projection_ty = ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(type_alias),
 +                        substitution: parameters.clone(),
 +                    };
 +
 +                    projection_ty.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Foreign(type_alias) => {
 +                let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
 +                write!(f, "{}", type_alias.name)?;
 +            }
 +            TyKind::OpaqueType(opaque_ty_id, parameters) => {
 +                let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
 +                match impl_trait_id {
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        let datas =
 +                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
 +                        let data = (*datas)
 +                            .as_ref()
 +                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                        let bounds = data.substitute(Interner, &parameters);
 +                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
 +                        write_bounds_like_dyn_trait_with_prefix(
 +                            "impl",
 +                            bounds.skip_binders(),
 +                            SizedByDefault::Sized { anchor: krate },
 +                            f,
 +                        )?;
 +                        // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
 +                    }
 +                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
 +                        write!(f, "impl Future<Output = ")?;
 +                        parameters.at(Interner, 0).hir_fmt(f)?;
 +                        write!(f, ">")?;
 +                    }
 +                }
 +            }
 +            TyKind::Closure(.., substs) => {
 +                if f.display_target.is_source_code() {
 +                    return Err(HirDisplayError::DisplaySourceCodeError(
 +                        DisplaySourceCodeError::Closure,
 +                    ));
 +                }
 +                let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(f.db);
 +                if let Some(sig) = sig {
 +                    if sig.params().is_empty() {
 +                        write!(f, "||")?;
 +                    } else if f.should_truncate() {
 +                        write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
 +                    } else {
 +                        write!(f, "|")?;
 +                        f.write_joined(sig.params(), ", ")?;
 +                        write!(f, "|")?;
 +                    };
 +
 +                    write!(f, " -> ")?;
 +                    sig.ret().hir_fmt(f)?;
 +                } else {
 +                    write!(f, "{{closure}}")?;
 +                }
 +            }
 +            TyKind::Placeholder(idx) => {
 +                let id = from_placeholder_idx(f.db, *idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.type_or_consts[id.local_id];
 +                match param_data {
 +                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
 +                        TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
 +                            write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
 +                        }
 +                        TypeParamProvenance::ArgumentImplTrait => {
 +                            let substs = generics.placeholder_subst(f.db);
 +                            let bounds =
 +                                f.db.generic_predicates(id.parent)
 +                                    .iter()
 +                                    .map(|pred| pred.clone().substitute(Interner, &substs))
 +                                    .filter(|wc| match &wc.skip_binders() {
 +                                        WhereClause::Implemented(tr) => {
 +                                            &tr.self_type_parameter(Interner) == self
 +                                        }
 +                                        WhereClause::AliasEq(AliasEq {
 +                                            alias: AliasTy::Projection(proj),
 +                                            ty: _,
 +                                        }) => &proj.self_type_parameter(Interner) == self,
 +                                        _ => false,
 +                                    })
 +                                    .collect::<Vec<_>>();
 +                            let krate = id.parent.module(f.db.upcast()).krate();
 +                            write_bounds_like_dyn_trait_with_prefix(
 +                                "impl",
 +                                &bounds,
 +                                SizedByDefault::Sized { anchor: krate },
 +                                f,
 +                            )?;
 +                        }
 +                    },
 +                    TypeOrConstParamData::ConstParamData(p) => {
 +                        write!(f, "{}", p.name)?;
 +                    }
 +                }
 +            }
 +            TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
 +            TyKind::Dyn(dyn_ty) => {
 +                write_bounds_like_dyn_trait_with_prefix(
 +                    "dyn",
 +                    dyn_ty.bounds.skip_binders().interned(),
 +                    SizedByDefault::NotSized,
 +                    f,
 +                )?;
 +            }
 +            TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
 +            TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
 +                match impl_trait_id {
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        let datas =
 +                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
 +                        let data = (*datas)
 +                            .as_ref()
 +                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                        let bounds = data.substitute(Interner, &opaque_ty.substitution);
 +                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
 +                        write_bounds_like_dyn_trait_with_prefix(
 +                            "impl",
 +                            bounds.skip_binders(),
 +                            SizedByDefault::Sized { anchor: krate },
 +                            f,
 +                        )?;
 +                    }
 +                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
 +                        write!(f, "{{async block}}")?;
 +                    }
 +                };
 +            }
 +            TyKind::Error => {
 +                if f.display_target.is_source_code() {
 +                    return Err(HirDisplayError::DisplaySourceCodeError(
 +                        DisplaySourceCodeError::UnknownType,
 +                    ));
 +                }
 +                write!(f, "{{unknown}}")?;
 +            }
 +            TyKind::InferenceVar(..) => write!(f, "_")?,
 +            TyKind::Generator(..) => write!(f, "{{generator}}")?,
 +            TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for CallableSig {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        write!(f, "fn(")?;
 +        f.write_joined(self.params(), ", ")?;
 +        if self.is_varargs {
 +            if self.params().is_empty() {
 +                write!(f, "...")?;
 +            } else {
 +                write!(f, ", ...")?;
 +            }
 +        }
 +        write!(f, ")")?;
 +        let ret = self.ret();
 +        if !ret.is_unit() {
 +            write!(f, " -> ")?;
 +            ret.hir_fmt(f)?;
 +        }
 +        Ok(())
 +    }
 +}
 +
 +fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
 +    let krate = trait_.lookup(db).container.krate();
 +    utils::fn_traits(db, krate)
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum SizedByDefault {
 +    NotSized,
 +    Sized { anchor: CrateId },
 +}
 +
 +impl SizedByDefault {
 +    fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
 +        match self {
 +            Self::NotSized => false,
 +            Self::Sized { anchor } => {
 +                let sized_trait = db
 +                    .lang_item(anchor, SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait());
 +                Some(trait_) == sized_trait
 +            }
 +        }
 +    }
 +}
 +
 +pub fn write_bounds_like_dyn_trait_with_prefix(
 +    prefix: &str,
 +    predicates: &[QuantifiedWhereClause],
 +    default_sized: SizedByDefault,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    write!(f, "{}", prefix)?;
 +    if !predicates.is_empty()
 +        || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
 +    {
 +        write!(f, " ")?;
 +        write_bounds_like_dyn_trait(predicates, default_sized, f)
 +    } else {
 +        Ok(())
 +    }
 +}
 +
 +fn write_bounds_like_dyn_trait(
 +    predicates: &[QuantifiedWhereClause],
 +    default_sized: SizedByDefault,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    // Note: This code is written to produce nice results (i.e.
 +    // corresponding to surface Rust) for types that can occur in
 +    // actual Rust. It will have weird results if the predicates
 +    // aren't as expected (i.e. self types = $0, projection
 +    // predicates for a certain trait come after the Implemented
 +    // predicate for that trait).
 +    let mut first = true;
 +    let mut angle_open = false;
 +    let mut is_fn_trait = false;
 +    let mut is_sized = false;
 +    for p in predicates.iter() {
 +        match p.skip_binders() {
 +            WhereClause::Implemented(trait_ref) => {
 +                let trait_ = trait_ref.hir_trait_id();
 +                if default_sized.is_sized_trait(trait_, f.db.upcast()) {
 +                    is_sized = true;
 +                    if matches!(default_sized, SizedByDefault::Sized { .. }) {
 +                        // Don't print +Sized, but rather +?Sized if absent.
 +                        continue;
 +                    }
 +                }
 +                if !is_fn_trait {
 +                    is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
 +                }
 +                if !is_fn_trait && angle_open {
 +                    write!(f, ">")?;
 +                    angle_open = false;
 +                }
 +                if !first {
 +                    write!(f, " + ")?;
 +                }
 +                // We assume that the self type is ^0.0 (i.e. the
 +                // existential) here, which is the only thing that's
 +                // possible in actual Rust, and hence don't print it
 +                write!(f, "{}", f.db.trait_data(trait_).name)?;
 +                if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
 +                    if is_fn_trait {
 +                        if let Some(args) =
 +                            params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
 +                        {
 +                            write!(f, "(")?;
 +                            f.write_joined(args.as_slice(Interner), ", ")?;
 +                            write!(f, ")")?;
 +                        }
 +                    } else if !params.is_empty() {
 +                        write!(f, "<")?;
 +                        f.write_joined(params, ", ")?;
 +                        // there might be assoc type bindings, so we leave the angle brackets open
 +                        angle_open = true;
 +                    }
 +                }
 +            }
 +            WhereClause::AliasEq(alias_eq) if is_fn_trait => {
 +                is_fn_trait = false;
 +                if !alias_eq.ty.is_unit() {
 +                    write!(f, " -> ")?;
 +                    alias_eq.ty.hir_fmt(f)?;
 +                }
 +            }
 +            WhereClause::AliasEq(AliasEq { ty, alias }) => {
 +                // in types in actual Rust, these will always come
 +                // after the corresponding Implemented predicate
 +                if angle_open {
 +                    write!(f, ", ")?;
 +                } else {
 +                    write!(f, "<")?;
 +                    angle_open = true;
 +                }
 +                if let AliasTy::Projection(proj) = alias {
 +                    let type_alias =
 +                        f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
 +                    write!(f, "{} = ", type_alias.name)?;
 +                }
 +                ty.hir_fmt(f)?;
 +            }
 +
 +            // FIXME implement these
 +            WhereClause::LifetimeOutlives(_) => {}
 +            WhereClause::TypeOutlives(_) => {}
 +        }
 +        first = false;
 +    }
 +    if angle_open {
 +        write!(f, ">")?;
 +    }
 +    if matches!(default_sized, SizedByDefault::Sized { .. }) {
 +        if !is_sized {
 +            write!(f, "{}?Sized", if first { "" } else { " + " })?;
 +        } else if first {
 +            write!(f, "Sized")?;
 +        }
 +    }
 +    Ok(())
 +}
 +
 +fn fmt_trait_ref(
 +    tr: &TraitRef,
 +    f: &mut HirFormatter<'_>,
 +    use_as: bool,
 +) -> Result<(), HirDisplayError> {
 +    if f.should_truncate() {
 +        return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +    }
 +
 +    tr.self_type_parameter(Interner).hir_fmt(f)?;
 +    if use_as {
 +        write!(f, " as ")?;
 +    } else {
 +        write!(f, ": ")?;
 +    }
 +    write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
 +    if tr.substitution.len(Interner) > 1 {
 +        write!(f, "<")?;
 +        f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
 +        write!(f, ">")?;
 +    }
 +    Ok(())
 +}
 +
 +impl HirDisplay for TraitRef {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        fmt_trait_ref(self, f, false)
 +    }
 +}
 +
 +impl HirDisplay for WhereClause {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        match self {
 +            WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
 +            WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
 +                write!(f, "<")?;
 +                fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
 +                write!(
 +                    f,
 +                    ">::{} = ",
 +                    f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
 +                )?;
 +                ty.hir_fmt(f)?;
 +            }
 +            WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
 +
 +            // FIXME implement these
 +            WhereClause::TypeOutlives(..) => {}
 +            WhereClause::LifetimeOutlives(..) => {}
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for LifetimeOutlives {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        self.a.hir_fmt(f)?;
 +        write!(f, ": ")?;
 +        self.b.hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for Lifetime {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        self.interned().hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for LifetimeData {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
 +            LifetimeData::InferenceVar(_) => write!(f, "_"),
 +            LifetimeData::Placeholder(idx) => {
 +                let id = lt_from_placeholder_idx(f.db, *idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.lifetimes[id.local_id];
 +                write!(f, "{}", param_data.name)
 +            }
 +            LifetimeData::Static => write!(f, "'static"),
 +            LifetimeData::Empty(_) => Ok(()),
 +            LifetimeData::Erased => Ok(()),
 +            LifetimeData::Phantom(_, _) => Ok(()),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for DomainGoal {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            DomainGoal::Holds(wc) => {
 +                write!(f, "Holds(")?;
 +                wc.hir_fmt(f)?;
 +                write!(f, ")")?;
 +            }
 +            _ => write!(f, "?")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +pub fn write_visibility(
 +    module_id: ModuleId,
 +    vis: Visibility,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    match vis {
 +        Visibility::Public => write!(f, "pub "),
 +        Visibility::Module(vis_id) => {
 +            let def_map = module_id.def_map(f.db.upcast());
 +            let root_module_id = def_map.module_id(def_map.root());
 +            if vis_id == module_id {
 +                // pub(self) or omitted
 +                Ok(())
 +            } else if root_module_id == vis_id {
 +                write!(f, "pub(crate) ")
 +            } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
 +                write!(f, "pub(super) ")
 +            } else {
 +                write!(f, "pub(in ...) ")
 +            }
 +        }
 +    }
 +}
 +
 +impl HirDisplay for TypeRef {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            TypeRef::Never => write!(f, "!")?,
 +            TypeRef::Placeholder => write!(f, "_")?,
 +            TypeRef::Tuple(elems) => {
 +                write!(f, "(")?;
 +                f.write_joined(elems, ", ")?;
 +                if elems.len() == 1 {
 +                    write!(f, ",")?;
 +                }
 +                write!(f, ")")?;
 +            }
 +            TypeRef::Path(path) => path.hir_fmt(f)?,
 +            TypeRef::RawPtr(inner, mutability) => {
 +                let mutability = match mutability {
 +                    hir_def::type_ref::Mutability::Shared => "*const ",
 +                    hir_def::type_ref::Mutability::Mut => "*mut ",
 +                };
 +                write!(f, "{}", mutability)?;
 +                inner.hir_fmt(f)?;
 +            }
 +            TypeRef::Reference(inner, lifetime, mutability) => {
 +                let mutability = match mutability {
 +                    hir_def::type_ref::Mutability::Shared => "",
 +                    hir_def::type_ref::Mutability::Mut => "mut ",
 +                };
 +                write!(f, "&")?;
 +                if let Some(lifetime) = lifetime {
 +                    write!(f, "{} ", lifetime.name)?;
 +                }
 +                write!(f, "{}", mutability)?;
 +                inner.hir_fmt(f)?;
 +            }
 +            TypeRef::Array(inner, len) => {
 +                write!(f, "[")?;
 +                inner.hir_fmt(f)?;
 +                write!(f, "; {}]", len)?;
 +            }
 +            TypeRef::Slice(inner) => {
 +                write!(f, "[")?;
 +                inner.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TypeRef::Fn(parameters, is_varargs) => {
 +                // FIXME: Function pointer qualifiers.
 +                write!(f, "fn(")?;
 +                if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
 +                    for index in 0..function_parameters.len() {
 +                        let (param_name, param_type) = &function_parameters[index];
 +                        if let Some(name) = param_name {
 +                            write!(f, "{}: ", name)?;
 +                        }
 +
 +                        param_type.hir_fmt(f)?;
 +
 +                        if index != function_parameters.len() - 1 {
 +                            write!(f, ", ")?;
 +                        }
 +                    }
 +                    if *is_varargs {
 +                        write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
 +                    }
 +                    write!(f, ")")?;
 +                    match &return_type {
 +                        TypeRef::Tuple(tup) if tup.is_empty() => {}
 +                        _ => {
 +                            write!(f, " -> ")?;
 +                            return_type.hir_fmt(f)?;
 +                        }
 +                    }
 +                }
 +            }
 +            TypeRef::ImplTrait(bounds) => {
 +                write!(f, "impl ")?;
 +                f.write_joined(bounds, " + ")?;
 +            }
 +            TypeRef::DynTrait(bounds) => {
 +                write!(f, "dyn ")?;
 +                f.write_joined(bounds, " + ")?;
 +            }
 +            TypeRef::Macro(macro_call) => {
 +                let macro_call = macro_call.to_node(f.db.upcast());
 +                let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic());
 +                match macro_call.path() {
 +                    Some(path) => match Path::from_src(path, &ctx) {
 +                        Some(path) => path.hir_fmt(f)?,
 +                        None => write!(f, "{{macro}}")?,
 +                    },
 +                    None => write!(f, "{{macro}}")?,
 +                }
 +                write!(f, "!(..)")?;
 +            }
 +            TypeRef::Error => write!(f, "{{error}}")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for TypeBound {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            TypeBound::Path(path, modifier) => {
 +                match modifier {
 +                    TraitBoundModifier::None => (),
 +                    TraitBoundModifier::Maybe => write!(f, "?")?,
 +                }
 +                path.hir_fmt(f)
 +            }
 +            TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
 +            TypeBound::ForLifetime(lifetimes, path) => {
 +                write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
 +                path.hir_fmt(f)
 +            }
 +            TypeBound::Error => write!(f, "{{error}}"),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for Path {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match (self.type_anchor(), self.kind()) {
 +            (Some(anchor), _) => {
 +                write!(f, "<")?;
 +                anchor.hir_fmt(f)?;
 +                write!(f, ">")?;
 +            }
 +            (_, PathKind::Plain) => {}
 +            (_, PathKind::Abs) => {}
 +            (_, PathKind::Crate) => write!(f, "crate")?,
 +            (_, PathKind::Super(0)) => write!(f, "self")?,
 +            (_, PathKind::Super(n)) => {
 +                for i in 0..*n {
 +                    if i > 0 {
 +                        write!(f, "::")?;
 +                    }
 +                    write!(f, "super")?;
 +                }
 +            }
 +            (_, PathKind::DollarCrate(id)) => {
 +                // Resolve `$crate` to the crate's display name.
 +                // FIXME: should use the dependency name instead if available, but that depends on
 +                // the crate invoking `HirDisplay`
 +                let crate_graph = f.db.crate_graph();
 +                let name = crate_graph[*id]
 +                    .display_name
 +                    .as_ref()
 +                    .map(|name| name.canonical_name())
 +                    .unwrap_or("$crate");
 +                write!(f, "{name}")?
 +            }
 +        }
 +
 +        for (seg_idx, segment) in self.segments().iter().enumerate() {
 +            if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
 +                write!(f, "::")?;
 +            }
 +            write!(f, "{}", segment.name)?;
 +            if let Some(generic_args) = segment.args_and_bindings {
 +                // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
 +                // Do we actually format expressions?
 +                if generic_args.desugared_from_fn {
 +                    // First argument will be a tuple, which already includes the parentheses.
 +                    // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
 +                    if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
 +                        &generic_args.args[0]
 +                    {
 +                        if v.len() == 1 {
 +                            write!(f, "(")?;
 +                            v[0].hir_fmt(f)?;
 +                            write!(f, ")")?;
 +                        } else {
 +                            generic_args.args[0].hir_fmt(f)?;
 +                        }
 +                    }
 +                    if let Some(ret) = &generic_args.bindings[0].type_ref {
 +                        if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
 +                            write!(f, " -> ")?;
 +                            ret.hir_fmt(f)?;
 +                        }
 +                    }
 +                    return Ok(());
 +                }
 +
 +                write!(f, "<")?;
 +                let mut first = true;
 +                for arg in &generic_args.args {
 +                    if first {
 +                        first = false;
 +                        if generic_args.has_self_type {
 +                            // FIXME: Convert to `<Ty as Trait>` form.
 +                            write!(f, "Self = ")?;
 +                        }
 +                    } else {
 +                        write!(f, ", ")?;
 +                    }
 +                    arg.hir_fmt(f)?;
 +                }
 +                for binding in &generic_args.bindings {
 +                    if first {
 +                        first = false;
 +                    } else {
 +                        write!(f, ", ")?;
 +                    }
 +                    write!(f, "{}", binding.name)?;
 +                    match &binding.type_ref {
 +                        Some(ty) => {
 +                            write!(f, " = ")?;
 +                            ty.hir_fmt(f)?
 +                        }
 +                        None => {
 +                            write!(f, ": ")?;
 +                            f.write_joined(&binding.bounds, " + ")?;
 +                        }
 +                    }
 +                }
 +                write!(f, ">")?;
 +            }
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for hir_def::path::GenericArg {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
 +            hir_def::path::GenericArg::Const(c) => write!(f, "{}", c),
 +            hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
 +        }
 +    }
 +}
index 10ffde87eef1491b4c6777db2c19309ff6f36f4e,0000000000000000000000000000000000000000..e37763e8ea7f03075b5c19349d4c7d5ff1baf69d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1119 -1,0 +1,1114 @@@
-     fn resolve_obligations_as_possible(&mut self) {
-         self.table.resolve_obligations_as_possible();
-     }
 +//! Type inference, i.e. the process of walking through the code and determining
 +//! the type of each expression and pattern.
 +//!
 +//! For type inference, compare the implementations in rustc (the various
 +//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
 +//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
 +//! inference here is the `infer` function, which infers the types of all
 +//! expressions in a given function.
 +//!
 +//! During inference, types (i.e. the `Ty` struct) can contain type 'variables'
 +//! which represent currently unknown types; as we walk through the expressions,
 +//! we might determine that certain variables need to be equal to each other, or
 +//! to certain types. To record this, we use the union-find implementation from
 +//! the `ena` crate, which is extracted from rustc.
 +
 +use std::ops::Index;
 +use std::sync::Arc;
 +
 +use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 +use hir_def::{
 +    body::Body,
 +    data::{ConstData, StaticData},
 +    expr::{BindingAnnotation, ExprId, PatId},
 +    lang_item::LangItemTarget,
 +    path::{path, Path},
 +    resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
 +    type_ref::TypeRef,
 +    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
 +    TraitId, TypeAliasId, VariantId,
 +};
 +use hir_expand::name::{name, Name};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashMap;
 +use stdx::{always, impl_from};
 +
 +use crate::{
 +    db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
 +    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
 +    GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
 +    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +// This lint has a false positive here. See the link below for details.
 +//
 +// https://github.com/rust-lang/rust/issues/57411
 +#[allow(unreachable_pub)]
 +pub use coerce::could_coerce;
 +#[allow(unreachable_pub)]
 +pub use unify::could_unify;
 +
 +pub(crate) mod unify;
 +mod path;
 +mod expr;
 +mod pat;
 +mod coerce;
 +mod closure;
 +
 +/// The entry point of type inference.
 +pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
 +    let _p = profile::span("infer_query");
 +    let resolver = def.resolver(db.upcast());
 +    let body = db.body(def);
 +    let mut ctx = InferenceContext::new(db, def, &body, resolver);
 +
 +    match def {
 +        DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
 +        DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
 +        DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
 +    }
 +
 +    ctx.infer_body();
 +
 +    Arc::new(ctx.resolve_all())
 +}
 +
 +/// Fully normalize all the types found within `ty` in context of `owner` body definition.
 +///
 +/// This is appropriate to use only after type-check: it assumes
 +/// that normalization will succeed, for example.
 +pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
 +    if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
 +        return ty;
 +    }
 +    let krate = owner.module(db.upcast()).krate();
 +    let trait_env = owner
 +        .as_generic_def_id()
 +        .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +    let mut table = unify::InferenceTable::new(db, trait_env);
 +
 +    let ty_with_vars = table.normalize_associated_types_in(ty);
 +    table.resolve_obligations_as_possible();
 +    table.propagate_diverging_flag();
 +    table.resolve_completely(ty_with_vars)
 +}
 +
 +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 +enum ExprOrPatId {
 +    ExprId(ExprId),
 +    PatId(PatId),
 +}
 +impl_from!(ExprId, PatId for ExprOrPatId);
 +
 +/// Binding modes inferred for patterns.
 +/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +impl BindingMode {
 +    fn convert(annotation: BindingAnnotation) -> BindingMode {
 +        match annotation {
 +            BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
 +            BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
 +            BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
 +        }
 +    }
 +}
 +
 +impl Default for BindingMode {
 +    fn default() -> Self {
 +        BindingMode::Move
 +    }
 +}
 +
 +/// Used to generalize patterns and assignee expressions.
 +trait PatLike: Into<ExprOrPatId> + Copy {
 +    type BindingMode: Copy;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty;
 +}
 +
 +impl PatLike for ExprId {
 +    type BindingMode = ();
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        _: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_assignee_expr(id, expected_ty)
 +    }
 +}
 +
 +impl PatLike for PatId {
 +    type BindingMode = BindingMode;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_pat(id, expected_ty, default_bm)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct InferOk<T> {
 +    value: T,
 +    goals: Vec<InEnvironment<Goal>>,
 +}
 +
 +impl<T> InferOk<T> {
 +    fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
 +        InferOk { value: f(self.value), goals: self.goals }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct TypeError;
 +pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum InferenceDiagnostic {
 +    NoSuchField { expr: ExprId },
 +    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
 +    MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 +}
 +
 +/// A mismatch between an expected and an inferred type.
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct TypeMismatch {
 +    pub expected: Ty,
 +    pub actual: Ty,
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +struct InternedStandardTypes {
 +    unknown: Ty,
 +    bool_: Ty,
 +    unit: Ty,
 +}
 +
 +impl Default for InternedStandardTypes {
 +    fn default() -> Self {
 +        InternedStandardTypes {
 +            unknown: TyKind::Error.intern(Interner),
 +            bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
 +        }
 +    }
 +}
 +/// Represents coercing a value to a different type of value.
 +///
 +/// We transform values by following a number of `Adjust` steps in order.
 +/// See the documentation on variants of `Adjust` for more details.
 +///
 +/// Here are some common scenarios:
 +///
 +/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 +///    Here the pointer will be dereferenced N times (where a dereference can
 +///    happen to raw or borrowed pointers or any smart pointer which implements
 +///    Deref, including Box<_>). The types of dereferences is given by
 +///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 +///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 +///    `false`.
 +///
 +/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
 +///    with a thin pointer, deref a number of times, unsize the underlying data,
 +///    then autoref. The 'unsize' phase may change a fixed length array to a
 +///    dynamically sized one, a concrete object to a trait object, or statically
 +///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
 +///    represented by:
 +///
 +///    ```
 +///    Deref(None) -> [i32; 4],
 +///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
 +///    Unsize -> &[i32],
 +///    ```
 +///
 +///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
 +///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
 +///    The autoderef and -ref are the same as in the above example, but the type
 +///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 +///    the underlying conversions from `[i32; 4]` to `[i32]`.
 +///
 +/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
 +///    that case, we have the pointer we need coming in, so there are no
 +///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 +///    At some point, of course, `Box` should move out of the compiler, in which
 +///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
 +///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
 +#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 +pub struct Adjustment {
 +    pub kind: Adjust,
 +    pub target: Ty,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adjust {
 +    /// Go from ! to any type.
 +    NeverToAny,
 +    /// Dereference once, producing a place.
 +    Deref(Option<OverloadedDeref>),
 +    /// Take the address and produce either a `&` or `*` pointer.
 +    Borrow(AutoBorrow),
 +    Pointer(PointerCast),
 +}
 +
 +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
 +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 +/// The target type is `U` in both cases, with the region and mutability
 +/// being those shared by both the receiver and the returned reference.
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct OverloadedDeref(pub Mutability);
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AutoBorrow {
 +    /// Converts from T to &T.
 +    Ref(Mutability),
 +    /// Converts from T to *T.
 +    RawPtr(Mutability),
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum PointerCast {
 +    /// Go from a fn-item type to a fn-pointer type.
 +    ReifyFnPointer,
 +
 +    /// Go from a safe fn pointer to an unsafe fn pointer.
 +    UnsafeFnPointer,
 +
 +    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
 +    /// It cannot convert a closure that requires unsafe.
 +    ClosureFnPointer(Safety),
 +
 +    /// Go from a mut raw pointer to a const raw pointer.
 +    MutToConstPointer,
 +
 +    #[allow(dead_code)]
 +    /// Go from `*const [T; N]` to `*const T`
 +    ArrayToPointer,
 +
 +    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
 +    /// `&[T]`. Note that the source could be a thin or fat pointer.
 +    /// This will do things like convert thin pointers to fat
 +    /// pointers, or convert structs containing thin pointers to
 +    /// structs containing fat pointers, or convert between fat
 +    /// pointers. We don't store the details of how the transform is
 +    /// done (in fact, we don't know that, because it might depend on
 +    /// the precise type parameters). We just store the target
 +    /// type. Codegen backends and miri figure out what has to be done
 +    /// based on the precise source/target type at hand.
 +    Unsize,
 +}
 +
 +/// The result of type inference: A mapping from expressions and patterns to types.
 +#[derive(Clone, PartialEq, Eq, Debug, Default)]
 +pub struct InferenceResult {
 +    /// For each method call expr, records the function it resolves to.
 +    method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
 +    /// For each field access expr, records the field it resolves to.
 +    field_resolutions: FxHashMap<ExprId, FieldId>,
 +    /// For each struct literal or pattern, records the variant it resolves to.
 +    variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
 +    /// For each associated item record what it resolves to
 +    assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
 +    pub diagnostics: Vec<InferenceDiagnostic>,
 +    pub type_of_expr: ArenaMap<ExprId, Ty>,
 +    /// For each pattern record the type it resolves to.
 +    ///
 +    /// **Note**: When a pattern type is resolved it may still contain
 +    /// unresolved or missing subpatterns or subpatterns of mismatched types.
 +    pub type_of_pat: ArenaMap<PatId, Ty>,
 +    type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
 +    /// Interned Unknown to return references to.
 +    standard_types: InternedStandardTypes,
 +    /// Stores the types which were implicitly dereferenced in pattern binding modes.
 +    pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
 +    pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
 +    pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
 +}
 +
 +impl InferenceResult {
 +    pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
 +        self.method_resolutions.get(&expr).cloned()
 +    }
 +    pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
 +        self.field_resolutions.get(&expr).copied()
 +    }
 +    pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&expr.into())
 +    }
 +    pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&pat.into())
 +    }
 +    pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
 +            _ => None,
 +        })
 +    }
 +    pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
 +            _ => None,
 +        })
 +    }
 +}
 +
 +impl Index<ExprId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, expr: ExprId) -> &Ty {
 +        self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +impl Index<PatId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, pat: PatId) -> &Ty {
 +        self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +/// The inference context contains all information needed during type inference.
 +#[derive(Clone, Debug)]
 +pub(crate) struct InferenceContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) owner: DefWithBodyId,
 +    pub(crate) body: &'a Body,
 +    pub(crate) resolver: Resolver,
 +    table: unify::InferenceTable<'a>,
 +    trait_env: Arc<TraitEnvironment>,
 +    pub(crate) result: InferenceResult,
 +    /// The return type of the function being inferred, the closure or async block if we're
 +    /// currently within one.
 +    ///
 +    /// We might consider using a nested inference context for checking
 +    /// closures, but currently this is the only field that will change there,
 +    /// so it doesn't make sense.
 +    return_ty: Ty,
 +    diverges: Diverges,
 +    breakables: Vec<BreakableContext>,
 +}
 +
 +#[derive(Clone, Debug)]
 +struct BreakableContext {
 +    /// Whether this context contains at least one break expression.
 +    may_break: bool,
 +    /// The coercion target of the context.
 +    coerce: CoerceMany,
 +    /// The optional label of the context.
 +    label: Option<name::Name>,
 +    kind: BreakableKind,
 +}
 +
 +#[derive(Clone, Debug)]
 +enum BreakableKind {
 +    Block,
 +    Loop,
 +    /// A border is something like an async block, closure etc. Anything that prevents
 +    /// breaking/continuing through
 +    Border,
 +}
 +
 +fn find_breakable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    let mut ctxs = ctxs
 +        .iter_mut()
 +        .rev()
 +        .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
 +    match label {
 +        Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
 +        None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
 +    }
 +}
 +
 +fn find_continuable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    match label {
 +        Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
 +        None => find_breakable(ctxs, label),
 +    }
 +}
 +
 +impl<'a> InferenceContext<'a> {
 +    fn new(
 +        db: &'a dyn HirDatabase,
 +        owner: DefWithBodyId,
 +        body: &'a Body,
 +        resolver: Resolver,
 +    ) -> Self {
 +        let krate = owner.module(db.upcast()).krate();
 +        let trait_env = owner
 +            .as_generic_def_id()
 +            .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +        InferenceContext {
 +            result: InferenceResult::default(),
 +            table: unify::InferenceTable::new(db, trait_env.clone()),
 +            trait_env,
 +            return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
 +            db,
 +            owner,
 +            body,
 +            resolver,
 +            diverges: Diverges::Maybe,
 +            breakables: Vec::new(),
 +        }
 +    }
 +
 +    fn resolve_all(self) -> InferenceResult {
 +        let InferenceContext { mut table, mut result, .. } = self;
 +
 +        // FIXME resolve obligations as well (use Guidance if necessary)
 +        table.resolve_obligations_as_possible();
 +
 +        // make sure diverging type variables are marked as such
 +        table.propagate_diverging_flag();
 +        for ty in result.type_of_expr.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for ty in result.type_of_pat.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for mismatch in result.type_mismatches.values_mut() {
 +            mismatch.expected = table.resolve_completely(mismatch.expected.clone());
 +            mismatch.actual = table.resolve_completely(mismatch.actual.clone());
 +        }
 +        for (_, subst) in result.method_resolutions.values_mut() {
 +            *subst = table.resolve_completely(subst.clone());
 +        }
 +        for adjustment in result.expr_adjustments.values_mut().flatten() {
 +            adjustment.target = table.resolve_completely(adjustment.target.clone());
 +        }
 +        for adjustment in result.pat_adjustments.values_mut().flatten() {
 +            *adjustment = table.resolve_completely(adjustment.clone());
 +        }
 +        result
 +    }
 +
 +    fn collect_const(&mut self, data: &ConstData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_static(&mut self, data: &StaticData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_fn(&mut self, func: FunctionId) {
 +        let data = self.db.function_data(func);
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
 +        let param_tys =
 +            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
 +        for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
 +            let ty = self.insert_type_vars(ty);
 +            let ty = self.normalize_associated_types_in(ty);
 +
 +            self.infer_pat(*pat, &ty, BindingMode::default());
 +        }
 +        let error_ty = &TypeRef::Error;
 +        let return_ty = if data.has_async_kw() {
 +            data.async_ret_type.as_deref().unwrap_or(error_ty)
 +        } else {
 +            &*data.ret_type
 +        };
 +        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
 +        self.return_ty = return_ty;
 +
 +        if let Some(rpits) = self.db.return_type_impl_traits(func) {
 +            // RPIT opaque types use substitution of their parent function.
 +            let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
 +            self.return_ty = fold_tys(
 +                self.return_ty.clone(),
 +                |ty, _| {
 +                    let opaque_ty_id = match ty.kind(Interner) {
 +                        TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
 +                        _ => return ty,
 +                    };
 +                    let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
 +                        ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
 +                        _ => unreachable!(),
 +                    };
 +                    let bounds = (*rpits).map_ref(|rpits| {
 +                        rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
 +                    });
 +                    let var = self.table.new_type_var();
 +                    let var_subst = Substitution::from1(Interner, var.clone());
 +                    for bound in bounds {
 +                        let predicate =
 +                            bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
 +                        let (var_predicate, binders) = predicate
 +                            .substitute(Interner, &var_subst)
 +                            .into_value_and_skipped_binders();
 +                        always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                        self.push_obligation(var_predicate.cast(Interner));
 +                    }
 +                    var
 +                },
 +                DebruijnIndex::INNERMOST,
 +            );
 +        }
 +    }
 +
 +    fn infer_body(&mut self) {
 +        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
 +    }
 +
 +    fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
 +        self.result.type_of_expr.insert(expr, ty);
 +    }
 +
 +    fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
 +        self.result.expr_adjustments.insert(expr, adjustments);
 +    }
 +
 +    fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
 +        self.result.method_resolutions.insert(expr, (func, subst));
 +    }
 +
 +    fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
 +        self.result.variant_resolutions.insert(id, variant);
 +    }
 +
 +    fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
 +        self.result.assoc_resolutions.insert(id, item);
 +    }
 +
 +    fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
 +        self.result.type_of_pat.insert(pat, ty);
 +    }
 +
 +    fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
 +        self.result.diagnostics.push(diagnostic);
 +    }
 +
 +    fn make_ty_with_mode(
 +        &mut self,
 +        type_ref: &TypeRef,
 +        impl_trait_mode: ImplTraitLoweringMode,
 +    ) -> Ty {
 +        // FIXME use right resolver for block
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(impl_trait_mode);
 +        let ty = ctx.lower_ty(type_ref);
 +        let ty = self.insert_type_vars(ty);
 +        self.normalize_associated_types_in(ty)
 +    }
 +
 +    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
 +        self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
 +    }
 +
 +    fn err_ty(&self) -> Ty {
 +        self.result.standard_types.unknown.clone()
 +    }
 +
 +    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
 +        let data = c.data(Interner);
 +        match data.value {
 +            ConstValue::Concrete(cc) => match cc.interned {
 +                hir_def::type_ref::ConstScalar::Unknown => {
 +                    self.table.new_const_var(data.ty.clone())
 +                }
 +                _ => c,
 +            },
 +            _ => c,
 +        }
 +    }
 +
 +    /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
 +        match ty.kind(Interner) {
 +            TyKind::Error => self.table.new_type_var(),
 +            TyKind::InferenceVar(..) => {
 +                let ty_resolved = self.resolve_ty_shallow(&ty);
 +                if ty_resolved.is_unknown() {
 +                    self.table.new_type_var()
 +                } else {
 +                    ty
 +                }
 +            }
 +            _ => ty,
 +        }
 +    }
 +
 +    fn insert_type_vars(&mut self, ty: Ty) -> Ty {
 +        fold_tys_and_consts(
 +            ty,
 +            |x, _| match x {
 +                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
 +                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
 +            },
 +            DebruijnIndex::INNERMOST,
 +        )
 +    }
 +
-         self.resolve_obligations_as_possible();
 +    fn push_obligation(&mut self, o: DomainGoal) {
 +        self.table.register_obligation(o.cast(Interner));
 +    }
 +
 +    fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
 +        self.table.unify(ty1, ty2)
 +    }
 +
 +    /// Recurses through the given type, normalizing associated types mentioned
 +    /// in it by replacing them by type variables and registering obligations to
 +    /// resolve later. This should be done once for every type we get from some
 +    /// type annotation (e.g. from a let type annotation, field type or function
 +    /// call). `make_ty` handles this already, but e.g. for field types we need
 +    /// to do it as well.
 +    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
 +        self.table.normalize_associated_types_in(ty)
 +    }
 +
 +    fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
 +        self.table.resolve_ty_shallow(ty)
 +    }
 +
 +    fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
 +        self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
 +    }
 +
 +    fn resolve_associated_type_with_params(
 +        &mut self,
 +        inner_ty: Ty,
 +        assoc_ty: Option<TypeAliasId>,
 +        params: &[GenericArg],
 +    ) -> Ty {
 +        match assoc_ty {
 +            Some(res_assoc_ty) => {
 +                let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
 +                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
 +                    _ => panic!("resolve_associated_type called with non-associated type"),
 +                };
 +                let ty = self.table.new_type_var();
 +                let mut param_iter = params.iter().cloned();
 +                let trait_ref = TyBuilder::trait_ref(self.db, trait_)
 +                    .push(inner_ty)
 +                    .fill(|_| param_iter.next().unwrap())
 +                    .build();
 +                let alias_eq = AliasEq {
 +                    alias: AliasTy::Projection(ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(res_assoc_ty),
 +                        substitution: trait_ref.substitution.clone(),
 +                    }),
 +                    ty: ty.clone(),
 +                };
 +                self.push_obligation(trait_ref.cast(Interner));
 +                self.push_obligation(alias_eq.cast(Interner));
 +                ty
 +            }
 +            None => self.err_ty(),
 +        }
 +    }
 +
 +    fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
 +        let path = match path {
 +            Some(path) => path,
 +            None => return (self.err_ty(), None),
 +        };
 +        let resolver = &self.resolver;
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
 +        // FIXME: this should resolve assoc items as well, see this example:
 +        // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
 +        let (resolution, unresolved) = if value_ns {
 +            match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
 +                Some(ResolveValueResult::ValueNs(value)) => match value {
 +                    ValueNs::EnumVariantId(var) => {
 +                        let substs = ctx.substs_from_path(path, var.into(), true);
 +                        let ty = self.db.ty(var.parent.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(var.into()));
 +                    }
 +                    ValueNs::StructId(strukt) => {
 +                        let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                        let ty = self.db.ty(strukt.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(strukt.into()));
 +                    }
 +                    ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
 +                    _ => return (self.err_ty(), None),
 +                },
 +                Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
 +                None => return (self.err_ty(), None),
 +            }
 +        } else {
 +            match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (self.err_ty(), None),
 +            }
 +        };
 +        return match resolution {
 +            TypeNs::AdtId(AdtId::StructId(strukt)) => {
 +                let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                let ty = self.db.ty(strukt.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
 +            }
 +            TypeNs::AdtId(AdtId::UnionId(u)) => {
 +                let substs = ctx.substs_from_path(path, u.into(), true);
 +                let ty = self.db.ty(u.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(u.into())), unresolved)
 +            }
 +            TypeNs::EnumVariantId(var) => {
 +                let substs = ctx.substs_from_path(path, var.into(), true);
 +                let ty = self.db.ty(var.parent.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(var.into())), unresolved)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
 +                let substs = generics.placeholder_subst(self.db);
 +                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                let ty = TyBuilder::def_ty(self.db, it.into())
 +                    .fill_with_inference_vars(&mut self.table)
 +                    .build();
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::AdtSelfType(_) => {
 +                // FIXME this could happen in array size expressions, once we're checking them
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::GenericParam(_) => {
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        };
 +
 +        fn forbid_unresolved_segments(
 +            result: (Ty, Option<VariantId>),
 +            unresolved: Option<usize>,
 +        ) -> (Ty, Option<VariantId>) {
 +            if unresolved.is_none() {
 +                result
 +            } else {
 +                // FIXME diagnostic
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_variant_on_alias(
 +        &mut self,
 +        ty: Ty,
 +        unresolved: Option<usize>,
 +        path: &Path,
 +    ) -> (Ty, Option<VariantId>) {
 +        let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0);
 +        match remaining {
 +            None => {
 +                let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
 +                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
 +                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
 +                    AdtId::EnumId(_) => {
 +                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
 +                        None
 +                    }
 +                });
 +                (ty, variant)
 +            }
 +            Some(1) => {
 +                let segment = path.mod_path().segments().last().unwrap();
 +                // this could be an enum variant or associated type
 +                if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
 +                    let enum_data = self.db.enum_data(enum_id);
 +                    if let Some(local_id) = enum_data.variant(segment) {
 +                        let variant = EnumVariantId { parent: enum_id, local_id };
 +                        return (ty, Some(variant.into()));
 +                    }
 +                }
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            Some(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
 +        let krate = self.resolver.krate();
 +        self.db.lang_item(krate, name.to_smol_str())
 +    }
 +
 +    fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::IntoIterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Item])
 +    }
 +
 +    fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
 +        // FIXME resolve via lang_item once try v2 is stable
 +        let path = path![core::ops::Try];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        let trait_data = self.db.trait_data(trait_);
 +        trait_data
 +            // FIXME remove once try v2 is stable
 +            .associated_type_by_name(&name![Ok])
 +            .or_else(|| trait_data.associated_type_by_name(&name![Output]))
 +    }
 +
 +    fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self
 +            .resolver
 +            .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
 +            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_boxed_box(&self) -> Option<AdtId> {
 +        let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_full(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFull];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range(&self) -> Option<AdtId> {
 +        let path = path![core::ops::Range];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_from(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFrom];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeTo];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeToInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_ops_index(&self) -> Option<TraitId> {
 +        self.resolve_lang_item(name![index])?.as_trait()
 +    }
 +
 +    fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_ops_index()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +}
 +
 +/// When inferring an expression, we propagate downward whatever type hint we
 +/// are able in the form of an `Expectation`.
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub(crate) enum Expectation {
 +    None,
 +    HasType(Ty),
 +    // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
 +    RValueLikeUnsized(Ty),
 +}
 +
 +impl Expectation {
 +    /// The expectation that the type of the expression needs to equal the given
 +    /// type.
 +    fn has_type(ty: Ty) -> Self {
 +        if ty.is_unknown() {
 +            // FIXME: get rid of this?
 +            Expectation::None
 +        } else {
 +            Expectation::HasType(ty)
 +        }
 +    }
 +
 +    fn from_option(ty: Option<Ty>) -> Self {
 +        ty.map_or(Expectation::None, Expectation::HasType)
 +    }
 +
 +    /// The following explanation is copied straight from rustc:
 +    /// Provides an expectation for an rvalue expression given an *optional*
 +    /// hint, which is not required for type safety (the resulting type might
 +    /// be checked higher up, as is the case with `&expr` and `box expr`), but
 +    /// is useful in determining the concrete type.
 +    ///
 +    /// The primary use case is where the expected type is a fat pointer,
 +    /// like `&[isize]`. For example, consider the following statement:
 +    ///
 +    ///    let x: &[isize] = &[1, 2, 3];
 +    ///
 +    /// In this case, the expected type for the `&[1, 2, 3]` expression is
 +    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
 +    /// expectation `ExpectHasType([isize])`, that would be too strong --
 +    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
 +    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
 +    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
 +    /// which still is useful, because it informs integer literals and the like.
 +    /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
 +    /// for examples of where this comes up,.
 +    fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self {
 +        // FIXME: do struct_tail_without_normalization
 +        match table.resolve_ty_shallow(&ty).kind(Interner) {
 +            TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
 +            _ => Expectation::has_type(ty),
 +        }
 +    }
 +
 +    /// This expresses no expectation on the type.
 +    fn none() -> Self {
 +        Expectation::None
 +    }
 +
 +    fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::None => Expectation::None,
 +            Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
 +            Expectation::RValueLikeUnsized(t) => {
 +                Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
 +            }
 +        }
 +    }
 +
 +    fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self.resolve(table) {
 +            Expectation::None => None,
 +            Expectation::HasType(t) |
 +            // Expectation::Castable(t) |
 +            Expectation::RValueLikeUnsized(t) => Some(t),
 +        }
 +    }
 +
 +    fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self {
 +            Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
 +            // Expectation::Castable(_) |
 +            Expectation::RValueLikeUnsized(_) | Expectation::None => None,
 +        }
 +    }
 +
 +    /// Comment copied from rustc:
 +    /// Disregard "castable to" expectations because they
 +    /// can lead us astray. Consider for example `if cond
 +    /// {22} else {c} as u8` -- if we propagate the
 +    /// "castable to u8" constraint to 22, it will pick the
 +    /// type 22u8, which is overly constrained (c might not
 +    /// be a u8). In effect, the problem is that the
 +    /// "castable to" expectation is not the tightest thing
 +    /// we can say, so we want to drop it in this case.
 +    /// The tightest thing we can say is "must unify with
 +    /// else branch". Note that in the case of a "has type"
 +    /// constraint, this limitation does not hold.
 +    ///
 +    /// If the expected type is just a type variable, then don't use
 +    /// an expected type. Otherwise, we might write parts of the type
 +    /// when checking the 'then' block which are incompatible with the
 +    /// 'else' branch.
 +    fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::HasType(ety) => {
 +                let ety = table.resolve_ty_shallow(ety);
 +                if !ety.is_ty_var() {
 +                    Expectation::HasType(ety)
 +                } else {
 +                    Expectation::None
 +                }
 +            }
 +            Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
 +            _ => Expectation::None,
 +        }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 +enum Diverges {
 +    Maybe,
 +    Always,
 +}
 +
 +impl Diverges {
 +    fn is_always(self) -> bool {
 +        self == Diverges::Always
 +    }
 +}
 +
 +impl std::ops::BitAnd for Diverges {
 +    type Output = Self;
 +    fn bitand(self, other: Self) -> Self {
 +        std::cmp::min(self, other)
 +    }
 +}
 +
 +impl std::ops::BitOr for Diverges {
 +    type Output = Self;
 +    fn bitor(self, other: Self) -> Self {
 +        std::cmp::max(self, other)
 +    }
 +}
 +
 +impl std::ops::BitAndAssign for Diverges {
 +    fn bitand_assign(&mut self, other: Self) {
 +        *self = *self & other;
 +    }
 +}
 +
 +impl std::ops::BitOrAssign for Diverges {
 +    fn bitor_assign(&mut self, other: Self) {
 +        *self = *self | other;
 +    }
 +}
index a82a331d4b8750e99c5fb8f69b6b04cf8007e96e,0000000000000000000000000000000000000000..de4a5446e57f00e948bee718ae6013dcddbb99b7
mode 100644,000000..100644
--- /dev/null
@@@ -1,526 -1,0 +1,512 @@@
- // FIXME: get rid of this
- pub fn make_canonical<T: HasInterner<Interner = Interner>>(
-     value: T,
-     kinds: impl IntoIterator<Item = TyVariableKind>,
- ) -> Canonical<T> {
-     let kinds = kinds.into_iter().map(|tk| {
-         chalk_ir::CanonicalVarKind::new(
-             chalk_ir::VariableKind::Ty(tk),
-             chalk_ir::UniverseIndex::ROOT,
-         )
-     });
-     Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
- }
 +//! The type system. We currently use this to infer types for completion, hover
 +//! information and various assists.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod autoderef;
 +mod builder;
 +mod chalk_db;
 +mod chalk_ext;
 +pub mod consteval;
 +mod infer;
 +mod inhabitedness;
 +mod interner;
 +mod lower;
 +mod mapping;
 +mod tls;
 +mod utils;
 +mod walk;
 +pub mod db;
 +pub mod diagnostics;
 +pub mod display;
 +pub mod method_resolution;
 +pub mod primitive;
 +pub mod traits;
 +
 +#[cfg(test)]
 +mod tests;
 +#[cfg(test)]
 +mod test_db;
 +
 +use std::sync::Arc;
 +
 +use chalk_ir::{
 +    fold::{Shift, TypeFoldable},
 +    interner::HasInterner,
 +    NoSolution,
 +};
 +use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
 +use itertools::Either;
 +use utils::Generics;
 +
 +use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
 +
 +pub use autoderef::autoderef;
 +pub use builder::{ParamKind, TyBuilder};
 +pub use chalk_ext::*;
 +pub use infer::{
 +    could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
 +    InferenceResult,
 +};
 +pub use interner::Interner;
 +pub use lower::{
 +    associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, TyDefId,
 +    TyLoweringContext, ValueTyDefId,
 +};
 +pub use mapping::{
 +    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
 +    lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
 +    to_placeholder_idx,
 +};
 +pub use traits::TraitEnvironment;
 +pub use utils::{all_super_traits, is_fn_unsafe_to_call};
 +pub use walk::TypeWalk;
 +
 +pub use chalk_ir::{
 +    cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
 +};
 +
 +pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
 +pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
 +pub type FnDefId = chalk_ir::FnDefId<Interner>;
 +pub type ClosureId = chalk_ir::ClosureId<Interner>;
 +pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
 +pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
 +
 +pub type VariableKind = chalk_ir::VariableKind<Interner>;
 +pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
 +pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
 +pub type Binders<T> = chalk_ir::Binders<T>;
 +pub type Substitution = chalk_ir::Substitution<Interner>;
 +pub type GenericArg = chalk_ir::GenericArg<Interner>;
 +pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
 +
 +pub type Ty = chalk_ir::Ty<Interner>;
 +pub type TyKind = chalk_ir::TyKind<Interner>;
 +pub type DynTy = chalk_ir::DynTy<Interner>;
 +pub type FnPointer = chalk_ir::FnPointer<Interner>;
 +// pub type FnSubst = chalk_ir::FnSubst<Interner>;
 +pub use chalk_ir::FnSubst;
 +pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
 +pub type AliasTy = chalk_ir::AliasTy<Interner>;
 +pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
 +pub type InferenceVar = chalk_ir::InferenceVar;
 +
 +pub type Lifetime = chalk_ir::Lifetime<Interner>;
 +pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
 +pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
 +
 +pub type Const = chalk_ir::Const<Interner>;
 +pub type ConstData = chalk_ir::ConstData<Interner>;
 +pub type ConstValue = chalk_ir::ConstValue<Interner>;
 +pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
 +
 +pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
 +pub type TraitRef = chalk_ir::TraitRef<Interner>;
 +pub type QuantifiedWhereClause = Binders<WhereClause>;
 +pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
 +pub type Canonical<T> = chalk_ir::Canonical<T>;
 +
 +pub type FnSig = chalk_ir::FnSig<Interner>;
 +
 +pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
 +pub type Environment = chalk_ir::Environment<Interner>;
 +pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
 +pub type Goal = chalk_ir::Goal<Interner>;
 +pub type AliasEq = chalk_ir::AliasEq<Interner>;
 +pub type Solution = chalk_solve::Solution<Interner>;
 +pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
 +pub type Guidance = chalk_solve::Guidance<Interner>;
 +pub type WhereClause = chalk_ir::WhereClause<Interner>;
 +
 +// FIXME: get rid of this
 +pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
 +    Substitution::from_iter(
 +        Interner,
 +        s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(),
 +    )
 +}
 +
 +/// Return an index of a parameter in the generic type parameter list by it's id.
 +pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
 +    generics(db.upcast(), id.parent).param_idx(id)
 +}
 +
 +pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
 +where
 +    T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
 +{
 +    Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
 +}
 +
 +pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
 +    which_is_const: impl Iterator<Item = Option<Ty>>,
 +    value: T,
 +) -> Binders<T> {
 +    Binders::new(
 +        VariableKinds::from_iter(
 +            Interner,
 +            which_is_const.map(|x| {
 +                if let Some(ty) = x {
 +                    chalk_ir::VariableKind::Const(ty)
 +                } else {
 +                    chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
 +                }
 +            }),
 +        ),
 +        value,
 +    )
 +}
 +
 +pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
 +    value: T,
 +) -> Binders<T> {
 +    Binders::new(
 +        VariableKinds::from_iter(
 +            Interner,
 +            std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
 +        ),
 +        value,
 +    )
 +}
 +
 +pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
 +    db: &dyn HirDatabase,
 +    count: usize,
 +    generics: &Generics,
 +    value: T,
 +) -> Binders<T> {
 +    let it = generics.iter_id().take(count).map(|id| match id {
 +        Either::Left(_) => None,
 +        Either::Right(id) => Some(db.const_param_ty(id)),
 +    });
 +    crate::make_type_and_const_binders(it, value)
 +}
 +
 +pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
 +    db: &dyn HirDatabase,
 +    generics: &Generics,
 +    value: T,
 +) -> Binders<T> {
 +    make_binders_with_count(db, usize::MAX, generics, value)
 +}
 +
 +// FIXME: get rid of this, just replace it by FnPointer
 +/// A function signature as seen by type inference: Several parameter types and
 +/// one return type.
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct CallableSig {
 +    params_and_return: Arc<[Ty]>,
 +    is_varargs: bool,
 +}
 +
 +has_interner!(CallableSig);
 +
 +/// A polymorphic function signature.
 +pub type PolyFnSig = Binders<CallableSig>;
 +
 +impl CallableSig {
 +    pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
 +        params.push(ret);
 +        CallableSig { params_and_return: params.into(), is_varargs }
 +    }
 +
 +    pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
 +        CallableSig {
 +            // FIXME: what to do about lifetime params? -> return PolyFnSig
 +            params_and_return: fn_ptr
 +                .substitution
 +                .clone()
 +                .shifted_out_to(Interner, DebruijnIndex::ONE)
 +                .expect("unexpected lifetime vars in fn ptr")
 +                .0
 +                .as_slice(Interner)
 +                .iter()
 +                .map(|arg| arg.assert_ty_ref(Interner).clone())
 +                .collect(),
 +            is_varargs: fn_ptr.sig.variadic,
 +        }
 +    }
 +
 +    pub fn to_fn_ptr(&self) -> FnPointer {
 +        FnPointer {
 +            num_binders: 0,
 +            sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
 +            substitution: FnSubst(Substitution::from_iter(
 +                Interner,
 +                self.params_and_return.iter().cloned(),
 +            )),
 +        }
 +    }
 +
 +    pub fn params(&self) -> &[Ty] {
 +        &self.params_and_return[0..self.params_and_return.len() - 1]
 +    }
 +
 +    pub fn ret(&self) -> &Ty {
 +        &self.params_and_return[self.params_and_return.len() - 1]
 +    }
 +}
 +
 +impl TypeFoldable<Interner> for CallableSig {
 +    fn fold_with<E>(
 +        self,
 +        folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
 +        outer_binder: DebruijnIndex,
 +    ) -> Result<Self, E> {
 +        let vec = self.params_and_return.to_vec();
 +        let folded = vec.fold_with(folder, outer_binder)?;
 +        Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
 +    }
 +}
 +
 +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 +pub enum ImplTraitId {
 +    ReturnTypeImplTrait(hir_def::FunctionId, u16),
 +    AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct ReturnTypeImplTraits {
 +    pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
 +}
 +
 +has_interner!(ReturnTypeImplTraits);
 +
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub(crate) struct ReturnTypeImplTrait {
 +    pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
 +}
 +
 +pub fn static_lifetime() -> Lifetime {
 +    LifetimeData::Static.intern(Interner)
 +}
 +
 +pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
 +    for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
 +) -> T {
 +    use chalk_ir::{fold::TypeFolder, Fallible};
 +    struct FreeVarFolder<F1, F2>(F1, F2);
 +    impl<
 +            'i,
 +            F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
 +            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
 +        > TypeFolder<Interner> for FreeVarFolder<F1, F2>
 +    {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn fold_free_var_ty(
 +            &mut self,
 +            bound_var: BoundVar,
 +            outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            Ok(self.0(bound_var, outer_binder))
 +        }
 +
 +        fn fold_free_var_const(
 +            &mut self,
 +            ty: Ty,
 +            bound_var: BoundVar,
 +            outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            Ok(self.1(ty, bound_var, outer_binder))
 +        }
 +    }
 +    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
 +        .expect("fold failed unexpectedly")
 +}
 +
 +pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
 +    binders: DebruijnIndex,
 +) -> T {
 +    fold_tys_and_consts(
 +        t,
 +        |x, d| match x {
 +            Either::Left(x) => Either::Left(for_ty(x, d)),
 +            Either::Right(x) => Either::Right(x),
 +        },
 +        binders,
 +    )
 +}
 +
 +pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
 +    binders: DebruijnIndex,
 +) -> T {
 +    use chalk_ir::{
 +        fold::{TypeFolder, TypeSuperFoldable},
 +        Fallible,
 +    };
 +    struct TyFolder<F>(F);
 +    impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
 +        TypeFolder<Interner> for TyFolder<F>
 +    {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
 +            let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
 +            Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
 +        }
 +
 +        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
 +            Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
 +        }
 +    }
 +    t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 +}
 +
 +/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
 +/// ensures there are no unbound variables or inference variables anywhere in
 +/// the `t`.
 +pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
 +where
 +    T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
 +    T: HasInterner<Interner = Interner>,
 +{
 +    use chalk_ir::{
 +        fold::{TypeFolder, TypeSuperFoldable},
 +        Fallible,
 +    };
 +    struct ErrorReplacer {
 +        vars: usize,
 +    }
 +    impl TypeFolder<Interner> for ErrorReplacer {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
 +            if let TyKind::Error = ty.kind(Interner) {
 +                let index = self.vars;
 +                self.vars += 1;
 +                Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
 +            } else {
 +                let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
 +                Ok(ty)
 +            }
 +        }
 +
 +        fn fold_inference_ty(
 +            &mut self,
 +            _var: InferenceVar,
 +            _kind: TyVariableKind,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            if cfg!(debug_assertions) {
 +                // we don't want to just panic here, because then the error message
 +                // won't contain the whole thing, which would not be very helpful
 +                Err(NoSolution)
 +            } else {
 +                Ok(TyKind::Error.intern(Interner))
 +            }
 +        }
 +
 +        fn fold_free_var_ty(
 +            &mut self,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            if cfg!(debug_assertions) {
 +                // we don't want to just panic here, because then the error message
 +                // won't contain the whole thing, which would not be very helpful
 +                Err(NoSolution)
 +            } else {
 +                Ok(TyKind::Error.intern(Interner))
 +            }
 +        }
 +
 +        fn fold_inference_const(
 +            &mut self,
 +            ty: Ty,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(unknown_const(ty))
 +            }
 +        }
 +
 +        fn fold_free_var_const(
 +            &mut self,
 +            ty: Ty,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(unknown_const(ty))
 +            }
 +        }
 +
 +        fn fold_inference_lifetime(
 +            &mut self,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Lifetime> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(static_lifetime())
 +            }
 +        }
 +
 +        fn fold_free_var_lifetime(
 +            &mut self,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Lifetime> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(static_lifetime())
 +            }
 +        }
 +    }
 +    let mut error_replacer = ErrorReplacer { vars: 0 };
 +    let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
 +        Ok(t) => t,
 +        Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
 +    };
 +    let kinds = (0..error_replacer.vars).map(|_| {
 +        chalk_ir::CanonicalVarKind::new(
 +            chalk_ir::VariableKind::Ty(TyVariableKind::General),
 +            chalk_ir::UniverseIndex::ROOT,
 +        )
 +    });
 +    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 +}
index 9a63d5013b4671274e8c93747049a5aa11fd33c7,0000000000000000000000000000000000000000..41fcef73d9be40827aa671979c8da0f0931560c6
mode 100644,000000..100644
--- /dev/null
@@@ -1,1287 -1,0 +1,1335 @@@
-     // if ty is `dyn Trait`, the trait doesn't need to be in scope
-     let inherent_trait =
-         self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
-     let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
-         // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
-         .then(|| {
-             env.traits_in_scope_from_clauses(self_ty.clone())
-                 .flat_map(|t| all_super_traits(db.upcast(), t))
-         })
-         .into_iter()
-         .flatten();
-     let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 +//! This module is concerned with finding methods that a given type provides.
 +//! For details about how this works in rustc, see the method lookup page in the
 +//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
 +//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateId, Edition};
 +use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 +use hir_def::{
 +    data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
 +    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
 +    TraitId,
 +};
 +use hir_expand::name::Name;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::never;
 +
 +use crate::{
 +    autoderef::{self, AutoderefKind},
 +    db::HirDatabase,
 +    from_foreign_def_id,
 +    infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
 +    primitive::{FloatTy, IntTy, UintTy},
 +    static_lifetime,
 +    utils::all_super_traits,
 +    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
 +    Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +/// This is used as a key for indexing impls.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum TyFingerprint {
 +    // These are lang item impls:
 +    Str,
 +    Slice,
 +    Array,
 +    Never,
 +    RawPtr(Mutability),
 +    Scalar(Scalar),
 +    // These can have user-defined impls:
 +    Adt(hir_def::AdtId),
 +    Dyn(TraitId),
 +    ForeignType(ForeignDefId),
 +    // These only exist for trait impls
 +    Unit,
 +    Unnameable,
 +    Function(u32),
 +}
 +
 +impl TyFingerprint {
 +    /// Creates a TyFingerprint for looking up an inherent impl. Only certain
 +    /// types can have inherent impls: if we have some `struct S`, we can have
 +    /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
 +    /// reference types and such.
 +    pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            _ => return None,
 +        };
 +        Some(fp)
 +    }
 +
 +    /// Creates a TyFingerprint for looking up a trait impl.
 +    pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
 +            TyKind::Tuple(_, subst) => {
 +                let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner));
 +                match first_ty {
 +                    Some(ty) => return TyFingerprint::for_trait_impl(ty),
 +                    None => TyFingerprint::Unit,
 +                }
 +            }
 +            TyKind::AssociatedType(_, _)
 +            | TyKind::OpaqueType(_, _)
 +            | TyKind::FnDef(_, _)
 +            | TyKind::Closure(_, _)
 +            | TyKind::Generator(..)
 +            | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
 +            TyKind::Function(fn_ptr) => {
 +                TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
 +            }
 +            TyKind::Alias(_)
 +            | TyKind::Placeholder(_)
 +            | TyKind::BoundVar(_)
 +            | TyKind::InferenceVar(_, _)
 +            | TyKind::Error => return None,
 +        };
 +        Some(fp)
 +    }
 +}
 +
 +pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I8)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I16)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I32)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I64)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I128)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)),
 +];
 +
 +pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)),
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
 +];
 +
 +/// Trait impls defined or available in some crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct TraitImpls {
 +    // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
 +    map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
 +}
 +
 +impl TraitImpls {
 +    pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn trait_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let _p = profile::span("trait_impls_in_block_query");
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let block_def_map = db.block_def_map(block)?;
 +        impls.collect_def_map(db, &block_def_map);
 +        impls.shrink_to_fit();
 +
 +        Some(Arc::new(impls))
 +    }
 +
 +    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}"));
 +        let crate_graph = db.crate_graph();
 +        let mut res = Self { map: FxHashMap::default() };
 +
 +        for krate in crate_graph.transitive_deps(krate) {
 +            res.merge(&db.trait_impls_in_crate(krate));
 +        }
 +        res.shrink_to_fit();
 +
 +        Arc::new(res)
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.shrink_to_fit();
 +        self.map.values_mut().for_each(|map| {
 +            map.shrink_to_fit();
 +            map.values_mut().for_each(Vec::shrink_to_fit);
 +        });
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let target_trait = match db.impl_trait(impl_id) {
 +                    Some(tr) => tr.skip_binders().hir_trait_id(),
 +                    None => continue,
 +                };
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
 +                self.map
 +                    .entry(target_trait)
 +                    .or_default()
 +                    .entry(self_ty_fp)
 +                    .or_default()
 +                    .push(impl_id);
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn merge(&mut self, other: &Self) {
 +        for (trait_, other_map) in &other.map {
 +            let map = self.map.entry(*trait_).or_default();
 +            for (fp, impls) in other_map {
 +                map.entry(*fp).or_default().extend(impls);
 +            }
 +        }
 +    }
 +
 +    /// Queries all trait impls for the given type.
 +    pub fn for_self_ty_without_blanket_impls(
 +        &self,
 +        fp: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .values()
 +            .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
 +            .flat_map(|it| it.iter().copied())
 +    }
 +
 +    /// Queries all impls of the given trait.
 +    pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +
 +    /// Queries all impls of `trait_` that may apply to `self_ty`.
 +    pub fn for_trait_and_self_ty(
 +        &self,
 +        trait_: TraitId,
 +        self_ty: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(move |map| map.get(&Some(self_ty)).into_iter().chain(map.get(&None)))
 +            .flat_map(|v| v.iter().copied())
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +}
 +
 +/// Inherent impls defined in some crate.
 +///
 +/// Inherent impls can only be defined in the crate that also defines the self type of the impl
 +/// (note that some primitives are considered to be defined by both libcore and liballoc).
 +///
 +/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
 +/// single crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct InherentImpls {
 +    map: FxHashMap<TyFingerprint, Vec<ImplId>>,
 +}
 +
 +impl InherentImpls {
 +    pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn inherent_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +        if let Some(block_def_map) = db.block_def_map(block) {
 +            impls.collect_def_map(db, &block_def_map);
 +            impls.shrink_to_fit();
 +            return Some(Arc::new(impls));
 +        }
 +        None
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.values_mut().for_each(Vec::shrink_to_fit);
 +        self.map.shrink_to_fit();
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let data = db.impl_data(impl_id);
 +                if data.target_trait.is_some() {
 +                    continue;
 +                }
 +
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
 +                if let Some(fp) = fp {
 +                    self.map.entry(fp).or_default().push(impl_id);
 +                }
 +                // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
 +        match TyFingerprint::for_inherent_impl(self_ty) {
 +            Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
 +            None => &[],
 +        }
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|v| v.iter().copied())
 +    }
 +}
 +
 +pub(crate) fn inherent_impl_crates_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    fp: TyFingerprint,
 +) -> ArrayVec<CrateId, 2> {
 +    let _p = profile::span("inherent_impl_crates_query");
 +    let mut res = ArrayVec::new();
 +    let crate_graph = db.crate_graph();
 +
 +    for krate in crate_graph.transitive_deps(krate) {
 +        if res.is_full() {
 +            // we don't currently look for or store more than two crates here,
 +            // so don't needlessly look at more crates than necessary.
 +            break;
 +        }
 +        let impls = db.inherent_impls_in_crate(krate);
 +        if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
 +            res.push(krate);
 +        }
 +    }
 +
 +    res
 +}
 +
 +fn collect_unnamed_consts<'a>(
 +    db: &'a dyn HirDatabase,
 +    scope: &'a ItemScope,
 +) -> impl Iterator<Item = ConstId> + 'a {
 +    let unnamed_consts = scope.unnamed_consts();
 +
 +    // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
 +    // Should be removed once synstructure stops doing that.
 +    let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
 +        ModuleDefId::ConstId(id) => {
 +            let loc = id.lookup(db.upcast());
 +            let item_tree = loc.id.item_tree(db.upcast());
 +            if item_tree[loc.id.value]
 +                .name
 +                .as_ref()
 +                .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
 +            {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        }
 +        _ => None,
 +    });
 +
 +    unnamed_consts.chain(synstructure_hack_consts)
 +}
 +
 +pub fn def_crates(
 +    db: &dyn HirDatabase,
 +    ty: &Ty,
 +    cur_crate: CrateId,
 +) -> Option<ArrayVec<CrateId, 2>> {
 +    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
 +
 +    let fp = TyFingerprint::for_inherent_impl(ty);
 +
 +    match ty.kind(Interner) {
 +        TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
 +        TyKind::Foreign(id) => {
 +            mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
 +        }
 +        TyKind::Dyn(_) => ty
 +            .dyn_trait()
 +            .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
 +        // for primitives, there may be impls in various places (core and alloc
 +        // mostly). We just check the whole crate graph for crates with impls
 +        // (cached behind a query).
 +        TyKind::Scalar(_)
 +        | TyKind::Str
 +        | TyKind::Slice(_)
 +        | TyKind::Array(..)
 +        | TyKind::Raw(..) => {
 +            Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
 +        }
 +        _ => return None,
 +    }
 +}
 +
 +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
 +    use hir_expand::name;
 +    use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
 +    Some(match op {
 +        BinaryOp::LogicOp(_) => return None,
 +        BinaryOp::ArithOp(aop) => match aop {
 +            ArithOp::Add => (name!(add), name!(add)),
 +            ArithOp::Mul => (name!(mul), name!(mul)),
 +            ArithOp::Sub => (name!(sub), name!(sub)),
 +            ArithOp::Div => (name!(div), name!(div)),
 +            ArithOp::Rem => (name!(rem), name!(rem)),
 +            ArithOp::Shl => (name!(shl), name!(shl)),
 +            ArithOp::Shr => (name!(shr), name!(shr)),
 +            ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
 +            ArithOp::BitOr => (name!(bitor), name!(bitor)),
 +            ArithOp::BitAnd => (name!(bitand), name!(bitand)),
 +        },
 +        BinaryOp::Assignment { op: Some(aop) } => match aop {
 +            ArithOp::Add => (name!(add_assign), name!(add_assign)),
 +            ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
 +            ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
 +            ArithOp::Div => (name!(div_assign), name!(div_assign)),
 +            ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
 +            ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
 +            ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
 +            ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
 +            ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
 +            ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
 +        },
 +        BinaryOp::CmpOp(cop) => match cop {
 +            CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
 +            CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
 +            CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
 +                (name!(le), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
 +                (name!(lt), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
 +                (name!(ge), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
 +                (name!(gt), name!(partial_ord))
 +            }
 +        },
 +        BinaryOp::Assignment { op: None } => return None,
 +    })
 +}
 +
 +/// Look up the method with the given name.
 +pub(crate) fn lookup_method(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: &Name,
 +) -> Option<(ReceiverAdjustments, FunctionId)> {
 +    iterate_method_candidates(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        Some(name),
 +        LookupMode::MethodCall,
 +        |adjustments, f| match f {
 +            AssocItemId::FunctionId(f) => Some((adjustments, f)),
 +            _ => None,
 +        },
 +    )
 +}
 +
 +/// Whether we're looking up a dotted method call (like `v.len()`) or a path
 +/// (like `Vec::new`).
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum LookupMode {
 +    /// Looking up a method call like `v.len()`: We only consider candidates
 +    /// that have a `self` parameter, and do autoderef.
 +    MethodCall,
 +    /// Looking up a path like `Vec::new` or `Vec::default`: We consider all
 +    /// candidates including associated constants, but don't do autoderef.
 +    Path,
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum VisibleFromModule {
 +    /// Filter for results that are visible from the given module
 +    Filter(ModuleId),
 +    /// Include impls from the given block.
 +    IncludeBlock(BlockId),
 +    /// Do nothing special in regards visibility
 +    None,
 +}
 +
 +impl From<Option<ModuleId>> for VisibleFromModule {
 +    fn from(module: Option<ModuleId>) -> Self {
 +        match module {
 +            Some(module) => Self::Filter(module),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +impl From<Option<BlockId>> for VisibleFromModule {
 +    fn from(block: Option<BlockId>) -> Self {
 +        match block {
 +            Some(block) => Self::IncludeBlock(block),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Default)]
 +pub struct ReceiverAdjustments {
 +    autoref: Option<Mutability>,
 +    autoderefs: usize,
 +    unsize_array: bool,
 +}
 +
 +impl ReceiverAdjustments {
 +    pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
 +        let mut ty = ty;
 +        let mut adjust = Vec::new();
 +        for _ in 0..self.autoderefs {
 +            match autoderef::autoderef_step(table, ty.clone()) {
 +                None => {
 +                    never!("autoderef not possible for {:?}", ty);
 +                    ty = TyKind::Error.intern(Interner);
 +                    break;
 +                }
 +                Some((kind, new_ty)) => {
 +                    ty = new_ty.clone();
 +                    adjust.push(Adjustment {
 +                        kind: Adjust::Deref(match kind {
 +                            // FIXME should we know the mutability here?
 +                            AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
 +                            AutoderefKind::Builtin => None,
 +                        }),
 +                        target: new_ty,
 +                    });
 +                }
 +            }
 +        }
 +        if self.unsize_array {
 +            ty = match ty.kind(Interner) {
 +                TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
 +                _ => {
 +                    never!("unsize_array with non-array {:?}", ty);
 +                    ty
 +                }
 +            };
 +            // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
 +            adjust.push(Adjustment {
 +                kind: Adjust::Pointer(PointerCast::Unsize),
 +                target: ty.clone(),
 +            });
 +        }
 +        if let Some(m) = self.autoref {
 +            ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
 +            adjust
 +                .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
 +        }
 +        (ty, adjust)
 +    }
 +
 +    fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
 +        Self { autoref: Some(m), ..*self }
 +    }
 +}
 +
 +// This would be nicer if it just returned an iterator, but that runs into
 +// lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +// FIXME add a context type here?
 +pub(crate) fn iterate_method_candidates<T>(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
 +) -> Option<T> {
 +    let mut slot = None;
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        mode,
 +        &mut |adj, item| {
 +            assert!(slot.is_none());
 +            if let Some(it) = callback(adj, item) {
 +                slot = Some(it);
 +                return ControlFlow::Break(());
 +            }
 +            ControlFlow::Continue(())
 +        },
 +    );
 +    slot
 +}
 +
 +pub fn lookup_impl_method(
 +    self_ty: &Ty,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    name: &Name,
 +) -> Option<FunctionId> {
 +    let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
 +    let trait_impls = db.trait_impls_in_deps(env.krate);
 +    let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
 +    let mut table = InferenceTable::new(db, env.clone());
 +    find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
 +        data.items.iter().find_map(|it| match it {
 +            AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
 +            _ => None,
 +        })
 +    })
 +}
 +
 +fn find_matching_impl(
 +    mut impls: impl Iterator<Item = ImplId>,
 +    table: &mut InferenceTable<'_>,
 +    self_ty: &Ty,
 +) -> Option<Arc<ImplData>> {
 +    let db = table.db;
 +    loop {
 +        let impl_ = impls.next()?;
 +        let r = table.run_in_snapshot(|table| {
 +            let impl_data = db.impl_data(impl_);
 +            let substs =
 +                TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
 +            let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 +
 +            table
 +                .unify(self_ty, &impl_ty)
 +                .then(|| {
 +                    let wh_goals =
 +                        crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
 +                            .into_iter()
 +                            .map(|b| b.cast(Interner));
 +
 +                    let goal = crate::Goal::all(Interner, wh_goals);
 +
 +                    table.try_obligation(goal).map(|_| impl_data)
 +                })
 +                .flatten()
 +        });
 +        if r.is_some() {
 +            break r;
 +        }
 +    }
 +}
 +
 +pub fn iterate_path_candidates(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        LookupMode::Path,
 +        // the adjustments are not relevant for path lookup
 +        &mut |_, id| callback(id),
 +    )
 +}
 +
 +pub fn iterate_method_candidates_dyn(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    match mode {
 +        LookupMode::MethodCall => {
 +            // For method calls, rust first does any number of autoderef, and
 +            // then one autoref (i.e. when the method takes &self or &mut self).
 +            // Note that when we've got a receiver like &S, even if the method
 +            // we find in the end takes &self, we still do the autoderef step
 +            // (just as rustc does an autoderef and then autoref again).
 +
 +            // We have to be careful about the order we're looking at candidates
 +            // in here. Consider the case where we're resolving `x.clone()`
 +            // where `x: &Vec<_>`. This resolves to the clone method with self
 +            // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
 +            // the receiver type exactly matches before cases where we have to
 +            // do autoref. But in the autoderef steps, the `&_` self type comes
 +            // up *before* the `Vec<_>` self type.
 +            //
 +            // On the other hand, we don't want to just pick any by-value method
 +            // before any by-autoref method; it's just that we need to consider
 +            // the methods by autoderef order of *receiver types*, not *self
 +            // types*.
 +
 +            let mut table = InferenceTable::new(db, env.clone());
 +            let ty = table.instantiate_canonical(ty.clone());
 +            let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +
 +            let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| {
 +                iterate_method_candidates_with_autoref(
 +                    &receiver_ty,
 +                    adj,
 +                    db,
 +                    env.clone(),
 +                    traits_in_scope,
 +                    visible_from_module,
 +                    name,
 +                    callback,
 +                )
 +            });
 +            result
 +        }
 +        LookupMode::Path => {
 +            // No autoderef for path lookups
 +            iterate_method_candidates_for_self_ty(
 +                ty,
 +                db,
 +                env,
 +                traits_in_scope,
 +                visible_from_module,
 +                name,
 +                callback,
 +            )
 +        }
 +    }
 +}
 +
 +fn iterate_method_candidates_with_autoref(
 +    receiver_ty: &Canonical<Ty>,
 +    first_adjustment: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
 +        // don't try to resolve methods on unknown types
 +        return ControlFlow::Continue(());
 +    }
 +
 +    iterate_method_candidates_by_receiver(
 +        receiver_ty,
 +        first_adjustment.clone(),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let refed = Canonical {
 +        value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &refed,
 +        first_adjustment.with_autoref(Mutability::Not),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let ref_muted = Canonical {
 +        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &ref_muted,
 +        first_adjustment.with_autoref(Mutability::Mut),
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )
 +}
 +
 +fn iterate_method_candidates_by_receiver(
 +    receiver_ty: &Canonical<Ty>,
 +    receiver_adjustments: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
 +    let snapshot = table.snapshot();
 +    // We're looking for methods with *receiver* type receiver_ty. These could
 +    // be found in any of the derefs of receiver_ty, so we have to go through
 +    // that.
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_inherent_methods(
 +            &self_ty,
 +            &mut autoderef.table,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            visible_from_module,
 +            &mut callback,
 +        )?
 +    }
 +
 +    table.rollback_to(snapshot);
 +
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_trait_method_candidates(
 +            &self_ty,
 +            &mut autoderef.table,
 +            traits_in_scope,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            &mut callback,
 +        )?
 +    }
 +
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_method_candidates_for_self_ty(
 +    self_ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let self_ty = table.instantiate_canonical(self_ty.clone());
 +    iterate_inherent_methods(
 +        &self_ty,
 +        &mut table,
 +        name,
 +        None,
 +        None,
 +        visible_from_module,
 +        &mut callback,
 +    )?;
 +    iterate_trait_method_candidates(
 +        &self_ty,
 +        &mut table,
 +        traits_in_scope,
 +        name,
 +        None,
 +        None,
 +        callback,
 +    )
 +}
 +
 +fn iterate_trait_method_candidates(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
 +    let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
-     'traits: for t in traits {
 +
 +    let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 +
++    'traits: for &t in traits_in_scope {
 +        let data = db.trait_data(t);
 +
 +        // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
 +        // method resolution, if the receiver is an array, and we're compiling for editions before
 +        // 2021.
 +        // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
 +        // arrays.
 +        if data.skip_array_during_method_dispatch && self_is_array {
 +            // FIXME: this should really be using the edition of the method name's span, in case it
 +            // comes from a macro
 +            if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
 +                continue;
 +            }
 +        }
 +
 +        // we'll be lazy about checking whether the type implements the
 +        // trait, but if we find out it doesn't, we'll skip the rest of the
 +        // iteration
 +        let mut known_implemented = false;
 +        for &(_, item) in data.items.iter() {
 +            // Don't pass a `visible_from_module` down to `is_valid_candidate`,
 +            // since only inherent methods should be included into visibility checking.
 +            if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
 +                continue;
 +            }
 +            if !known_implemented {
 +                let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
 +                if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
 +                    continue 'traits;
 +                }
 +            }
 +            known_implemented = true;
 +            callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +        }
 +    }
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_inherent_methods(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    visible_from_module: VisibleFromModule,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
++
++    // For trait object types and placeholder types with trait bounds, the methods of the trait and
++    // its super traits are considered inherent methods. This matters because these methods have
++    // higher priority than the other traits' methods, which would be considered in
++    // `iterate_trait_method_candidates()` only after this function.
++    match self_ty.kind(Interner) {
++        TyKind::Placeholder(_) => {
++            let env = table.trait_env.clone();
++            let traits = env
++                .traits_in_scope_from_clauses(self_ty.clone())
++                .flat_map(|t| all_super_traits(db.upcast(), t));
++            iterate_inherent_trait_methods(
++                self_ty,
++                table,
++                name,
++                receiver_ty,
++                receiver_adjustments.clone(),
++                callback,
++                traits,
++            )?;
++        }
++        TyKind::Dyn(_) => {
++            if let Some(principal_trait) = self_ty.dyn_trait() {
++                let traits = all_super_traits(db.upcast(), principal_trait);
++                iterate_inherent_trait_methods(
++                    self_ty,
++                    table,
++                    name,
++                    receiver_ty,
++                    receiver_adjustments.clone(),
++                    callback,
++                    traits.into_iter(),
++                )?;
++            }
++        }
++        _ => {}
++    }
++
 +    let def_crates = match def_crates(db, self_ty, env.krate) {
 +        Some(k) => k,
 +        None => return ControlFlow::Continue(()),
 +    };
 +
 +    let (module, block) = match visible_from_module {
 +        VisibleFromModule::Filter(module) => (Some(module), module.containing_block()),
 +        VisibleFromModule::IncludeBlock(block) => (None, Some(block)),
 +        VisibleFromModule::None => (None, None),
 +    };
 +
 +    if let Some(block_id) = block {
 +        if let Some(impls) = db.inherent_impls_in_block(block_id) {
 +            impls_for_self_ty(
 +                &impls,
 +                self_ty,
 +                table,
 +                name,
 +                receiver_ty,
 +                receiver_adjustments.clone(),
 +                module,
 +                callback,
 +            )?;
 +        }
 +    }
 +
 +    for krate in def_crates {
 +        let impls = db.inherent_impls_in_crate(krate);
 +        impls_for_self_ty(
 +            &impls,
 +            self_ty,
 +            table,
 +            name,
 +            receiver_ty,
 +            receiver_adjustments.clone(),
 +            module,
 +            callback,
 +        )?;
 +    }
 +    return ControlFlow::Continue(());
 +
++    fn iterate_inherent_trait_methods(
++        self_ty: &Ty,
++        table: &mut InferenceTable<'_>,
++        name: Option<&Name>,
++        receiver_ty: Option<&Ty>,
++        receiver_adjustments: Option<ReceiverAdjustments>,
++        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
++        traits: impl Iterator<Item = TraitId>,
++    ) -> ControlFlow<()> {
++        let db = table.db;
++        for t in traits {
++            let data = db.trait_data(t);
++            for &(_, item) in data.items.iter() {
++                // We don't pass `visible_from_module` as all trait items should be visible.
++                if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
++                    callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
++                }
++            }
++        }
++        ControlFlow::Continue(())
++    }
++
 +    fn impls_for_self_ty(
 +        impls: &InherentImpls,
 +        self_ty: &Ty,
 +        table: &mut InferenceTable<'_>,
 +        name: Option<&Name>,
 +        receiver_ty: Option<&Ty>,
 +        receiver_adjustments: Option<ReceiverAdjustments>,
 +        visible_from_module: Option<ModuleId>,
 +        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +    ) -> ControlFlow<()> {
 +        let db = table.db;
 +        let impls_for_self_ty = impls.for_self_ty(self_ty);
 +        for &impl_def in impls_for_self_ty {
 +            for &item in &db.impl_data(impl_def).items {
 +                if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module)
 +                {
 +                    continue;
 +                }
 +                callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +            }
 +        }
 +        ControlFlow::Continue(())
 +    }
 +}
 +
 +/// Returns the receiver type for the index trait call.
 +pub fn resolve_indexing_op(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    ty: Canonical<Ty>,
 +    index_trait: TraitId,
 +) -> Option<ReceiverAdjustments> {
 +    let mut table = InferenceTable::new(db, env.clone());
 +    let ty = table.instantiate_canonical(ty);
 +    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +    for (ty, adj) in deref_chain.into_iter().zip(adj) {
 +        let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
 +        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
 +            return Some(adj);
 +        }
 +    }
 +    None
 +}
 +
 +macro_rules! check_that {
 +    ($cond:expr) => {
 +        if !$cond {
 +            return false;
 +        }
 +    };
 +}
 +
 +fn is_valid_candidate(
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    item: AssocItemId,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    match item {
 +        AssocItemId::FunctionId(m) => {
 +            is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
 +        }
 +        AssocItemId::ConstId(c) => {
 +            let data = db.const_data(c);
 +            check_that!(receiver_ty.is_none());
 +
 +            check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
 +            check_that!(visible_from_module.map_or(true, |from_module| {
 +                let v = db.const_visibility(c).is_visible_from(db.upcast(), from_module);
 +                if !v {
 +                    cov_mark::hit!(const_candidate_not_visible);
 +                }
 +                v
 +            }));
 +            if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
 +                let self_ty_matches = table.run_in_snapshot(|table| {
 +                    let subst =
 +                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
 +                    let expected_self_ty =
 +                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
 +                    table.unify(&expected_self_ty, &self_ty)
 +                });
 +                if !self_ty_matches {
 +                    cov_mark::hit!(const_candidate_self_type_mismatch);
 +                    return false;
 +                }
 +            }
 +            true
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn is_valid_fn_candidate(
 +    table: &mut InferenceTable<'_>,
 +    fn_id: FunctionId,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    let data = db.function_data(fn_id);
 +
 +    check_that!(name.map_or(true, |n| n == &data.name));
 +    check_that!(visible_from_module.map_or(true, |from_module| {
 +        let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module);
 +        if !v {
 +            cov_mark::hit!(autoderef_candidate_not_visible);
 +        }
 +        v
 +    }));
 +
 +    table.run_in_snapshot(|table| {
 +        let container = fn_id.lookup(db.upcast()).container;
 +        let impl_subst = match container {
 +            ItemContainerId::ImplId(it) => {
 +                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
 +            }
 +            ItemContainerId::TraitId(it) => {
 +                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
 +            }
 +            _ => unreachable!(),
 +        };
 +
 +        let fn_subst = TyBuilder::subst_for_def(db, fn_id)
 +            .use_parent_substs(&impl_subst)
 +            .fill_with_inference_vars(table)
 +            .build();
 +
 +        let expect_self_ty = match container {
 +            ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
 +            ItemContainerId::ImplId(impl_id) => {
 +                fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
 +            }
 +            // We should only get called for associated items (impl/trait)
 +            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
 +                unreachable!()
 +            }
 +        };
 +        check_that!(table.unify(&expect_self_ty, self_ty));
 +
 +        if let Some(receiver_ty) = receiver_ty {
 +            check_that!(data.has_self_param());
 +
 +            let sig = db.callable_item_signature(fn_id.into());
 +            let expected_receiver =
 +                sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
 +
 +            check_that!(table.unify(&receiver_ty, &expected_receiver));
 +        }
 +
 +        if let ItemContainerId::ImplId(impl_id) = container {
 +            // We need to consider the bounds on the impl to distinguish functions of the same name
 +            // for a type.
 +            let predicates = db.generic_predicates(impl_id.into());
 +            predicates
 +                .iter()
 +                .map(|predicate| {
 +                    let (p, b) = predicate
 +                        .clone()
 +                        .substitute(Interner, &impl_subst)
 +                        // Skipping the inner binders is ok, as we don't handle quantified where
 +                        // clauses yet.
 +                        .into_value_and_skipped_binders();
 +                    stdx::always!(b.len(Interner) == 0);
 +                    p
 +                })
 +                // It's ok to get ambiguity here, as we may not have enough information to prove
 +                // obligations. We'll check if the user is calling the selected method properly
 +                // later anyway.
 +                .all(|p| table.try_obligation(p.cast(Interner)).is_some())
 +        } else {
 +            // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
 +            // `iterate_trait_method_candidates()`.
 +            // For others, this function shouldn't be called.
 +            true
 +        }
 +    })
 +}
 +
 +pub fn implements_trait(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    solution.is_some()
 +}
 +
 +pub fn implements_trait_unique(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    matches!(solution, Some(crate::Solution::Unique(_)))
 +}
 +
 +/// This creates Substs for a trait with the given Self type and type variables
 +/// for all other parameters, to query Chalk with it.
 +fn generic_implements_goal(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    self_ty: &Canonical<Ty>,
 +) -> Canonical<InEnvironment<super::DomainGoal>> {
 +    let mut kinds = self_ty.binders.interned().to_vec();
 +    let trait_ref = TyBuilder::trait_ref(db, trait_)
 +        .push(self_ty.value.clone())
 +        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
 +        .build();
 +    kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
 +        let vk = match x.data(Interner) {
 +            chalk_ir::GenericArgData::Ty(_) => {
 +                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
 +            }
 +            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
 +            chalk_ir::GenericArgData::Const(c) => {
 +                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
 +            }
 +        };
 +        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
 +    }));
 +    let obligation = trait_ref.cast(Interner);
 +    Canonical {
 +        binders: CanonicalVarKinds::from_iter(Interner, kinds),
 +        value: InEnvironment::new(&env.env, obligation),
 +    }
 +}
 +
 +fn autoderef_method_receiver(
 +    table: &mut InferenceTable<'_>,
 +    ty: Ty,
 +) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) {
 +    let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new());
 +    let mut autoderef = autoderef::Autoderef::new(table, ty);
 +    while let Some((ty, derefs)) = autoderef.next() {
 +        deref_chain.push(autoderef.table.canonicalize(ty).value);
 +        adjustments.push(ReceiverAdjustments {
 +            autoref: None,
 +            autoderefs: derefs,
 +            unsize_array: false,
 +        });
 +    }
 +    // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
 +    if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = (
 +        deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())),
 +        adjustments.last().cloned(),
 +    ) {
 +        let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
 +        deref_chain.push(Canonical { value: unsized_ty, binders });
 +        adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj });
 +    }
 +    (deref_chain, adjustments)
 +}
index 81588a7c4ffd668bb6ccfb92f65e3628b09cb5a7,0000000000000000000000000000000000000000..ac8edb841a580322b18b5a47b9eb39ae174b3a49
mode 100644,000000..100644
--- /dev/null
@@@ -1,1835 -1,0 +1,1869 @@@
 +use expect_test::expect;
 +
 +use crate::tests::check;
 +
 +use super::{check_infer, check_no_mismatches, check_types};
 +
 +#[test]
 +fn infer_slice_method() {
 +    check_types(
 +        r#"
 +impl<T> [T] {
 +    fn foo(&self) -> T {
 +        loop {}
 +    }
 +}
 +
 +fn test(x: &[u8]) {
 +    <[_]>::foo(x);
 +  //^^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn cross_crate_primitive_method() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:other_crate
 +fn test() {
 +    let x = 1f32;
 +    x.foo();
 +} //^^^^^^^ f32
 +
 +//- /lib.rs crate:other_crate
 +mod foo {
 +    impl f32 {
 +        pub fn foo(self) -> f32 { 0. }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_array_inherent_impl() {
 +    check_types(
 +        r#"
 +impl<T, const N: usize> [T; N] {
 +    fn foo(&self) -> T {
 +        loop {}
 +    }
 +}
 +fn test(x: &[u8; 0]) {
 +    <[_; 0]>::foo(x);
 +  //^^^^^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_struct() {
 +    check_infer(
 +        r#"
 +        struct A { x: u32 }
 +
 +        impl A {
 +            fn new() -> A {
 +                A { x: 0 }
 +            }
 +        }
 +        fn test() {
 +            let a = A::new();
 +            a.x;
 +        }
 +        "#,
 +        expect![[r#"
 +            48..74 '{     ...     }': A
 +            58..68 'A { x: 0 }': A
 +            65..66 '0': u32
 +            87..121 '{     ...a.x; }': ()
 +            97..98 'a': A
 +            101..107 'A::new': fn new() -> A
 +            101..109 'A::new()': A
 +            115..116 'a': A
 +            115..118 'a.x': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_struct_in_local_scope() {
 +    check_infer(
 +        r#"
 +        fn mismatch() {
 +            struct A;
 +
 +            impl A {
 +                fn from(_: i32, _: i32) -> Self {
 +                    A
 +                }
 +            }
 +
 +            let _a = A::from(1, 2);
 +        }
 +        "#,
 +        expect![[r#"
 +            14..146 '{     ... 2); }': ()
 +            125..127 '_a': A
 +            130..137 'A::from': fn from(i32, i32) -> A
 +            130..143 'A::from(1, 2)': A
 +            138..139 '1': i32
 +            141..142 '2': i32
 +            60..61 '_': i32
 +            68..69 '_': i32
 +            84..109 '{     ...     }': A
 +            98..99 'A': A
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_enum() {
 +    check_infer(
 +        r#"
 +        enum A { B, C }
 +
 +        impl A {
 +            pub fn b() -> A {
 +                A::B
 +            }
 +            pub fn c() -> A {
 +                A::C
 +            }
 +        }
 +        fn test() {
 +            let a = A::b();
 +            a;
 +            let c = A::c();
 +            c;
 +        }
 +        "#,
 +        expect![[r#"
 +            46..66 '{     ...     }': A
 +            56..60 'A::B': A
 +            87..107 '{     ...     }': A
 +            97..101 'A::C': A
 +            120..177 '{     ...  c; }': ()
 +            130..131 'a': A
 +            134..138 'A::b': fn b() -> A
 +            134..140 'A::b()': A
 +            146..147 'a': A
 +            157..158 'c': A
 +            161..165 'A::c': fn c() -> A
 +            161..167 'A::c()': A
 +            173..174 'c': A
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_with_modules() {
 +    check_infer(
 +        r#"
 +        mod a {
 +            struct A;
 +            impl A { pub fn thing() -> A { A {} }}
 +        }
 +
 +        mod b {
 +            struct B;
 +            impl B { pub fn thing() -> u32 { 99 }}
 +
 +            mod c {
 +                struct C;
 +                impl C { pub fn thing() -> C { C {} }}
 +            }
 +        }
 +        use b::c;
 +
 +        fn test() {
 +            let x = a::A::thing();
 +            let y = b::B::thing();
 +            let z = c::C::thing();
 +        }
 +        "#,
 +        expect![[r#"
 +            55..63 '{ A {} }': A
 +            57..61 'A {}': A
 +            125..131 '{ 99 }': u32
 +            127..129 '99': u32
 +            201..209 '{ C {} }': C
 +            203..207 'C {}': C
 +            240..324 '{     ...g(); }': ()
 +            250..251 'x': A
 +            254..265 'a::A::thing': fn thing() -> A
 +            254..267 'a::A::thing()': A
 +            277..278 'y': u32
 +            281..292 'b::B::thing': fn thing() -> u32
 +            281..294 'b::B::thing()': u32
 +            304..305 'z': C
 +            308..319 'c::C::thing': fn thing() -> C
 +            308..321 'c::C::thing()': C
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics() {
 +    check_infer(
 +        r#"
 +        struct Gen<T> {
 +            val: T
 +        }
 +
 +        impl<T> Gen<T> {
 +            pub fn make(val: T) -> Gen<T> {
 +                Gen { val }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::make(0u32);
 +        }
 +        "#,
 +        expect![[r#"
 +            63..66 'val': T
 +            81..108 '{     ...     }': Gen<T>
 +            91..102 'Gen { val }': Gen<T>
 +            97..100 'val': T
 +            122..154 '{     ...32); }': ()
 +            132..133 'a': Gen<u32>
 +            136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32>
 +            136..151 'Gen::make(0u32)': Gen<u32>
 +            146..150 '0u32': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics_without_args() {
 +    check_infer(
 +        r#"
 +        struct Gen<T> {
 +            val: T
 +        }
 +
 +        impl<T> Gen<T> {
 +            pub fn make() -> Gen<T> {
 +                loop { }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::<u32>::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            75..99 '{     ...     }': Gen<T>
 +            85..93 'loop { }': !
 +            90..93 '{ }': ()
 +            113..148 '{     ...e(); }': ()
 +            123..124 'a': Gen<u32>
 +            127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32>
 +            127..145 'Gen::<...make()': Gen<u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics_2_type_params_without_args() {
 +    check_infer(
 +        r#"
 +        struct Gen<T, U> {
 +            val: T,
 +            val2: U,
 +        }
 +
 +        impl<T> Gen<u32, T> {
 +            pub fn make() -> Gen<u32,T> {
 +                loop { }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::<u32, u64>::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            101..125 '{     ...     }': Gen<u32, T>
 +            111..119 'loop { }': !
 +            116..119 '{ }': ()
 +            139..179 '{     ...e(); }': ()
 +            149..150 'a': Gen<u32, u64>
 +            153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64>
 +            153..176 'Gen::<...make()': Gen<u32, u64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cross_crate_associated_method_call() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:other_crate
 +fn test() {
 +    let x = other_crate::foo::S::thing();
 +    x;
 +} //^ i128
 +
 +//- /lib.rs crate:other_crate
 +pub mod foo {
 +    pub struct S;
 +    impl S {
 +        pub fn thing() -> i128 { 0 }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_simple() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait1 {
 +    fn method(&self) -> u32;
 +}
 +struct S1;
 +impl Trait1 for S1 {}
 +trait Trait2 {
 +    fn method(&self) -> i128;
 +}
 +struct S2;
 +impl Trait2 for S2 {}
 +fn test() {
 +    S1.method();
 +  //^^^^^^^^^^^ u32
 +    S2.method(); // -> i128
 +  //^^^^^^^^^^^ i128
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_scoped() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +struct S;
 +mod foo {
 +    pub trait Trait1 {
 +        fn method(&self) -> u32;
 +    }
 +    impl Trait1 for super::S {}
 +}
 +mod bar {
 +    pub trait Trait2 {
 +        fn method(&self) -> i128;
 +    }
 +    impl Trait2 for super::S {}
 +}
 +
 +mod foo_test {
 +    use super::S;
 +    use super::foo::Trait1;
 +    fn test() {
 +        S.method();
 +      //^^^^^^^^^^ u32
 +    }
 +}
 +
 +mod bar_test {
 +    use super::S;
 +    use super::bar::Trait2;
 +    fn test() {
 +        S.method();
 +      //^^^^^^^^^^ i128
 +    }
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_1() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn method(&self) -> T;
 +}
 +struct S;
 +impl Trait<u32> for S {}
 +fn test() {
 +    S.method();
 +  //^^^^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_more_params() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T1, T2, T3> {
 +    fn method1(&self) -> (T1, T2, T3);
 +    fn method2(&self) -> (T3, T2, T1);
 +}
 +struct S1;
 +impl Trait<u8, u16, u32> for S1 {}
 +struct S2;
 +impl<T> Trait<i8, i16, T> for S2 {}
 +fn test() {
 +    S1.method1();
 +  //^^^^^^^^^^^^ (u8, u16, u32)
 +    S1.method2();
 +  //^^^^^^^^^^^^ (u32, u16, u8)
 +    S2.method1();
 +  //^^^^^^^^^^^^ (i8, i16, {unknown})
 +    S2.method2();
 +  //^^^^^^^^^^^^ ({unknown}, i16, i8)
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_2() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn method(&self) -> T;
 +}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn test() {
 +    S(1u32).method();
 +  //^^^^^^^^^^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method() {
 +    check_infer(
 +        r#"
 +        trait Default {
 +            fn default() -> Self;
 +        }
 +        struct S;
 +        impl Default for S {}
 +        fn test() {
 +            let s1: S = Default::default();
 +            let s2 = S::default();
 +            let s3 = <S as Default>::default();
 +        }
 +        "#,
 +        expect![[r#"
 +            86..192 '{     ...t(); }': ()
 +            96..98 's1': S
 +            104..120 'Defaul...efault': fn default<S>() -> S
 +            104..122 'Defaul...ault()': S
 +            132..134 's2': S
 +            137..147 'S::default': fn default<S>() -> S
 +            137..149 'S::default()': S
 +            159..161 's3': S
 +            164..187 '<S as ...efault': fn default<S>() -> S
 +            164..189 '<S as ...ault()': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_1() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> T;
 +        }
 +        struct S;
 +        impl Trait<u32> for S {}
 +        struct G<T>;
 +        impl<T> Trait<T> for G<T> {}
 +        fn test() {
 +            let a = S::make();
 +            let b = G::<u64>::make();
 +            let c: f64 = G::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            126..210 '{     ...e(); }': ()
 +            136..137 'a': u32
 +            140..147 'S::make': fn make<S, u32>() -> u32
 +            140..149 'S::make()': u32
 +            159..160 'b': u64
 +            163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64
 +            163..179 'G::<u6...make()': u64
 +            189..190 'c': f64
 +            198..205 'G::make': fn make<G<f64>, f64>() -> f64
 +            198..207 'G::make()': f64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_2() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make<U>() -> (T, U);
 +        }
 +        struct S;
 +        impl Trait<u32> for S {}
 +        struct G<T>;
 +        impl<T> Trait<T> for G<T> {}
 +        fn test() {
 +            let a = S::make::<i64>();
 +            let b: (_, i64) = S::make();
 +            let c = G::<u32>::make::<i64>();
 +            let d: (u32, _) = G::make::<i64>();
 +            let e: (u32, i64) = G::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            134..312 '{     ...e(); }': ()
 +            144..145 'a': (u32, i64)
 +            148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64)
 +            148..164 'S::mak...i64>()': (u32, i64)
 +            174..175 'b': (u32, i64)
 +            188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64)
 +            188..197 'S::make()': (u32, i64)
 +            207..208 'c': (u32, i64)
 +            211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            211..234 'G::<u3...i64>()': (u32, i64)
 +            244..245 'd': (u32, i64)
 +            258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            258..274 'G::mak...i64>()': (u32, i64)
 +            284..285 'e': (u32, i64)
 +            300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            300..309 'G::make()': (u32, i64)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_3() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> (Self, T);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<i32> {}
 +        fn test() {
 +            let a = S::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            100..126 '{     ...e(); }': ()
 +            110..111 'a': (S<i32>, i64)
 +            114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64)
 +            114..123 'S::make()': (S<i32>, i64)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_4() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> (Self, T);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<u64> {}
 +        impl Trait<i32> for S<u32> {}
 +        fn test() {
 +            let a: (S<u64>, _) = S::make();
 +            let b: (_, i32) = S::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            130..202 '{     ...e(); }': ()
 +            140..141 'a': (S<u64>, i64)
 +            157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64)
 +            157..166 'S::make()': (S<u64>, i64)
 +            176..177 'b': (S<u32>, i32)
 +            190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32)
 +            190..199 'S::make()': (S<u32>, i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_5() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make<U>() -> (Self, T, U);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<u64> {}
 +        fn test() {
 +            let a = <S as Trait<i64>>::make::<u8>();
 +            let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
 +        }
 +        "#,
 +        expect![[r#"
 +            106..210 '{     ...>(); }': ()
 +            116..117 'a': (S<u64>, i64, u8)
 +            120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
 +            120..151 '<S as ...<u8>()': (S<u64>, i64, u8)
 +            161..162 'b': (S<u64>, i64, u8)
 +            181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
 +            181..207 'Trait:...<u8>()': (S<u64>, i64, u8)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_call_trait_method_on_generic_param_1() {
 +    check_infer(
 +        r#"
 +        trait Trait {
 +            fn method(&self) -> u32;
 +        }
 +        fn test<T: Trait>(t: T) {
 +            t.method();
 +        }
 +        "#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            63..64 't': T
 +            69..88 '{     ...d(); }': ()
 +            75..76 't': T
 +            75..85 't.method()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_call_trait_method_on_generic_param_2() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn method(&self) -> T;
 +        }
 +        fn test<U, T: Trait<U>>(t: T) {
 +            t.method();
 +        }
 +        "#,
 +        expect![[r#"
 +            32..36 'self': &Self
 +            70..71 't': T
 +            76..95 '{     ...d(); }': ()
 +            82..83 't': T
 +            82..92 't.method()': U
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_with_multiple_trait_impls() {
 +    check_infer(
 +        r#"
 +        trait Into<T> {
 +            fn into(self) -> T;
 +        }
 +        struct S;
 +        impl Into<u32> for S {}
 +        impl Into<u64> for S {}
 +        fn test() {
 +            let x: u32 = S.into();
 +            let y: u64 = S.into();
 +            let z = Into::<u64>::into(S);
 +        }
 +        "#,
 +        expect![[r#"
 +            28..32 'self': Self
 +            110..201 '{     ...(S); }': ()
 +            120..121 'x': u32
 +            129..130 'S': S
 +            129..137 'S.into()': u32
 +            147..148 'y': u64
 +            156..157 'S': S
 +            156..164 'S.into()': u64
 +            174..175 'z': u64
 +            178..195 'Into::...::into': fn into<S, u64>(S) -> u64
 +            178..198 'Into::...nto(S)': u64
 +            196..197 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_unify_impl_self_type() {
 +    check_types(
 +        r#"
 +struct S<T>;
 +impl S<u32> { fn foo(&self) -> u8 { 0 } }
 +impl S<i32> { fn foo(&self) -> i8 { 0 } }
 +fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
 +          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_before_autoref() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(&self) -> i8 { 0 } }
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_by_value_before_autoref() {
 +    check_types(
 +        r#"
 +trait Clone { fn clone(&self) -> Self; }
 +struct S;
 +impl Clone for S {}
 +impl Clone for &S {}
 +fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
 +          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_before_autoderef() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(self) -> i8 { 0 } }
 +impl Trait for &S { fn foo(self) -> u128 { 0 } }
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_impl_before_trait() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(self) -> i8 { 0 } }
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ i8
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_impl_ref_before_trait() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(&self) -> i8 { 0 } }
 +impl Trait for &S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ i8
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_autoderef() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_unsize_array() {
 +    check_types(
 +        r#"
 +//- minicore: slice
 +fn test() {
 +    let a = [1, 2, 3];
 +    a.len();
 +} //^^^^^^^ usize
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_from_prelude() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +struct S;
 +impl Clone for S {}
 +
 +fn test() {
 +    S.clone();
 +  //^^^^^^^^^ S
 +}
 +
 +//- /lib.rs crate:core
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub trait Clone {
 +            fn clone(&self) -> Self;
 +        }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_for_unknown_trait() {
 +    // The blanket impl currently applies because we ignore the unresolved where clause
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T> Trait for T where T: UnknownTrait {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_not_met() {
 +    // The blanket impl shouldn't apply because we can't prove S: Clone
 +    // This is also to make sure that we don't resolve to the foo method just
 +    // because that's the only method named foo we can find, which would make
 +    // the below tests not work
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T> Trait for T where T: Clone {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_inline_not_met() {
 +    // The blanket impl shouldn't apply because we can't prove S: Clone
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T: Clone> Trait for T {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_1() {
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_2() {
 +    check_types(
 +        r#"
 +trait Into<T> { fn into(self) -> T; }
 +trait From<T> { fn from(other: T) -> Self; }
 +struct S1;
 +struct S2;
 +impl From<S2> for S1 {}
 +impl<T, U> Into<U> for T where U: From<T> {}
 +fn test() { S2.into(); }
 +          //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_inline() {
 +    check_types(
 +        r#"
 +trait Into<T> { fn into(self) -> T; }
 +trait From<T> { fn from(other: T) -> Self; }
 +struct S1;
 +struct S2;
 +impl From<S2> for S1 {}
 +impl<T, U: From<T>> Into<U> for T {}
 +fn test() { S2.into(); }
 +          //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_overloaded_method() {
 +    check_types(
 +        r#"
 +struct Wrapper<T>(T);
 +struct Foo<T>(T);
 +struct Bar<T>(T);
 +
 +impl<T> Wrapper<Foo<T>> {
 +    pub fn new(foo_: T) -> Self {
 +        Wrapper(Foo(foo_))
 +    }
 +}
 +
 +impl<T> Wrapper<Bar<T>> {
 +    pub fn new(bar_: T) -> Self {
 +        Wrapper(Bar(bar_))
 +    }
 +}
 +
 +fn main() {
 +    let a = Wrapper::<Foo<f32>>::new(1.0);
 +    let b = Wrapper::<Bar<f32>>::new(1.0);
 +    (a, b);
 +  //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_overloaded_const() {
 +    cov_mark::check!(const_candidate_self_type_mismatch);
 +    check_types(
 +        r#"
 +struct Wrapper<T>(T);
 +struct Foo<T>(T);
 +struct Bar<T>(T);
 +
 +impl<T> Wrapper<Foo<T>> {
 +    pub const VALUE: Foo<T>;
 +}
 +
 +impl<T> Wrapper<Bar<T>> {
 +    pub const VALUE: Bar<T>;
 +}
 +
 +fn main() {
 +    let a = Wrapper::<Foo<f32>>::VALUE;
 +    let b = Wrapper::<Bar<f32>>::VALUE;
 +    (a, b);
 +  //^^^^^^ (Foo<f32>, Bar<f32>)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_encountering_fn_type() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +fn foo() {}
 +trait FnOnce { fn call(self); }
 +fn test() { foo.call(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn super_trait_impl_return_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +        //- minicore: sized
 +        trait Base {
 +            fn foo(self) -> usize;
 +        }
 +
 +        trait Super : Base {}
 +
 +        fn base1() -> impl Base { loop {} }
 +        fn super1() -> impl Super { loop {} }
 +
 +        fn test(base2: impl Base, super2: impl Super) {
 +            base1().foo();
 +            super1().foo();
 +            base2.foo();
 +            super2.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            24..28 'self': Self
 +            90..101 '{ loop {} }': !
 +            92..99 'loop {}': !
 +            97..99 '{}': ()
 +            128..139 '{ loop {} }': !
 +            130..137 'loop {}': !
 +            135..137 '{}': ()
 +            149..154 'base2': impl Base
 +            167..173 'super2': impl Super
 +            187..264 '{     ...o(); }': ()
 +            193..198 'base1': fn base1() -> impl Base
 +            193..200 'base1()': impl Base
 +            193..206 'base1().foo()': usize
 +            212..218 'super1': fn super1() -> impl Super
 +            212..220 'super1()': impl Super
 +            212..226 'super1().foo()': usize
 +            232..237 'base2': impl Base
 +            232..243 'base2.foo()': usize
 +            249..255 'super2': impl Super
 +            249..261 'super2.foo()': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_non_parameter_type() {
 +    check_types(
 +        r#"
 +mod a {
 +    pub trait Foo {
 +        fn foo(&self);
 +    }
 +}
 +
 +struct Wrapper<T>(T);
 +fn foo<T>(t: Wrapper<T>)
 +where
 +    Wrapper<T>: a::Foo,
 +{
 +    t.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_3373() {
 +    check_types(
 +        r#"
 +struct A<T>(T);
 +
 +impl A<i32> {
 +    fn from(v: i32) -> A<i32> { A(v) }
 +}
 +
 +fn main() {
 +    A::from(3);
 +} //^^^^^^^^^^ A<i32>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_slow() {
 +    // this can get quite slow if we set the solver size limit too high
 +    check_types(
 +        r#"
 +trait SendX {}
 +
 +struct S1; impl SendX for S1 {}
 +struct S2; impl SendX for S2 {}
 +struct U1;
 +
 +trait Trait { fn method(self); }
 +
 +struct X1<A, B> {}
 +impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
 +
 +struct S<B, C> {}
 +
 +trait FnX {}
 +
 +impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
 +
 +fn test() { (S {}).method(); }
 +          //^^^^^^^^^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_super_trait_not_in_scope() {
 +    check_infer(
 +        r#"
 +        mod m {
 +            pub trait SuperTrait {
 +                fn foo(&self) -> u32 { 0 }
 +            }
 +        }
 +        trait Trait: m::SuperTrait {}
 +
 +        struct S;
 +        impl m::SuperTrait for S {}
 +        impl Trait for S {}
 +
 +        fn test(d: &dyn Trait) {
 +            d.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            51..55 'self': &Self
 +            64..69 '{ 0 }': u32
 +            66..67 '0': u32
 +            176..177 'd': &dyn Trait
 +            191..207 '{     ...o(); }': ()
 +            197..198 'd': &dyn Trait
 +            197..204 'd.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_foreign_opaque_type() {
 +    check_infer(
 +        r#"
 +extern "C" {
 +    type S;
 +    fn f() -> &'static S;
 +}
 +
 +impl S {
 +    fn foo(&self) -> bool {
 +        true
 +    }
 +}
 +
 +fn test() {
 +    let s = unsafe { f() };
 +    s.foo();
 +}
 +"#,
 +        expect![[r#"
 +            75..79 'self': &S
 +            89..109 '{     ...     }': bool
 +            99..103 'true': bool
 +            123..167 '{     ...o(); }': ()
 +            133..134 's': &S
 +            137..151 'unsafe { f() }': &S
 +            137..151 'unsafe { f() }': &S
 +            146..147 'f': fn f() -> &S
 +            146..149 'f()': &S
 +            157..158 's': &S
 +            157..164 's.foo()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_with_allocator_box_self_type() {
 +    check_types(
 +        r#"
 +struct Slice<T> {}
 +struct Box<T, A> {}
 +
 +impl<T> Slice<T> {
 +    pub fn into_vec<A>(self: Box<Self, A>) { }
 +}
 +
 +fn main() {
 +    let foo: Slice<u32>;
 +    foo.into_vec(); // we shouldn't crash on this at least
 +} //^^^^^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_on_dyn_impl() {
 +    check_types(
 +        r#"
 +trait Foo {}
 +
 +impl Foo for u32 {}
 +impl dyn Foo + '_ {
 +    pub fn dyn_foo(&self) -> u32 {
 +        0
 +    }
 +}
 +
 +fn main() {
 +    let f = &42u32 as &dyn Foo;
 +    f.dyn_foo();
 + // ^^^^^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
++#[test]
++fn dyn_trait_method_priority() {
++    check_types(
++        r#"
++//- minicore: from
++trait Trait {
++    fn into(&self) -> usize { 0 }
++}
++
++fn foo(a: &dyn Trait) {
++    let _ = a.into();
++      //^usize
++}
++        "#,
++    );
++}
++
++#[test]
++fn trait_method_priority_for_placeholder_type() {
++    check_types(
++        r#"
++//- minicore: from
++trait Trait {
++    fn into(&self) -> usize { 0 }
++}
++
++fn foo<T: Trait>(a: &T) {
++    let _ = a.into();
++      //^usize
++}
++        "#,
++    );
++}
++
 +#[test]
 +fn autoderef_visibility_field() {
 +    check(
 +        r#"
 +//- minicore: deref
 +mod a {
 +    pub struct Foo(pub char);
 +    pub struct Bar(i32);
 +    impl Bar {
 +        pub fn new() -> Self {
 +            Self(0)
 +        }
 +    }
 +    impl core::ops::Deref for Bar {
 +        type Target = Foo;
 +        fn deref(&self) -> &Foo {
 +            &Foo('z')
 +        }
 +    }
 +}
 +mod b {
 +    fn foo() {
 +        let x = super::a::Bar::new().0;
 +             // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Not)))
 +             // ^^^^^^^^^^^^^^^^^^^^^^ type: char
 +    }
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn autoderef_visibility_method() {
 +    cov_mark::check!(autoderef_candidate_not_visible);
 +    check(
 +        r#"
 +//- minicore: deref
 +mod a {
 +    pub struct Foo(pub char);
 +    impl Foo {
 +        pub fn mango(&self) -> char {
 +            self.0
 +        }
 +    }
 +    pub struct Bar(i32);
 +    impl Bar {
 +        pub fn new() -> Self {
 +            Self(0)
 +        }
 +        fn mango(&self) -> i32 {
 +            self.0
 +        }
 +    }
 +    impl core::ops::Deref for Bar {
 +        type Target = Foo;
 +        fn deref(&self) -> &Foo {
 +            &Foo('z')
 +        }
 +    }
 +}
 +mod b {
 +    fn foo() {
 +        let x = super::a::Bar::new().mango();
 +             // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: char
 +    }
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn trait_vs_private_inherent_const() {
 +    cov_mark::check!(const_candidate_not_visible);
 +    check(
 +        r#"
 +mod a {
 +    pub struct Foo;
 +    impl Foo {
 +        const VALUE: u32 = 2;
 +    }
 +    pub trait Trait {
 +        const VALUE: usize;
 +    }
 +    impl Trait for Foo {
 +        const VALUE: usize = 3;
 +    }
 +
 +    fn foo() {
 +        let x = Foo::VALUE;
 +            //  ^^^^^^^^^^ type: u32
 +    }
 +}
 +use a::Trait;
 +fn foo() {
 +    let x = a::Foo::VALUE;
 +         // ^^^^^^^^^^^^^ type: usize
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn trait_impl_in_unnamed_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Tr {
 +    fn method(&self) -> u16;
 +}
 +
 +const _: () = {
 +    impl Tr for S {}
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_in_synstructure_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Tr {
 +    fn method(&self) -> u16;
 +}
 +
 +const _DERIVE_Tr_: () = {
 +    impl Tr for S {}
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn inherent_impl_in_unnamed_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +const _: () = {
 +    impl S {
 +        fn method(&self) -> u16 { 0 }
 +
 +        pub(super) fn super_method(&self) -> u16 { 0 }
 +
 +        pub(crate) fn crate_method(&self) -> u16 { 0 }
 +
 +        pub fn pub_method(&self) -> u16 { 0 }
 +    }
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +
 +    S.super_method();
 +  //^^^^^^^^^^^^^^^^ u16
 +
 +    S.crate_method();
 +  //^^^^^^^^^^^^^^^^ u16
 +
 +    S.pub_method();
 +  //^^^^^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_const_generic_array_methods() {
 +    check_types(
 +        r#"
 +#[lang = "array"]
 +impl<T, const N: usize> [T; N] {
 +    pub fn map<F, U>(self, f: F) -> [U; N]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +#[lang = "slice"]
 +impl<T> [T] {
 +    pub fn map<F, U>(self, f: F) -> &[U]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +fn f() {
 +    let v = [1, 2].map::<_, usize>(|x| -> x * 2);
 +    v;
 +  //^ [usize; 2]
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_const_generic_method() {
 +    check_types(
 +        r#"
 +struct Const<const N: usize>;
 +
 +#[lang = "array"]
 +impl<T, const N: usize> [T; N] {
 +    pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +#[lang = "slice"]
 +impl<T> [T] {
 +    pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +fn f<const C: usize, P>() {
 +    let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>);
 +    v;
 +  //^ [(); 12]
 +    let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>);
 +    v;
 +  //^ [P; C]
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_type_alias() {
 +    check_types(
 +        r#"
 +struct Const<const N: usize>;
 +type U2 = Const<2>;
 +type U5 = Const<5>;
 +
 +impl U2 {
 +    fn f(self) -> Const<12> {
 +        loop {}
 +    }
 +}
 +
 +impl U5 {
 +    fn f(self) -> Const<15> {
 +        loop {}
 +    }
 +}
 +
 +fn f(x: U2) {
 +    let y = x.f();
 +      //^ Const<12>
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn skip_array_during_method_dispatch() {
 +    check_types(
 +        r#"
 +//- /main2018.rs crate:main2018 deps:core
 +use core::IntoIterator;
 +
 +fn f() {
 +    let v = [4].into_iter();
 +    v;
 +  //^ &i32
 +
 +    let a = [0, 1].into_iter();
 +    a;
 +  //^ &i32
 +}
 +
 +//- /main2021.rs crate:main2021 deps:core edition:2021
 +use core::IntoIterator;
 +
 +fn f() {
 +    let v = [4].into_iter();
 +    v;
 +  //^ i32
 +
 +    let a = [0, 1].into_iter();
 +    a;
 +  //^ &i32
 +}
 +
 +//- /core.rs crate:core
 +#[rustc_skip_array_during_method_dispatch]
 +pub trait IntoIterator {
 +    type Out;
 +    fn into_iter(self) -> Self::Out;
 +}
 +
 +impl<T> IntoIterator for [T; 1] {
 +    type Out = T;
 +    fn into_iter(self) -> Self::Out { loop {} }
 +}
 +impl<'a, T> IntoIterator for &'a [T] {
 +    type Out = &'a T;
 +    fn into_iter(self) -> Self::Out { loop {} }
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn sized_blanket_impl() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Foo { fn foo() -> u8; }
 +impl<T: Sized> Foo for T {}
 +fn f<S: Sized, T, U: ?Sized>() {
 +    u32::foo;
 +    S::foo;
 +    T::foo;
 +    U::foo;
 +    <[u32]>::foo;
 +}
 +"#,
 +        expect![[r#"
 +            89..160 '{     ...foo; }': ()
 +            95..103 'u32::foo': fn foo<u32>() -> u8
 +            109..115 'S::foo': fn foo<S>() -> u8
 +            121..127 'T::foo': fn foo<T>() -> u8
 +            133..139 'U::foo': {unknown}
 +            145..157 '<[u32]>::foo': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn local_impl() {
 +    check_types(
 +        r#"
 +fn main() {
 +    struct SomeStruct(i32);
 +
 +    impl SomeStruct {
 +        fn is_even(&self) -> bool {
 +            self.0 % 2 == 0
 +        }
 +    }
 +
 +    let o = SomeStruct(3);
 +    let is_even = o.is_even();
 +     // ^^^^^^^ bool
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn deref_fun_1() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +
 +struct A<T, U>(T, U);
 +struct B<T>(T);
 +struct C<T>(T);
 +
 +impl<T> core::ops::Deref for A<B<T>, u32> {
 +    type Target = B<T>;
 +    fn deref(&self) -> &B<T> { &self.0 }
 +}
 +impl core::ops::Deref for B<isize> {
 +    type Target = C<isize>;
 +    fn deref(&self) -> &C<isize> { loop {} }
 +}
 +
 +impl<T: Copy> C<T> {
 +    fn thing(&self) -> T { self.0 }
 +}
 +
 +fn make<T>() -> T { loop {} }
 +
 +fn test() {
 +    let a1 = A(make(), make());
 +    let _: usize = (*a1).0;
 +    a1;
 +  //^^ A<B<usize>, u32>
 +
 +    let a2 = A(make(), make());
 +    a2.thing();
 +  //^^^^^^^^^^ isize
 +    a2;
 +  //^^ A<B<isize>, u32>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_fun_2() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +
 +struct A<T, U>(T, U);
 +struct B<T>(T);
 +struct C<T>(T);
 +
 +impl<T> core::ops::Deref for A<B<T>, u32> {
 +    type Target = B<T>;
 +    fn deref(&self) -> &B<T> { &self.0 }
 +}
 +impl core::ops::Deref for B<isize> {
 +    type Target = C<isize>;
 +    fn deref(&self) -> &C<isize> { loop {} }
 +}
 +
 +impl<T> core::ops::Deref for A<C<T>, i32> {
 +    type Target = C<T>;
 +    fn deref(&self) -> &C<T> { &self.0 }
 +}
 +
 +impl<T: Copy> C<T> {
 +    fn thing(&self) -> T { self.0 }
 +}
 +
 +fn make<T>() -> T { loop {} }
 +
 +fn test() {
 +    let a1 = A(make(), 1u32);
 +    a1.thing();
 +    a1;
 +  //^^ A<B<isize>, u32>
 +
 +    let a2 = A(make(), 1i32);
 +    let _: &str = a2.thing();
 +    a2;
 +  //^^ A<C<&str>, i32>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn receiver_adjustment_autoref() {
 +    check(
 +        r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn test() {
 +    Foo.foo();
 +  //^^^ adjustments: Borrow(Ref(Not))
 +    (&Foo).foo();
 +  // ^^^^ adjustments: ,
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn receiver_adjustment_unsize_array() {
 +    // FIXME not quite correct
 +    check(
 +        r#"
 +//- minicore: slice
 +fn test() {
 +    let a = [1, 2, 3];
 +    a.len();
 +} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not))
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bad_inferred_reference_1() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: sized
 +pub trait Into<T>: Sized {
 +    fn into(self) -> T;
 +}
 +impl<T> Into<T> for T {
 +    fn into(self) -> T { self }
 +}
 +
 +trait ExactSizeIterator {
 +    fn len(&self) -> usize;
 +}
 +
 +pub struct Foo;
 +impl Foo {
 +    fn len(&self) -> usize { 0 }
 +}
 +
 +pub fn test(generic_args: impl Into<Foo>) {
 +    let generic_args = generic_args.into();
 +    generic_args.len();
 +    let _: Foo = generic_args;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bad_inferred_reference_2() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: deref
 +trait ExactSizeIterator {
 +    fn len(&self) -> usize;
 +}
 +
 +pub struct Foo;
 +impl Foo {
 +    fn len(&self) -> usize { 0 }
 +}
 +
 +pub fn test() {
 +    let generic_args;
 +    generic_args.len();
 +    let _: Foo = generic_args;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_minicore_iterator() {
 +    check_types(
 +        r#"
 +//- minicore: iterators, sized
 +fn foo() {
 +    let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
 +}         //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option<i32>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn primitive_assoc_fn_shadowed_by_use() {
 +    check_types(
 +        r#"
 +//- /lib.rs crate:lib deps:core
 +use core::u16;
 +
 +fn f() -> u16 {
 +    let x = u16::from_le_bytes();
 +      x
 +    //^ u16
 +}
 +
 +//- /core.rs crate:core
 +pub mod u16 {}
 +
 +impl u16 {
 +    pub fn from_le_bytes() -> Self { 0 }
 +}
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn with_impl_bounds() {
 +    check_types(
 +        r#"
 +trait Trait {}
 +struct Foo<T>(T);
 +impl Trait for isize {}
 +
 +impl<T: Trait> Foo<T> {
 +  fn foo() -> isize { 0 }
 +  fn bar(&self) -> isize { 0 }
 +}
 +
 +impl Foo<()> {
 +  fn foo() {}
 +  fn bar(&self) {}
 +}
 +
 +fn f() {
 +  let _ = Foo::<isize>::foo();
 +    //^isize
 +  let _ = Foo(0isize).bar();
 +    //^isize
 +  let _ = Foo::<()>::foo();
 +    //^()
 +  let _ = Foo(()).bar();
 +    //^()
 +  let _ = Foo::<usize>::foo();
 +    //^{unknown}
 +  let _ = Foo(0usize).bar();
 +    //^{unknown}
 +}
 +
 +fn g<T: Trait>(a: T) {
 +    let _ = Foo::<T>::foo();
 +      //^isize
 +    let _ = Foo(a).bar();
 +      //^isize
 +}
 +        "#,
 +    );
 +}
index 77afeb3217dd02779e5ef65cf48d6e9ff162a5e9,0000000000000000000000000000000000000000..372c3a3cca644fd0966c88bc992c5c06087ffb03
mode 100644,000000..100644
--- /dev/null
@@@ -1,187 -1,0 +1,198 @@@
- use std::env::var;
 +//! Trait solving using Chalk.
 +
-     db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
-     Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
++use std::{env::var, sync::Arc};
 +
 +use chalk_ir::GoalData;
 +use chalk_recursive::Cache;
 +use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
 +
 +use base_db::CrateId;
 +use hir_def::{lang_item::LangItemTarget, TraitId};
 +use stdx::panic_context;
 +use syntax::SmolStr;
 +
 +use crate::{
++    db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
++    Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
++    WhereClause,
 +};
 +
 +/// This controls how much 'time' we give the Chalk solver before giving up.
 +const CHALK_SOLVER_FUEL: i32 = 100;
 +
 +#[derive(Debug, Copy, Clone)]
 +pub(crate) struct ChalkContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) krate: CrateId,
 +}
 +
 +fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
 +    let overflow_depth =
 +        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500);
 +    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
 +    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
 +}
 +
 +/// A set of clauses that we assume to be true. E.g. if we are inside this function:
 +/// ```rust
 +/// fn foo<T: Default>(t: T) {}
 +/// ```
 +/// we assume that `T: Default`.
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TraitEnvironment {
 +    pub krate: CrateId,
 +    // FIXME make this a BTreeMap
 +    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
 +    pub env: chalk_ir::Environment<Interner>,
 +}
 +
 +impl TraitEnvironment {
 +    pub fn empty(krate: CrateId) -> Self {
 +        TraitEnvironment {
 +            krate,
 +            traits_from_clauses: Vec::new(),
 +            env: chalk_ir::Environment::new(Interner),
 +        }
 +    }
 +
 +    pub fn traits_in_scope_from_clauses<'a>(
 +        &'a self,
 +        ty: Ty,
 +    ) -> impl Iterator<Item = TraitId> + 'a {
 +        self.traits_from_clauses
 +            .iter()
 +            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
 +    }
 +}
 +
++pub(crate) fn normalize_projection_query(
++    db: &dyn HirDatabase,
++    projection: ProjectionTy,
++    env: Arc<TraitEnvironment>,
++) -> Ty {
++    let mut table = InferenceTable::new(db, env);
++    let ty = table.normalize_projection_ty(projection);
++    table.resolve_completely(ty)
++}
++
 +/// Solve a trait goal using Chalk.
 +pub(crate) fn trait_solve_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    goal: Canonical<InEnvironment<Goal>>,
 +) -> Option<Solution> {
 +    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
 +        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
 +            db.trait_data(it.hir_trait_id()).name.to_string()
 +        }
 +        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
 +        _ => "??".to_string(),
 +    });
 +    tracing::info!("trait_solve_query({:?})", goal.value.goal);
 +
 +    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
 +        alias: AliasTy::Projection(projection_ty),
 +        ..
 +    }))) = &goal.value.goal.data(Interner)
 +    {
 +        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
 +            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
 +            return Some(Solution::Ambig(Guidance::Unknown));
 +        }
 +    }
 +
 +    // We currently don't deal with universes (I think / hope they're not yet
 +    // relevant for our use cases?)
 +    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
 +    solve(db, krate, &u_canonical)
 +}
 +
 +fn solve(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
 +) -> Option<chalk_solve::Solution<Interner>> {
 +    let context = ChalkContext { db, krate };
 +    tracing::debug!("solve goal: {:?}", goal);
 +    let mut solver = create_chalk_solver();
 +
 +    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
 +
 +    let should_continue = || {
 +        db.unwind_if_cancelled();
 +        let remaining = fuel.get();
 +        fuel.set(remaining - 1);
 +        if remaining == 0 {
 +            tracing::debug!("fuel exhausted");
 +        }
 +        remaining > 0
 +    };
 +
 +    let mut solve = || {
 +        let _ctx = if is_chalk_debug() || is_chalk_print() {
 +            Some(panic_context::enter(format!("solving {:?}", goal)))
 +        } else {
 +            None
 +        };
 +        let solution = if is_chalk_print() {
 +            let logging_db =
 +                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
 +            solver.solve_limited(&logging_db.0, goal, &should_continue)
 +        } else {
 +            solver.solve_limited(&context, goal, &should_continue)
 +        };
 +
 +        tracing::debug!("solve({:?}) => {:?}", goal, solution);
 +
 +        solution
 +    };
 +
 +    // don't set the TLS for Chalk unless Chalk debugging is active, to make
 +    // extra sure we only use it for debugging
 +    if is_chalk_debug() {
 +        crate::tls::set_current_program(db, solve)
 +    } else {
 +        solve()
 +    }
 +}
 +
 +struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);
 +
 +impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
 +    fn drop(&mut self) {
 +        eprintln!("chalk program:\n{}", self.0);
 +    }
 +}
 +
 +fn is_chalk_debug() -> bool {
 +    std::env::var("CHALK_DEBUG").is_ok()
 +}
 +
 +fn is_chalk_print() -> bool {
 +    std::env::var("CHALK_PRINT").is_ok()
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum FnTrait {
 +    FnOnce,
 +    FnMut,
 +    Fn,
 +}
 +
 +impl FnTrait {
 +    const fn lang_item_name(self) -> &'static str {
 +        match self {
 +            FnTrait::FnOnce => "fn_once",
 +            FnTrait::FnMut => "fn_mut",
 +            FnTrait::Fn => "fn",
 +        }
 +    }
 +
 +    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
 +        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
 +        match target {
 +            LangItemTarget::TraitId(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +}
index e4bb63a864719956e4b31b76e8994852f3b3ca55,0000000000000000000000000000000000000000..d2717c5665471e70f7b1bbe7e0f9a01d2d193295
mode 100644,000000..100644
--- /dev/null
@@@ -1,3663 -1,0 +1,3659 @@@
-     AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
-     ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
-     QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
-     TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
 +//! HIR (previously known as descriptors) provides a high-level object oriented
 +//! access to Rust code.
 +//!
 +//! The principal difference between HIR and syntax trees is that HIR is bound
 +//! to a particular crate instance. That is, it has cfg flags and features
 +//! applied. So, the relation between syntax and HIR is many-to-one.
 +//!
 +//! HIR is the public API of the all of the compiler logic above syntax trees.
 +//! It is written in "OO" style. Each type is self contained (as in, it knows it's
 +//! parents and full context). It should be "clean code".
 +//!
 +//! `hir_*` crates are the implementation of the compiler logic.
 +//! They are written in "ECS" style, with relatively little abstractions.
 +//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
 +//!
 +//! `hir` is what insulates the "we don't know how to actually write an incremental compiler"
 +//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
 +//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +#![recursion_limit = "512"]
 +
 +mod semantics;
 +mod source_analyzer;
 +
 +mod from_id;
 +mod attrs;
 +mod has_source;
 +
 +pub mod diagnostics;
 +pub mod db;
 +pub mod symbols;
 +
 +mod display;
 +
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
 +use either::Either;
 +use hir_def::{
 +    adt::{ReprKind, VariantData},
 +    body::{BodyDiagnostic, SyntheticSyntax},
 +    expr::{BindingAnnotation, LabelId, Pat, PatId},
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    item_tree::ItemTreeNode,
 +    lang_item::LangItemTarget,
 +    nameres::{self, diagnostics::DefDiagnostic},
 +    per_ns::PerNs,
 +    resolver::{HasResolver, Resolver},
 +    src::HasSource as _,
 +    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
 +    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
 +    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 +};
 +use hir_expand::{name::name, MacroCallKind};
 +use hir_ty::{
 +    all_super_traits, autoderef,
 +    consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt},
 +    diagnostics::BodyValidationDiagnostic,
 +    method_resolution::{self, TyFingerprint},
 +    primitive::UintTy,
 +    subst_prefix,
 +    traits::FnTrait,
-     pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
-         hir_def::find_path::find_path(db, item.into().into(), self.into())
++    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
++    GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
++    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
 +use stdx::{impl_from, never};
 +use syntax::{
 +    ast::{self, HasAttrs as _, HasDocComments, HasName},
 +    AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
 +};
 +
 +use crate::db::{DefDatabase, HirDatabase};
 +
 +pub use crate::{
 +    attrs::{HasAttrs, Namespace},
 +    diagnostics::{
 +        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
 +        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
 +        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
 +        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
 +        UnresolvedModule, UnresolvedProcMacro,
 +    },
 +    has_source::HasSource,
 +    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
 +};
 +
 +// Be careful with these re-exports.
 +//
 +// `hir` is the boundary between the compiler and the IDE. It should try hard to
 +// isolate the compiler from the ide, to allow the two to be refactored
 +// independently. Re-exporting something from the compiler is the sure way to
 +// breach the boundary.
 +//
 +// Generally, a refactoring which *removes* a name from this list is a good
 +// idea!
 +pub use {
 +    cfg::{CfgAtom, CfgExpr, CfgOptions},
 +    hir_def::{
 +        adt::StructKind,
 +        attr::{Attr, Attrs, AttrsWithOwner, Documentation},
 +        builtin_attr::AttributeTemplate,
 +        find_path::PrefixKind,
 +        import_map,
 +        nameres::ModuleSource,
 +        path::{ModPath, PathKind},
 +        type_ref::{Mutability, TypeRef},
 +        visibility::Visibility,
 +    },
 +    hir_expand::{
 +        name::{known, Name},
 +        ExpandResult, HirFileId, InFile, MacroFile, Origin,
 +    },
 +    hir_ty::display::HirDisplay,
 +};
 +
 +// These are negative re-exports: pub using these names is forbidden, they
 +// should remain private to hir internals.
 +#[allow(unused)]
 +use {
 +    hir_def::path::Path,
 +    hir_expand::{hygiene::Hygiene, name::AsName},
 +};
 +
 +/// hir::Crate describes a single crate. It's the main interface with which
 +/// a crate's dependencies interact. Mostly, it should be just a proxy for the
 +/// root module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Crate {
 +    pub(crate) id: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct CrateDependency {
 +    pub krate: Crate,
 +    pub name: Name,
 +}
 +
 +impl Crate {
 +    pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
 +        db.crate_graph()[self.id].origin.clone()
 +    }
 +
 +    pub fn is_builtin(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.origin(db), CrateOrigin::Lang(_))
 +    }
 +
 +    pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
 +        db.crate_graph()[self.id]
 +            .dependencies
 +            .iter()
 +            .map(|dep| {
 +                let krate = Crate { id: dep.crate_id };
 +                let name = dep.as_name();
 +                CrateDependency { krate, name }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
 +        let crate_graph = db.crate_graph();
 +        crate_graph
 +            .iter()
 +            .filter(|&krate| {
 +                crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
 +            })
 +            .map(|id| Crate { id })
 +            .collect()
 +    }
 +
 +    pub fn transitive_reverse_dependencies(
 +        self,
 +        db: &dyn HirDatabase,
 +    ) -> impl Iterator<Item = Crate> {
 +        db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
 +    }
 +
 +    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id);
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let def_map = db.crate_def_map(self.id);
 +        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
 +    }
 +
 +    pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
 +        db.crate_graph()[self.id].root_file_id
 +    }
 +
 +    pub fn edition(self, db: &dyn HirDatabase) -> Edition {
 +        db.crate_graph()[self.id].edition
 +    }
 +
 +    pub fn version(self, db: &dyn HirDatabase) -> Option<String> {
 +        db.crate_graph()[self.id].version.clone()
 +    }
 +
 +    pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
 +        db.crate_graph()[self.id].display_name.clone()
 +    }
 +
 +    pub fn query_external_importables(
 +        self,
 +        db: &dyn DefDatabase,
 +        query: import_map::Query,
 +    ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
 +        let _p = profile::span("query_external_importables");
 +        import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| {
 +            match ItemInNs::from(item) {
 +                ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
 +                ItemInNs::Macros(mac_id) => Either::Right(mac_id),
 +            }
 +        })
 +    }
 +
 +    pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
 +        db.crate_graph().iter().map(|id| Crate { id }).collect()
 +    }
 +
 +    /// Try to get the root URL of the documentation of a crate.
 +    pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
 +        // Look for #![doc(html_root_url = "...")]
 +        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
 +        let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
 +        doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
 +    }
 +
 +    pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].cfg_options.clone()
 +    }
 +
 +    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].potential_cfg_options.clone()
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Module {
 +    pub(crate) id: ModuleId,
 +}
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDef {
 +    Module(Module),
 +    Function(Function),
 +    Adt(Adt),
 +    // Can't be directly declared, but can be imported.
 +    Variant(Variant),
 +    Const(Const),
 +    Static(Static),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    BuiltinType(BuiltinType),
 +    Macro(Macro),
 +}
 +impl_from!(
 +    Module,
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Variant,
 +    Const,
 +    Static,
 +    Trait,
 +    TypeAlias,
 +    BuiltinType,
 +    Macro
 +    for ModuleDef
 +);
 +
 +impl From<VariantDef> for ModuleDef {
 +    fn from(var: VariantDef) -> Self {
 +        match var {
 +            VariantDef::Struct(t) => Adt::from(t).into(),
 +            VariantDef::Union(t) => Adt::from(t).into(),
 +            VariantDef::Variant(t) => t.into(),
 +        }
 +    }
 +}
 +
 +impl ModuleDef {
 +    pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
 +        match self {
 +            ModuleDef::Module(it) => it.parent(db),
 +            ModuleDef::Function(it) => Some(it.module(db)),
 +            ModuleDef::Adt(it) => Some(it.module(db)),
 +            ModuleDef::Variant(it) => Some(it.module(db)),
 +            ModuleDef::Const(it) => Some(it.module(db)),
 +            ModuleDef::Static(it) => Some(it.module(db)),
 +            ModuleDef::Trait(it) => Some(it.module(db)),
 +            ModuleDef::TypeAlias(it) => Some(it.module(db)),
 +            ModuleDef::Macro(it) => Some(it.module(db)),
 +            ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
 +        let mut segments = vec![self.name(db)?];
 +        for m in self.module(db)?.path_to_root(db) {
 +            segments.extend(m.name(db))
 +        }
 +        segments.reverse();
 +        Some(segments.into_iter().join("::"))
 +    }
 +
 +    pub fn canonical_module_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Option<impl Iterator<Item = Module>> {
 +        self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let name = match self {
 +            ModuleDef::Module(it) => it.name(db)?,
 +            ModuleDef::Const(it) => it.name(db)?,
 +            ModuleDef::Adt(it) => it.name(db),
 +            ModuleDef::Trait(it) => it.name(db),
 +            ModuleDef::Function(it) => it.name(db),
 +            ModuleDef::Variant(it) => it.name(db),
 +            ModuleDef::TypeAlias(it) => it.name(db),
 +            ModuleDef::Static(it) => it.name(db),
 +            ModuleDef::Macro(it) => it.name(db),
 +            ModuleDef::BuiltinType(it) => it.name(),
 +        };
 +        Some(name)
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
 +        let id = match self {
 +            ModuleDef::Adt(it) => match it {
 +                Adt::Struct(it) => it.id.into(),
 +                Adt::Enum(it) => it.id.into(),
 +                Adt::Union(it) => it.id.into(),
 +            },
 +            ModuleDef::Trait(it) => it.id.into(),
 +            ModuleDef::Function(it) => it.id.into(),
 +            ModuleDef::TypeAlias(it) => it.id.into(),
 +            ModuleDef::Module(it) => it.id.into(),
 +            ModuleDef::Const(it) => it.id.into(),
 +            ModuleDef::Static(it) => it.id.into(),
 +            _ => return Vec::new(),
 +        };
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut acc = Vec::new();
 +
 +        match self.as_def_with_body() {
 +            Some(def) => {
 +                def.diagnostics(db, &mut acc);
 +            }
 +            None => {
 +                for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
 +                    acc.push(diag.into())
 +                }
 +            }
 +        }
 +
 +        acc
 +    }
 +
 +    pub fn as_def_with_body(self) -> Option<DefWithBody> {
 +        match self {
 +            ModuleDef::Function(it) => Some(it.into()),
 +            ModuleDef::Const(it) => Some(it.into()),
 +            ModuleDef::Static(it) => Some(it.into()),
 +
 +            ModuleDef::Module(_)
 +            | ModuleDef::Adt(_)
 +            | ModuleDef::Variant(_)
 +            | ModuleDef::Trait(_)
 +            | ModuleDef::TypeAlias(_)
 +            | ModuleDef::Macro(_)
 +            | ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        Some(match self {
 +            ModuleDef::Module(it) => it.attrs(db),
 +            ModuleDef::Function(it) => it.attrs(db),
 +            ModuleDef::Adt(it) => it.attrs(db),
 +            ModuleDef::Variant(it) => it.attrs(db),
 +            ModuleDef::Const(it) => it.attrs(db),
 +            ModuleDef::Static(it) => it.attrs(db),
 +            ModuleDef::Trait(it) => it.attrs(db),
 +            ModuleDef::TypeAlias(it) => it.attrs(db),
 +            ModuleDef::Macro(it) => it.attrs(db),
 +            ModuleDef::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl HasVisibility for ModuleDef {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match *self {
 +            ModuleDef::Module(it) => it.visibility(db),
 +            ModuleDef::Function(it) => it.visibility(db),
 +            ModuleDef::Adt(it) => it.visibility(db),
 +            ModuleDef::Const(it) => it.visibility(db),
 +            ModuleDef::Static(it) => it.visibility(db),
 +            ModuleDef::Trait(it) => it.visibility(db),
 +            ModuleDef::TypeAlias(it) => it.visibility(db),
 +            ModuleDef::Variant(it) => it.visibility(db),
 +            ModuleDef::Macro(it) => it.visibility(db),
 +            ModuleDef::BuiltinType(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +impl Module {
 +    /// Name of this module.
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent = def_map[self.id.local_id].parent?;
 +        def_map[parent].children.iter().find_map(|(name, module_id)| {
 +            if *module_id == self.id.local_id {
 +                Some(name.clone())
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +
 +    /// Returns the crate this module is part of.
 +    pub fn krate(self) -> Crate {
 +        Crate { id: self.id.krate() }
 +    }
 +
 +    /// Topmost parent of this module. Every module has a `crate_root`, but some
 +    /// might be missing `krate`. This can happen if a module's file is not included
 +    /// in the module tree of any target in `Cargo.toml`.
 +    pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        def_map.root() == self.id.local_id
 +    }
 +
 +    /// Iterates over all child modules.
 +    pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let children = def_map[self.id.local_id]
 +            .children
 +            .iter()
 +            .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
 +            .collect::<Vec<_>>();
 +        children.into_iter()
 +    }
 +
 +    /// Finds a parent module.
 +    pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
 +        // FIXME: handle block expressions as modules (their parent is in a different DefMap)
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent_id = def_map[self.id.local_id].parent?;
 +        Some(Module { id: def_map.module_id(parent_id) })
 +    }
 +
 +    pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let mut res = vec![self];
 +        let mut curr = self;
 +        while let Some(next) = curr.parent(db) {
 +            res.push(next);
 +            curr = next
 +        }
 +        res
 +    }
 +
 +    /// Returns a `ModuleScope`: a set of items, visible in this module.
 +    pub fn scope(
 +        self,
 +        db: &dyn HirDatabase,
 +        visible_from: Option<Module>,
 +    ) -> Vec<(Name, ScopeDef)> {
 +        self.id.def_map(db.upcast())[self.id.local_id]
 +            .scope
 +            .entries()
 +            .filter_map(|(name, def)| {
 +                if let Some(m) = visible_from {
 +                    let filtered =
 +                        def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
 +                    if filtered.is_none() && !def.is_none() {
 +                        None
 +                    } else {
 +                        Some((name, filtered))
 +                    }
 +                } else {
 +                    Some((name, def))
 +                }
 +            })
 +            .flat_map(|(name, def)| {
 +                ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
 +            })
 +            .collect()
 +    }
 +
 +    /// Fills `acc` with the module's diagnostics.
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let _p = profile::span("Module::diagnostics").detail(|| {
 +            format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
 +        });
 +        let def_map = self.id.def_map(db.upcast());
 +        for diag in def_map.diagnostics() {
 +            if diag.in_module != self.id.local_id {
 +                // FIXME: This is accidentally quadratic.
 +                continue;
 +            }
 +            emit_def_diagnostic(db, acc, diag);
 +        }
 +        for decl in self.declarations(db) {
 +            match decl {
 +                ModuleDef::Module(m) => {
 +                    // Only add diagnostics from inline modules
 +                    if def_map[m.id.local_id].origin.is_inline() {
 +                        m.diagnostics(db, acc)
 +                    }
 +                }
 +                ModuleDef::Trait(t) => {
 +                    for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
 +                        emit_def_diagnostic(db, acc, diag);
 +                    }
 +                    acc.extend(decl.diagnostics(db))
 +                }
 +                _ => acc.extend(decl.diagnostics(db)),
 +            }
 +        }
 +
 +        for impl_def in self.impl_defs(db) {
 +            for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +
 +            for item in impl_def.items(db) {
 +                let def: DefWithBody = match item {
 +                    AssocItem::Function(it) => it.into(),
 +                    AssocItem::Const(it) => it.into(),
 +                    AssocItem::TypeAlias(_) => continue,
 +                };
 +
 +                def.diagnostics(db, acc);
 +            }
 +        }
 +    }
 +
 +    pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope
 +            .declarations()
 +            .map(ModuleDef::from)
 +            .chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id))))
 +            .collect()
 +    }
 +
 +    pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| MacroId::from(it).into()).collect()
 +    }
 +
 +    pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
 +        let def_map = self.id.def_map(db.upcast());
 +        def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible.
-         hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
++    pub fn find_use_path(
++        self,
++        db: &dyn DefDatabase,
++        item: impl Into<ItemInNs>,
++        prefer_no_std: bool,
++    ) -> Option<ModPath> {
++        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible. This is used for returning import paths for use-statements.
 +    pub fn find_use_path_prefixed(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefix_kind: PrefixKind,
++        prefer_no_std: bool,
 +    ) -> Option<ModPath> {
-         let goal = hir_ty::make_canonical(
-             InEnvironment::new(
-                 &self.env.env,
-                 AliasEq {
-                     alias: AliasTy::Projection(projection),
-                     ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                         .intern(Interner),
-                 }
-                 .cast(Interner),
-             ),
-             [TyVariableKind::General].into_iter(),
-         );
++        hir_def::find_path::find_path_prefixed(
++            db,
++            item.into().into(),
++            self.into(),
++            prefix_kind,
++            prefer_no_std,
++        )
 +    }
 +}
 +
 +fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
 +    match &diag.kind {
 +        DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
 +            let decl = declaration.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedModule {
 +                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
 +                    candidates: candidates.clone(),
 +                }
 +                .into(),
 +            )
 +        }
 +        DefDiagnosticKind::UnresolvedExternCrate { ast } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedImport { id, index } => {
 +            let file_id = id.file_id();
 +            let item_tree = id.item_tree(db.upcast());
 +            let import = &item_tree[id.value];
 +
 +            let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
 +            acc.push(
 +                UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                InactiveCode {
 +                    node: ast.with_value(AstPtr::new(&item).into()),
 +                    cfg: cfg.clone(),
 +                    opts: opts.clone(),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
 +            let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
 +                    .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedMacroCall {
 +                    macro_call: node,
 +                    precise_location,
 +                    path: path.clone(),
 +                    is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::MacroError { ast, message } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
 +        }
 +
 +        DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
 +            let node = ast.to_node(db.upcast());
 +            // Must have a name, otherwise we wouldn't emit it.
 +            let name = node.name().expect("unimplemented builtin macro with no name");
 +            acc.push(
 +                UnimplementedBuiltinMacro {
 +                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
 +                }
 +                .into(),
 +            );
 +        }
 +        DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        InvalidDeriveTarget {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +        DefDiagnosticKind::MalformedDerive { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        MalformedDerive {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +    }
 +}
 +
 +fn precise_macro_call_location(
 +    ast: &MacroCallKind,
 +    db: &dyn HirDatabase,
 +) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
 +    // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
 +    // - e.g. the full attribute for macro errors, but only the name for name resolution
 +    match ast {
 +        MacroCallKind::FnLike { ast_id, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                node.path()
 +                    .and_then(|it| it.segment())
 +                    .and_then(|it| it.name_ref())
 +                    .map(|it| it.syntax().text_range()),
 +                node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
 +                MacroKind::ProcMacro,
 +            )
 +        }
 +        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
 +            let node = ast_id.to_node(db.upcast());
 +            // Compute the precise location of the macro name's token in the derive
 +            // list.
 +            let token = (|| {
 +                let derive_attr = node
 +                    .doc_comments_and_attrs()
 +                    .nth(*derive_attr_index as usize)
 +                    .and_then(Either::left)?;
 +                let token_tree = derive_attr.meta()?.token_tree()?;
 +                let group_by = token_tree
 +                    .syntax()
 +                    .children_with_tokens()
 +                    .filter_map(|elem| match elem {
 +                        syntax::NodeOrToken::Token(tok) => Some(tok),
 +                        _ => None,
 +                    })
 +                    .group_by(|t| t.kind() == T![,]);
 +                let (_, mut group) = group_by
 +                    .into_iter()
 +                    .filter(|&(comma, _)| !comma)
 +                    .nth(*derive_index as usize)?;
 +                group.find(|t| t.kind() == T![ident])
 +            })();
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                token.as_ref().map(|tok| tok.text_range()),
 +                token.as_ref().map(ToString::to_string),
 +                MacroKind::Derive,
 +            )
 +        }
 +        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            let attr = node
 +                .doc_comments_and_attrs()
 +                .nth((*invoc_attr_index) as usize)
 +                .and_then(Either::left)
 +                .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
 +
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
 +                Some(attr.syntax().text_range()),
 +                attr.path()
 +                    .and_then(|path| path.segment())
 +                    .and_then(|seg| seg.name_ref())
 +                    .as_ref()
 +                    .map(ToString::to_string),
 +                MacroKind::Attr,
 +            )
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Module {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let def_map = self.id.def_map(db.upcast());
 +        let module_data = &def_map[self.id.local_id];
 +        module_data.visibility
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Field {
 +    pub(crate) parent: VariantDef,
 +    pub(crate) id: LocalFieldId,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum FieldSource {
 +    Named(ast::RecordField),
 +    Pos(ast::TupleField),
 +}
 +
 +impl Field {
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        self.parent.variant_data(db).fields()[self.id].name.clone()
 +    }
 +
 +    /// Returns the type as in the signature of the struct (i.e., with
 +    /// placeholder types for type parameters). Only use this in the context of
 +    /// the field definition.
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let var_id = self.parent.into();
 +        let generic_def_id: GenericDefId = match self.parent {
 +            VariantDef::Struct(it) => it.id.into(),
 +            VariantDef::Union(it) => it.id.into(),
 +            VariantDef::Variant(it) => it.parent.id.into(),
 +        };
 +        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
 +        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
 +        Type::new(db, var_id, ty)
 +    }
 +
 +    pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
 +        self.parent
 +    }
 +}
 +
 +impl HasVisibility for Field {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let variant_data = self.parent.variant_data(db);
 +        let visibility = &variant_data.fields()[self.id].visibility;
 +        let parent_id: hir_def::VariantId = self.parent.into();
 +        visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Struct {
 +    pub(crate) id: StructId,
 +}
 +
 +impl Struct {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.struct_data(self.id).name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.struct_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
 +        db.struct_data(self.id).repr.clone()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.struct_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Struct {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Union {
 +    pub(crate) id: UnionId,
 +}
 +
 +impl Union {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.union_data(self.id).name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.union_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.union_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Union {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Enum {
 +    pub(crate) id: EnumId,
 +}
 +
 +impl Enum {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.id).name.clone()
 +    }
 +
 +    pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
 +        db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +}
 +
 +impl HasVisibility for Enum {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Variant {
 +    pub(crate) parent: Enum,
 +    pub(crate) id: LocalEnumVariantId,
 +}
 +
 +impl Variant {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent.module(db)
 +    }
 +
 +    pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
 +        self.parent
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.parent.id).variants[self.id].name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        self.variant_data(db)
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
 +    }
 +}
 +
 +/// Variants inherit visibility from the parent enum.
 +impl HasVisibility for Variant {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        self.parent_enum(db).visibility(db)
 +    }
 +}
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adt {
 +    Struct(Struct),
 +    Union(Union),
 +    Enum(Enum),
 +}
 +impl_from!(Struct, Union, Enum for Adt);
 +
 +impl Adt {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    /// Turns this ADT into a type. Any type parameters of the ADT will be
 +    /// turned into unknown types, which is good for e.g. finding the most
 +    /// general set of completions, but will not look very nice when printed.
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let id = AdtId::from(self);
 +        Type::from_def(db, id)
 +    }
 +
 +    /// Turns this ADT into a type with the given type parameters. This isn't
 +    /// the greatest API, FIXME find a better one.
 +    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
 +        let id = AdtId::from(self);
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let ty = TyBuilder::def_ty(db, id.into())
 +            .fill(|x| {
 +                let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        Type::new(db, id, ty)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            Adt::Struct(s) => s.module(db),
 +            Adt::Union(s) => s.module(db),
 +            Adt::Enum(e) => e.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            Adt::Struct(s) => s.name(db),
 +            Adt::Union(u) => u.name(db),
 +            Adt::Enum(e) => e.name(db),
 +        }
 +    }
 +
 +    pub fn as_enum(&self) -> Option<Enum> {
 +        if let Self::Enum(v) = self {
 +            Some(*v)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Adt {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            Adt::Struct(it) => it.visibility(db),
 +            Adt::Union(it) => it.visibility(db),
 +            Adt::Enum(it) => it.visibility(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum VariantDef {
 +    Struct(Struct),
 +    Union(Union),
 +    Variant(Variant),
 +}
 +impl_from!(Struct, Union, Variant for VariantDef);
 +
 +impl VariantDef {
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        match self {
 +            VariantDef::Struct(it) => it.fields(db),
 +            VariantDef::Union(it) => it.fields(db),
 +            VariantDef::Variant(it) => it.fields(db),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            VariantDef::Struct(it) => it.module(db),
 +            VariantDef::Union(it) => it.module(db),
 +            VariantDef::Variant(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            VariantDef::Struct(s) => s.name(db),
 +            VariantDef::Union(u) => u.name(db),
 +            VariantDef::Variant(e) => e.name(db),
 +        }
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantDef::Struct(it) => it.variant_data(db),
 +            VariantDef::Union(it) => it.variant_data(db),
 +            VariantDef::Variant(it) => it.variant_data(db),
 +        }
 +    }
 +}
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBody {
 +    Function(Function),
 +    Static(Static),
 +    Const(Const),
 +}
 +impl_from!(Function, Const, Static for DefWithBody);
 +
 +impl DefWithBody {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            DefWithBody::Const(c) => c.module(db),
 +            DefWithBody::Function(f) => f.module(db),
 +            DefWithBody::Static(s) => s.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            DefWithBody::Function(f) => Some(f.name(db)),
 +            DefWithBody::Static(s) => Some(s.name(db)),
 +            DefWithBody::Const(c) => c.name(db),
 +        }
 +    }
 +
 +    /// Returns the type this def's body has to evaluate to.
 +    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
 +        match self {
 +            DefWithBody::Function(it) => it.ret_type(db),
 +            DefWithBody::Static(it) => it.ty(db),
 +            DefWithBody::Const(it) => it.ty(db),
 +        }
 +    }
 +
 +    fn id(&self) -> DefWithBodyId {
 +        match self {
 +            DefWithBody::Function(it) => it.id.into(),
 +            DefWithBody::Static(it) => it.id.into(),
 +            DefWithBody::Const(it) => it.id.into(),
 +        }
 +    }
 +
 +    /// A textual representation of the HIR of this def's body for debugging purposes.
 +    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
 +        let body = db.body(self.id());
 +        body.pretty_print(db.upcast(), self.id())
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        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()) {
 +            for diag in def_map.diagnostics() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +        }
 +
 +        for diag in source_map.diagnostics() {
 +            match diag {
 +                BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
 +                    InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() }
 +                        .into(),
 +                ),
 +                BodyDiagnostic::MacroError { node, message } => acc.push(
 +                    MacroError {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        message: message.to_string(),
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push(
 +                    UnresolvedProcMacro {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        macro_name: None,
 +                        kind: MacroKind::ProcMacro,
 +                        krate: *krate,
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
 +                    UnresolvedMacroCall {
 +                        macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
 +                        precise_location: None,
 +                        path: path.clone(),
 +                        is_bang: true,
 +                    }
 +                    .into(),
 +                ),
 +            }
 +        }
 +
 +        let infer = db.infer(self.into());
 +        let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
 +        for d in &infer.diagnostics {
 +            match d {
 +                hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
 +                    let field = source_map.field_syntax(*expr);
 +                    acc.push(NoSuchField { field }.into())
 +                }
 +                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
 +                    let expr = source_map
 +                        .expr_syntax(expr)
 +                        .expect("break outside of loop in synthetic syntax");
 +                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
 +                }
 +                hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
 +                    match source_map.expr_syntax(*call_expr) {
 +                        Ok(source_ptr) => acc.push(
 +                            MismatchedArgCount {
 +                                call_expr: source_ptr,
 +                                expected: *expected,
 +                                found: *found,
 +                            }
 +                            .into(),
 +                        ),
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +        for (expr, mismatch) in infer.expr_type_mismatches() {
 +            let expr = match source_map.expr_syntax(expr) {
 +                Ok(expr) => expr,
 +                Err(SyntheticSyntax) => continue,
 +            };
 +            acc.push(
 +                TypeMismatch {
 +                    expr,
 +                    expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()),
 +                    actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
 +            match source_map.expr_syntax(expr) {
 +                Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
 +                Err(SyntheticSyntax) => {
 +                    // FIXME: Here and eslwhere in this file, the `expr` was
 +                    // desugared, report or assert that this doesn't happen.
 +                }
 +            }
 +        }
 +
 +        for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) {
 +            match diagnostic {
 +                BodyValidationDiagnostic::RecordMissingFields {
 +                    record,
 +                    variant,
 +                    missed_fields,
 +                } => {
 +                    let variant_data = variant.variant_data(db.upcast());
 +                    let missed_fields = missed_fields
 +                        .into_iter()
 +                        .map(|idx| variant_data.fields()[idx].name.clone())
 +                        .collect();
 +
 +                    match record {
 +                        Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
 +                            Ok(source_ptr) => {
 +                                let root = source_ptr.file_syntax(db.upcast());
 +                                if let ast::Expr::RecordExpr(record_expr) =
 +                                    &source_ptr.value.to_node(&root)
 +                                {
 +                                    if record_expr.record_expr_field_list().is_some() {
 +                                        acc.push(
 +                                            MissingFields {
 +                                                file: source_ptr.file_id,
 +                                                field_list_parent: Either::Left(AstPtr::new(
 +                                                    record_expr,
 +                                                )),
 +                                                field_list_parent_path: record_expr
 +                                                    .path()
 +                                                    .map(|path| AstPtr::new(&path)),
 +                                                missed_fields,
 +                                            }
 +                                            .into(),
 +                                        )
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                        Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
 +                            Ok(source_ptr) => {
 +                                if let Some(expr) = source_ptr.value.as_ref().left() {
 +                                    let root = source_ptr.file_syntax(db.upcast());
 +                                    if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
 +                                        if record_pat.record_pat_field_list().is_some() {
 +                                            acc.push(
 +                                                MissingFields {
 +                                                    file: source_ptr.file_id,
 +                                                    field_list_parent: Either::Right(AstPtr::new(
 +                                                        &record_pat,
 +                                                    )),
 +                                                    field_list_parent_path: record_pat
 +                                                        .path()
 +                                                        .map(|path| AstPtr::new(&path)),
 +                                                    missed_fields,
 +                                                }
 +                                                .into(),
 +                                            )
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                    }
 +                }
 +                BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
 +                    if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
 +                        acc.push(
 +                            ReplaceFilterMapNextWithFindMap {
 +                                file: next_source_ptr.file_id,
 +                                next_expr: next_source_ptr.value,
 +                            }
 +                            .into(),
 +                        );
 +                    }
 +                }
 +                BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
 +                    match source_map.expr_syntax(match_expr) {
 +                        Ok(source_ptr) => {
 +                            let root = source_ptr.file_syntax(db.upcast());
 +                            if let ast::Expr::MatchExpr(match_expr) =
 +                                &source_ptr.value.to_node(&root)
 +                            {
 +                                if let Some(match_expr) = match_expr.expr() {
 +                                    acc.push(
 +                                        MissingMatchArms {
 +                                            file: source_ptr.file_id,
 +                                            match_expr: AstPtr::new(&match_expr),
 +                                            uncovered_patterns,
 +                                        }
 +                                        .into(),
 +                                    );
 +                                }
 +                            }
 +                        }
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let def: ModuleDef = match self {
 +            DefWithBody::Function(it) => it.into(),
 +            DefWithBody::Static(it) => it.into(),
 +            DefWithBody::Const(it) => it.into(),
 +        };
 +        for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
 +            acc.push(diag.into())
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Function {
 +    pub(crate) id: FunctionId,
 +}
 +
 +impl Function {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).module(db.upcast()).into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.function_data(self.id).name.clone()
 +    }
 +
 +    /// Get this function's return type
 +    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ty = callable_sig.ret().clone();
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
 +        if !self.is_async(db) {
 +            return None;
 +        }
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ret_ty = callable_sig.ret().clone();
 +        for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
 +            if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
 +                return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
 +            }
 +        }
 +        never!("Async fn ret_type should be impl Future");
 +        None
 +    }
 +
 +    pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_self_param()
 +    }
 +
 +    pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        self.has_self_param(db).then(|| SelfParam { func: self.id })
 +    }
 +
 +    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
 +        if self.self_param(db).is_none() {
 +            return None;
 +        }
 +        Some(self.params_without_self(db))
 +    }
 +
 +    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 };
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .skip(skip)
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn is_const(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_const_kw()
 +    }
 +
 +    pub fn is_async(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_async_kw()
 +    }
 +
 +    pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
 +        hir_ty::is_fn_unsafe_to_call(db, self.id)
 +    }
 +
 +    /// Whether this function declaration has a definition.
 +    ///
 +    /// This is false in the case of required (not provided) trait methods.
 +    pub fn has_body(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_body()
 +    }
 +
 +    pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
 +        let function_data = db.function_data(self.id);
 +        let attrs = &function_data.attrs;
 +        // FIXME: Store this in FunctionData flags?
 +        if !(attrs.is_proc_macro()
 +            || attrs.is_proc_macro_attribute()
 +            || attrs.is_proc_macro_derive())
 +        {
 +            return None;
 +        }
 +        let loc = self.id.lookup(db.upcast());
 +        let def_map = db.crate_def_map(loc.krate(db).into());
 +        def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
 +    }
 +}
 +
 +// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum Access {
 +    Shared,
 +    Exclusive,
 +    Owned,
 +}
 +
 +impl From<hir_ty::Mutability> for Access {
 +    fn from(mutability: hir_ty::Mutability) -> Access {
 +        match mutability {
 +            hir_ty::Mutability::Not => Access::Shared,
 +            hir_ty::Mutability::Mut => Access::Exclusive,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug)]
 +pub struct Param {
 +    func: Function,
 +    /// The index in parameter list, including self parameter.
 +    idx: usize,
 +    ty: Type,
 +}
 +
 +impl Param {
 +    pub fn ty(&self) -> &Type {
 +        &self.ty
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.function_data(self.func.id).params[self.idx].0.clone()
 +    }
 +
 +    pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
 +        let parent = DefWithBodyId::FunctionId(self.func.into());
 +        let body = db.body(parent);
 +        let pat_id = body.params[self.idx];
 +        if let Pat::Bind { .. } = &body[pat_id] {
 +            Some(Local { parent, pat_id: body.params[self.idx] })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
 +        self.source(db).and_then(|p| p.value.pat())
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
 +        let InFile { file_id, value } = self.func.source(db)?;
 +        let params = value.param_list()?;
 +        if params.self_param().is_some() {
 +            params.params().nth(self.idx.checked_sub(1)?)
 +        } else {
 +            params.params().nth(self.idx)
 +        }
 +        .map(|value| InFile { file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct SelfParam {
 +    func: FunctionId,
 +}
 +
 +impl SelfParam {
 +    pub fn access(self, db: &dyn HirDatabase) -> Access {
 +        let func_data = db.function_data(self.func);
 +        func_data
 +            .params
 +            .first()
 +            .map(|(_, param)| match &**param {
 +                TypeRef::Reference(.., mutability) => match mutability {
 +                    hir_def::type_ref::Mutability::Shared => Access::Shared,
 +                    hir_def::type_ref::Mutability::Mut => Access::Exclusive,
 +                },
 +                _ => Access::Owned,
 +            })
 +            .unwrap_or(Access::Owned)
 +    }
 +
 +    pub fn display(self, db: &dyn HirDatabase) -> &'static str {
 +        match self.access(db) {
 +            Access::Shared => "&self",
 +            Access::Exclusive => "&mut self",
 +            Access::Owned => "self",
 +        }
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
 +        let InFile { file_id, value } = Function::from(self.func).source(db)?;
 +        value
 +            .param_list()
 +            .and_then(|params| params.self_param())
 +            .map(|value| InFile { file_id, value })
 +    }
 +
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let substs = TyBuilder::placeholder_subst(db, self.func);
 +        let callable_sig =
 +            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
 +        let environment = db.trait_environment(self.func.into());
 +        let ty = callable_sig.params()[0].clone();
 +        Type { env: environment, ty }
 +    }
 +}
 +
 +impl HasVisibility for Function {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.function_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Const {
 +    pub(crate) id: ConstId,
 +}
 +
 +impl Const {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.const_data(self.id).name.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.const_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval(self.id)
 +    }
 +}
 +
 +impl HasVisibility for Const {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.const_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Static {
 +    pub(crate) id: StaticId,
 +}
 +
 +impl Static {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.static_data(self.id).name.clone()
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        db.static_data(self.id).mutable
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.static_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +}
 +
 +impl HasVisibility for Static {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Trait {
 +    pub(crate) id: TraitId,
 +}
 +
 +impl Trait {
 +    pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
 +        db.lang_item(krate.into(), name.to_smol_str())
 +            .and_then(LangItemTarget::as_trait)
 +            .map(Into::into)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.trait_data(self.id).name.clone()
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
 +    }
 +
 +    pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        let traits = all_super_traits(db.upcast(), self.into());
 +        traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
 +    }
 +
 +    pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_auto
 +    }
 +
 +    pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_unsafe
 +    }
 +
 +    pub fn type_or_const_param_count(
 +        &self,
 +        db: &dyn HirDatabase,
 +        count_required_only: bool,
 +    ) -> usize {
 +        db.generic_params(GenericDefId::from(self.id))
 +            .type_or_consts
 +            .iter()
 +            .filter(|(_, ty)| match ty {
 +                TypeOrConstParamData::TypeParamData(ty)
 +                    if ty.provenance != TypeParamProvenance::TypeParamList =>
 +                {
 +                    false
 +                }
 +                _ => true,
 +            })
 +            .filter(|(_, ty)| !count_required_only || !ty.has_default())
 +            .count()
 +    }
 +}
 +
 +impl HasVisibility for Trait {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAlias {
 +    pub(crate) id: TypeAliasId,
 +}
 +
 +impl TypeAlias {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.id.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
 +        db.type_alias_data(self.id).type_ref.as_deref().cloned()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.type_alias_data(self.id).name.clone()
 +    }
 +}
 +
 +impl HasVisibility for TypeAlias {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let function_data = db.type_alias_data(self.id);
 +        let visibility = &function_data.visibility;
 +        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct BuiltinType {
 +    pub(crate) inner: hir_def::builtin_type::BuiltinType,
 +}
 +
 +impl BuiltinType {
 +    pub fn str() -> BuiltinType {
 +        BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
 +    }
 +
 +    pub fn name(self) -> Name {
 +        self.inner.as_name()
 +    }
 +
 +    pub fn is_int(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
 +    }
 +
 +    pub fn is_uint(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
 +    }
 +
 +    pub fn is_float(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
 +    }
 +
 +    pub fn is_char(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Bool)
 +    }
 +
 +    pub fn is_str(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroKind {
 +    /// `macro_rules!` or Macros 2.0 macro.
 +    Declarative,
 +    /// A built-in or custom derive.
 +    Derive,
 +    /// A built-in function-like macro.
 +    BuiltIn,
 +    /// A procedural attribute macro.
 +    Attr,
 +    /// A function-like procedural macro.
 +    ProcMacro,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro {
 +    pub(crate) id: MacroId,
 +}
 +
 +impl Macro {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self.id {
 +            MacroId::Macro2Id(id) => db.macro2_data(id).name.clone(),
 +            MacroId::MacroRulesId(id) => db.macro_rules_data(id).name.clone(),
 +            MacroId::ProcMacroId(id) => db.proc_macro_data(id).name.clone(),
 +        }
 +    }
 +
 +    pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
 +    }
 +
 +    pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
 +        match self.id {
 +            MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::MacroRulesId(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind {
 +                ProcMacroKind::CustomDerive => MacroKind::Derive,
 +                ProcMacroKind::FuncLike => MacroKind::ProcMacro,
 +                ProcMacroKind::Attr => MacroKind::Attr,
 +            },
 +        }
 +    }
 +
 +    pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool {
 +        match self.kind(db) {
 +            MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true,
 +            MacroKind::Attr | MacroKind::Derive => false,
 +        }
 +    }
 +
 +    pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
 +        match self.id {
 +            MacroId::Macro2Id(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::MacroRulesId(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::ProcMacroId(_) => false,
 +        }
 +    }
 +
 +    pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Attr)
 +    }
 +
 +    pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Derive)
 +    }
 +}
 +
 +impl HasVisibility for Macro {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self.id {
 +            MacroId::Macro2Id(id) => {
 +                let data = db.macro2_data(id);
 +                let visibility = &data.visibility;
 +                visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +            }
 +            MacroId::MacroRulesId(_) => Visibility::Public,
 +            MacroId::ProcMacroId(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum ItemInNs {
 +    Types(ModuleDef),
 +    Values(ModuleDef),
 +    Macros(Macro),
 +}
 +
 +impl From<Macro> for ItemInNs {
 +    fn from(it: Macro) -> Self {
 +        Self::Macros(it)
 +    }
 +}
 +
 +impl From<ModuleDef> for ItemInNs {
 +    fn from(module_def: ModuleDef) -> Self {
 +        match module_def {
 +            ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
 +                ItemInNs::Values(module_def)
 +            }
 +            _ => ItemInNs::Types(module_def),
 +        }
 +    }
 +}
 +
 +impl ItemInNs {
 +    pub fn as_module_def(self) -> Option<ModuleDef> {
 +        match self {
 +            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
 +            ItemInNs::Macros(_) => None,
 +        }
 +    }
 +
 +    /// Returns the crate defining this item (or `None` if `self` is built-in).
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate()),
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ItemInNs::Types(it) | ItemInNs::Values(it) => it.attrs(db),
 +            ItemInNs::Macros(it) => Some(it.attrs(db)),
 +        }
 +    }
 +}
 +
 +/// Invariant: `inner.as_assoc_item(db).is_some()`
 +/// We do not actively enforce this invariant.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    Function(Function),
 +    Const(Const),
 +    TypeAlias(TypeAlias),
 +}
 +#[derive(Debug)]
 +pub enum AssocItemContainer {
 +    Trait(Trait),
 +    Impl(Impl),
 +}
 +pub trait AsAssocItem {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
 +}
 +
 +impl AsAssocItem for Function {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Function, self.id)
 +    }
 +}
 +impl AsAssocItem for Const {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Const, self.id)
 +    }
 +}
 +impl AsAssocItem for TypeAlias {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::TypeAlias, self.id)
 +    }
 +}
 +impl AsAssocItem for ModuleDef {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        match self {
 +            ModuleDef::Function(it) => it.as_assoc_item(db),
 +            ModuleDef::Const(it) => it.as_assoc_item(db),
 +            ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
 +            _ => None,
 +        }
 +    }
 +}
 +fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
 +where
 +    ID: Lookup<Data = AssocItemLoc<AST>>,
 +    DEF: From<ID>,
 +    CTOR: FnOnce(DEF) -> AssocItem,
 +    AST: ItemTreeNode,
 +{
 +    match id.lookup(db.upcast()).container {
 +        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
 +        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
 +    }
 +}
 +
 +impl AssocItem {
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            AssocItem::Function(it) => Some(it.name(db)),
 +            AssocItem::Const(it) => it.name(db),
 +            AssocItem::TypeAlias(it) => Some(it.name(db)),
 +        }
 +    }
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            AssocItem::Function(f) => f.module(db),
 +            AssocItem::Const(c) => c.module(db),
 +            AssocItem::TypeAlias(t) => t.module(db),
 +        }
 +    }
 +    pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
 +        let container = match self {
 +            AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
 +        };
 +        match container {
 +            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
 +            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
 +            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
 +                panic!("invalid AssocItem")
 +            }
 +        }
 +    }
 +
 +    pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +        }
 +    }
 +}
 +
 +impl HasVisibility for AssocItem {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            AssocItem::Function(f) => f.visibility(db),
 +            AssocItem::Const(c) => c.visibility(db),
 +            AssocItem::TypeAlias(t) => t.visibility(db),
 +        }
 +    }
 +}
 +
 +impl From<AssocItem> for ModuleDef {
 +    fn from(assoc: AssocItem) -> Self {
 +        match assoc {
 +            AssocItem::Function(it) => ModuleDef::Function(it),
 +            AssocItem::Const(it) => ModuleDef::Const(it),
 +            AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDef {
 +    Function(Function),
 +    Adt(Adt),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    Impl(Impl),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    Variant(Variant),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    Const(Const),
 +}
 +impl_from!(
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Trait,
 +    TypeAlias,
 +    Impl,
 +    Variant,
 +    Const
 +    for GenericDef
 +);
 +
 +impl GenericDef {
 +    pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
 +        let generics = db.generic_params(self.into());
 +        let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
 +            let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
 +            match toc.split(db) {
 +                Either::Left(x) => GenericParam::ConstParam(x),
 +                Either::Right(x) => GenericParam::TypeParam(x),
 +            }
 +        });
 +        let lt_params = generics
 +            .lifetimes
 +            .iter()
 +            .map(|(local_id, _)| LifetimeParam {
 +                id: LifetimeParamId { parent: self.into(), local_id },
 +            })
 +            .map(GenericParam::LifetimeParam);
 +        lt_params.chain(ty_params).collect()
 +    }
 +
 +    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
 +        let generics = db.generic_params(self.into());
 +        generics
 +            .type_or_consts
 +            .iter()
 +            .map(|(local_id, _)| TypeOrConstParam {
 +                id: TypeOrConstParamId { parent: self.into(), local_id },
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// A single local definition.
 +///
 +/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns
 +/// then this only references a single one of those.
 +/// To retrieve the other locals you should use [`Local::associated_locals`]
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Local {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) pat_id: PatId,
 +}
 +
 +impl Local {
 +    pub fn is_param(self, db: &dyn HirDatabase) -> bool {
 +        let src = self.source(db);
 +        match src.value {
 +            Either::Left(pat) => pat
 +                .syntax()
 +                .ancestors()
 +                .map(|it| it.kind())
 +                .take_while(|&kind| ast::Pat::can_cast(kind) || ast::Param::can_cast(kind))
 +                .any(ast::Param::can_cast),
 +            Either::Right(_) => true,
 +        }
 +    }
 +
 +    pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        match self.parent {
 +            DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        match &body[self.pat_id] {
 +            Pat::Bind { name, .. } => name.clone(),
 +            _ => {
 +                stdx::never!("hir::Local is missing a name!");
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn is_self(self, db: &dyn HirDatabase) -> bool {
 +        self.name(db) == name![self]
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. })
 +    }
 +
 +    pub fn is_ref(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(
 +            &body[self.pat_id],
 +            Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. }
 +        )
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let def = self.parent;
 +        let infer = db.infer(def);
 +        let ty = infer[self.pat_id].clone();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> {
 +        let body = db.body(self.parent);
 +        body.ident_patterns_for(&self.pat_id)
 +            .iter()
 +            .map(|&pat_id| Local { parent: self.parent, pat_id })
 +            .collect()
 +    }
 +
 +    /// If this local is part of a multi-local, retrieve the representative local.
 +    /// That is the local that references are being resolved to.
 +    pub fn representative(self, db: &dyn HirDatabase) -> Local {
 +        let body = db.body(self.parent);
 +        Local { pat_id: body.pattern_representative(self.pat_id), ..self }
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| match ast {
 +            // Suspicious unwrap
 +            Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)),
 +            Either::Right(it) => Either::Right(it.to_node(&root)),
 +        })
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct DeriveHelper {
 +    pub(crate) derive: MacroId,
 +    pub(crate) idx: usize,
 +}
 +
 +impl DeriveHelper {
 +    pub fn derive(&self) -> Macro {
 +        Macro { id: self.derive.into() }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self.derive {
 +            MacroId::Macro2Id(_) => None,
 +            MacroId::MacroRulesId(_) => None,
 +            MacroId::ProcMacroId(proc_macro) => db
 +                .proc_macro_data(proc_macro)
 +                .helpers
 +                .as_ref()
 +                .and_then(|it| it.get(self.idx))
 +                .cloned(),
 +        }
 +        .unwrap_or_else(|| Name::missing())
 +    }
 +}
 +
 +// FIXME: Wrong name? This is could also be a registered attribute
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct BuiltinAttr {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl BuiltinAttr {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
 +        Some(BuiltinAttr { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::INERT_ATTRIBUTES
 +            .iter()
 +            .position(|tool| tool.name == name)
 +            .map(|idx| BuiltinAttr { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
 +        }
 +    }
 +
 +    pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
 +        match self.krate {
 +            Some(_) => None,
 +            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ToolModule {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl ToolModule {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
 +        Some(ToolModule { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::TOOL_MODULES
 +            .iter()
 +            .position(|&tool| tool == name)
 +            .map(|idx| ToolModule { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Label {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) label_id: LabelId,
 +}
 +
 +impl Label {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        body[self.label_id].name.clone()
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.label_syntax(self.label_id);
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| ast.to_node(&root))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParam {
 +    TypeParam(TypeParam),
 +    ConstParam(ConstParam),
 +    LifetimeParam(LifetimeParam),
 +}
 +impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
 +
 +impl GenericParam {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            GenericParam::TypeParam(it) => it.module(db),
 +            GenericParam::ConstParam(it) => it.module(db),
 +            GenericParam::LifetimeParam(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            GenericParam::TypeParam(it) => it.name(db),
 +            GenericParam::ConstParam(it) => it.name(db),
 +            GenericParam::LifetimeParam(it) => it.name(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeParam {
 +    pub(crate) id: TypeParamId,
 +}
 +
 +impl TypeParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        self.merge().name(db)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait`
 +    /// argument)?
 +    pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
 +        let params = db.generic_params(self.id.parent());
 +        let data = &params.type_or_consts[self.id.local_id()];
 +        match data.type_param().unwrap().provenance {
 +            hir_def::generics::TypeParamProvenance::TypeParamList => false,
 +            hir_def::generics::TypeParamProvenance::TraitSelf
 +            | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true,
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty =
 +            TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    /// FIXME: this only lists trait bounds from the item defining the type
 +    /// parameter, not additional bounds that might be added e.g. by a method if
 +    /// the parameter comes from an impl!
 +    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
 +        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
 +            .iter()
 +            .filter_map(|pred| match &pred.skip_binders().skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +            .collect()
 +    }
 +
 +    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
 +        let params = db.generic_defaults(self.id.parent());
 +        let local_idx = hir_ty::param_idx(db, self.id.into())?;
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty = params.get(local_idx)?.clone();
 +        let subst = TyBuilder::placeholder_subst(db, self.id.parent());
 +        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
 +        match ty.data(Interner) {
 +            GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct LifetimeParam {
 +    pub(crate) id: LifetimeParamId,
 +}
 +
 +impl LifetimeParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        params.lifetimes[self.id.local_id].name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ConstParam {
 +    pub(crate) id: ConstParamId,
 +}
 +
 +impl ConstParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent());
 +        match params.type_or_consts[self.id.local_id()].name() {
 +            Some(x) => x.clone(),
 +            None => {
 +                never!();
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent().into()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new(db, self.id.parent(), db.const_param_ty(self.id))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParam {
 +    pub(crate) id: TypeOrConstParamId,
 +}
 +
 +impl TypeOrConstParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        match params.type_or_consts[self.id.local_id].name() {
 +            Some(n) => n.clone(),
 +            _ => Name::missing(),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +
 +    pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
 +        let params = db.generic_params(self.id.parent);
 +        match &params.type_or_consts[self.id.local_id] {
 +            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
 +                Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
 +            }
 +            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
 +                Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
 +            }
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        match self.split(db) {
 +            Either::Left(x) => x.ty(db),
 +            Either::Right(x) => x.ty(db),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Impl {
 +    pub(crate) id: ImplId,
 +}
 +
 +impl Impl {
 +    pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
 +        let inherent = db.inherent_impls_in_crate(krate.id);
 +        let trait_ = db.trait_impls_in_crate(krate.id);
 +
 +        inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
 +    }
 +
 +    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
 +        let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
 +            Some(def_crates) => def_crates,
 +            None => return Vec::new(),
 +        };
 +
 +        let filter = |impl_def: &Impl| {
 +            let self_ty = impl_def.self_ty(db);
 +            let rref = self_ty.remove_ref();
 +            ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
 +        };
 +
 +        let fp = TyFingerprint::for_inherent_impl(&ty);
 +        let fp = match fp {
 +            Some(fp) => fp,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut all = Vec::new();
 +        def_crates.iter().for_each(|&id| {
 +            all.extend(
 +                db.inherent_impls_in_crate(id)
 +                    .for_self_ty(&ty)
 +                    .iter()
 +                    .cloned()
 +                    .map(Self::from)
 +                    .filter(filter),
 +            )
 +        });
 +        for id in def_crates
 +            .iter()
 +            .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
 +            .map(|Crate { id }| id)
 +            .chain(def_crates.iter().copied())
 +            .unique()
 +        {
 +            all.extend(
 +                db.trait_impls_in_crate(id)
 +                    .for_self_ty_without_blanket_impls(fp)
 +                    .map(Self::from)
 +                    .filter(filter),
 +            );
 +        }
 +        all
 +    }
 +
 +    pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
 +        let krate = trait_.module(db).krate();
 +        let mut all = Vec::new();
 +        for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter() {
 +            let impls = db.trait_impls_in_crate(id);
 +            all.extend(impls.for_trait(trait_.id).map(Self::from))
 +        }
 +        all
 +    }
 +
 +    // FIXME: the return type is wrong. This should be a hir version of
 +    // `TraitRef` (to account for parameters and qualifiers)
 +    pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
 +        let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
 +        Some(Trait { id })
 +    }
 +
 +    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
 +    }
 +
 +    pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
 +        db.impl_data(self.id).is_negative
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).container.into()
 +    }
 +
 +    pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
 +        let src = self.source(db)?;
 +        src.file_id.is_builtin_derive(db.upcast())
 +    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct Type {
 +    env: Arc<TraitEnvironment>,
 +    ty: Ty,
 +}
 +
 +impl Type {
 +    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
 +        Type::new_with_resolver_inner(db, resolver, ty)
 +    }
 +
 +    pub(crate) fn new_with_resolver_inner(
 +        db: &dyn HirDatabase,
 +        resolver: &Resolver,
 +        ty: Ty,
 +    ) -> Type {
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type {
 +        Type { env: Arc::new(TraitEnvironment::empty(krate)), ty }
 +    }
 +
 +    pub fn reference(inner: &Type, m: Mutability) -> Type {
 +        inner.derived(
 +            TyKind::Ref(
 +                if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
 +                hir_ty::static_lifetime(),
 +                inner.ty.clone(),
 +            )
 +            .intern(Interner),
 +        )
 +    }
 +
 +    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
 +        let resolver = lexical_env.resolver(db.upcast());
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
 +        let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn new_slice(ty: Type) -> Type {
 +        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
 +    }
 +
 +    pub fn is_unit(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
 +    }
 +
 +    pub fn is_never(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Never)
 +    }
 +
 +    pub fn is_mutable_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
 +    }
 +
 +    pub fn is_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(..))
 +    }
 +
 +    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
 +        let (ty, _lt, m) = self.ty.as_reference()?;
 +        let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
 +        Some((self.derived(ty.clone()), m))
 +    }
 +
 +    pub fn is_slice(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Slice(..))
 +    }
 +
 +    pub fn is_usize(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
 +    }
 +
 +    pub fn remove_ref(&self) -> Option<Type> {
 +        match &self.ty.kind(Interner) {
 +            TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn strip_references(&self) -> Type {
 +        self.derived(self.ty.strip_references().clone())
 +    }
 +
 +    pub fn strip_reference(&self) -> Type {
 +        self.derived(self.ty.strip_reference().clone())
 +    }
 +
 +    pub fn is_unknown(&self) -> bool {
 +        self.ty.is_unknown()
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::future::IntoFuture` or
 +    /// `std::future::Future`.
 +    /// This function is used in `.await` syntax completion.
 +    pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
 +        let trait_ = db
 +            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
 +            .and_then(|it| {
 +                let into_future_fn = it.as_function()?;
 +                let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
 +                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
 +                Some(into_future_trait.id)
 +            })
 +            .or_else(|| {
 +                let future_trait =
 +                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
 +                future_trait.as_trait()
 +            });
 +
 +        let trait_ = match trait_ {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::ops::FnOnce`.
 +    ///
 +    /// This function can be used to check if a particular type is callable, since FnOnce is a
 +    /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
 +    pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
 +        let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait_unique(
 +            &canonical_ty,
 +            db,
 +            self.env.clone(),
 +            fnonce_trait,
 +        )
 +    }
 +
 +    pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let trait_ref = TyBuilder::trait_ref(db, trait_.id)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                let r = it.next().unwrap();
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => {
 +                        // FIXME: this code is not covered in tests.
 +                        unknown_const_as_generic(ty.clone())
 +                    }
 +                }
 +            })
 +            .build();
 +
 +        let goal = Canonical {
 +            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
 +            binders: CanonicalVarKinds::empty(Interner),
 +        };
 +
 +        db.trait_solve(self.env.krate, goal).is_some()
 +    }
 +
 +    pub fn normalize_trait_assoc_type(
 +        &self,
 +        db: &dyn HirDatabase,
 +        args: &[Type],
 +        alias: TypeAlias,
 +    ) -> Option<Type> {
 +        let mut args = args.iter();
 +        let projection = TyBuilder::assoc_type_projection(db, alias.id)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                // FIXME: this code is not covered in tests.
 +                match x {
 +                    ParamKind::Type => {
 +                        GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
 +                    }
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
-         match db.trait_solve(self.env.krate, goal)? {
-             Solution::Unique(s) => s
-                 .value
-                 .subst
-                 .as_slice(Interner)
-                 .first()
-                 .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
-             Solution::Ambig(_) => None,
 +
++        let ty = db.normalize_projection(projection, self.env.clone());
++        if ty.is_unknown() {
++            None
++        } else {
++            Some(self.derived(ty))
 +        }
 +    }
 +
 +    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
 +        let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy"));
 +        let copy_trait = match lang_item {
 +            Some(LangItemTarget::TraitId(it)) => it,
 +            _ => return false,
 +        };
 +        self.impls_trait(db, copy_trait.into(), &[])
 +    }
 +
 +    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
 +        let callee = match self.ty.kind(Interner) {
 +            TyKind::Closure(id, _) => Callee::Closure(*id),
 +            TyKind::Function(_) => Callee::FnPtr,
 +            _ => Callee::Def(self.ty.callable_def(db)?),
 +        };
 +
 +        let sig = self.ty.callable_sig(db)?;
 +        Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
 +    }
 +
 +    pub fn is_closure(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
 +    }
 +
 +    pub fn is_fn(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
 +    }
 +
 +    pub fn is_array(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Array(..))
 +    }
 +
 +    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
 +        let adt_id = match *self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
 +            _ => return false,
 +        };
 +
 +        let adt = adt_id.into();
 +        match adt {
 +            Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_raw_ptr(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Raw(..))
 +    }
 +
 +    pub fn contains_unknown(&self) -> bool {
 +        return go(&self.ty);
 +
 +        fn go(ty: &Ty) -> bool {
 +            match ty.kind(Interner) {
 +                TyKind::Error => true,
 +
 +                TyKind::Adt(_, substs)
 +                | TyKind::AssociatedType(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::OpaqueType(_, substs)
 +                | TyKind::FnDef(_, substs)
 +                | TyKind::Closure(_, substs) => {
 +                    substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
 +                }
 +
 +                TyKind::Array(_ty, len) if len.is_unknown() => true,
 +                TyKind::Array(ty, _)
 +                | TyKind::Slice(ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Ref(_, _, ty) => go(ty),
 +
 +                TyKind::Scalar(_)
 +                | TyKind::Str
 +                | TyKind::Never
 +                | TyKind::Placeholder(_)
 +                | TyKind::BoundVar(_)
 +                | TyKind::InferenceVar(_, _)
 +                | TyKind::Dyn(_)
 +                | TyKind::Function(_)
 +                | TyKind::Alias(_)
 +                | TyKind::Foreign(_)
 +                | TyKind::Generator(..)
 +                | TyKind::GeneratorWitness(..) => false,
 +            }
 +        }
 +    }
 +
 +    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
 +        let (variant_id, substs) = match self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
 +            TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
 +            _ => return Vec::new(),
 +        };
 +
 +        db.field_types(variant_id)
 +            .iter()
 +            .map(|(local_id, ty)| {
 +                let def = Field { parent: variant_id.into(), id: local_id };
 +                let ty = ty.clone().substitute(Interner, substs);
 +                (def, self.derived(ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
 +        if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
 +            substs
 +                .iter(Interner)
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
 +                .collect()
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
 +        self.autoderef_(db).map(move |ty| self.derived(ty))
 +    }
 +
 +    fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +        let environment = self.env.clone();
 +        autoderef(db, environment, canonical).map(|canonical| canonical.value)
 +    }
 +
 +    // This would be nicer if it just returned an iterator, but that runs into
 +    // lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +    pub fn iterate_assoc_items<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let mut slot = None;
 +        self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| {
 +            slot = callback(assoc_item_id.into());
 +            slot.is_some()
 +        });
 +        slot
 +    }
 +
 +    fn iterate_assoc_items_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        callback: &mut dyn FnMut(AssocItemId) -> bool,
 +    ) {
 +        let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) {
 +            Some(it) => it,
 +            None => return,
 +        };
 +        for krate in def_crates {
 +            let impls = db.inherent_impls_in_crate(krate);
 +
 +            for impl_def in impls.for_self_ty(&self.ty) {
 +                for &item in db.impl_data(*impl_def).items.iter() {
 +                    if callback(item) {
 +                        return;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
 +        self.ty
 +            .strip_references()
 +            .as_adt()
 +            .into_iter()
 +            .flat_map(|(_, substs)| substs.iter(Interner))
 +            .filter_map(|arg| arg.ty(Interner).cloned())
 +            .map(move |ty| self.derived(ty))
 +    }
 +
 +    pub fn iterate_method_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        // FIXME this can be retrieved from `scope`, except autoimport uses this
 +        // to specify a different set, so the method needs to be split
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(Function) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_method_candidates");
 +        let mut slot = None;
 +
 +        self.iterate_method_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let AssocItemId::FunctionId(func) = assoc_item_id {
 +                    if let Some(res) = callback(func.into()) {
 +                        slot = Some(res);
 +                        return ControlFlow::Break(());
 +                    }
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_method_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_method_candidates_dyn(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            method_resolution::LookupMode::MethodCall,
 +            &mut |_adj, id| callback(id),
 +        );
 +    }
 +
 +    pub fn iterate_path_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_path_candidates");
 +        let mut slot = None;
 +        self.iterate_path_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let Some(res) = callback(assoc_item_id.into()) {
 +                    slot = Some(res);
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_path_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_path_candidates(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            &mut |id| callback(id),
 +        );
 +    }
 +
 +    pub fn as_adt(&self) -> Option<Adt> {
 +        let (adt, _subst) = self.ty.as_adt()?;
 +        Some(adt.into())
 +    }
 +
 +    pub fn as_builtin(&self) -> Option<BuiltinType> {
 +        self.ty.as_builtin().map(|inner| BuiltinType { inner })
 +    }
 +
 +    pub fn as_dyn_trait(&self) -> Option<Trait> {
 +        self.ty.dyn_trait().map(Into::into)
 +    }
 +
 +    /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
 +    /// or an empty iterator otherwise.
 +    pub fn applicable_inherent_traits<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +    ) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("applicable_inherent_traits");
 +        self.autoderef_(db)
 +            .filter_map(|ty| ty.dyn_trait())
 +            .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
 +            .map(Trait::from)
 +    }
 +
 +    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("env_traits");
 +        self.autoderef_(db)
 +            .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
 +            .flat_map(|ty| {
 +                self.env
 +                    .traits_in_scope_from_clauses(ty)
 +                    .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
 +            })
 +            .map(Trait::from)
 +    }
 +
 +    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
 +        self.ty.impl_trait_bounds(db).map(|it| {
 +            it.into_iter().filter_map(|pred| match pred.skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +        })
 +    }
 +
 +    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
 +        self.ty.associated_type_parent_trait(db).map(Into::into)
 +    }
 +
 +    fn derived(&self, ty: Ty) -> Type {
 +        Type { env: self.env.clone(), ty }
 +    }
 +
 +    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
 +        // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
 +        // We need a different order here.
 +
 +        fn walk_substs(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            substs: &Substitution,
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
 +                walk_type(db, &type_.derived(ty.clone()), cb);
 +            }
 +        }
 +
 +        fn walk_bounds(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            bounds: &[QuantifiedWhereClause],
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for pred in bounds {
 +                if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
 +                    cb(type_.clone());
 +                    // skip the self type. it's likely the type we just got the bounds from
 +                    for ty in
 +                        trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
 +                    {
 +                        walk_type(db, &type_.derived(ty.clone()), cb);
 +                    }
 +                }
 +            }
 +        }
 +
 +        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
 +            let ty = type_.ty.strip_references();
 +            match ty.kind(Interner) {
 +                TyKind::Adt(_, substs) => {
 +                    cb(type_.derived(ty.clone()));
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::AssociatedType(_, substs) => {
 +                    if ty.associated_type_parent_trait(db).is_some() {
 +                        cb(type_.derived(ty.clone()));
 +                    }
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::OpaqueType(_, subst) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, subst, cb);
 +                }
 +                TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, &opaque_ty.substitution, cb);
 +                }
 +                TyKind::Placeholder(_) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +                }
 +                TyKind::Dyn(bounds) => {
 +                    walk_bounds(
 +                        db,
 +                        &type_.derived(ty.clone()),
 +                        bounds.bounds.skip_binders().interned(),
 +                        cb,
 +                    );
 +                }
 +
 +                TyKind::Ref(_, _, ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Array(ty, _)
 +                | TyKind::Slice(ty) => {
 +                    walk_type(db, &type_.derived(ty.clone()), cb);
 +                }
 +
 +                TyKind::FnDef(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::Closure(.., substs) => {
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
 +                    walk_substs(db, type_, &substitution.0, cb);
 +                }
 +
 +                _ => {}
 +            }
 +        }
 +
 +        walk_type(db, self, &mut cb);
 +    }
 +
 +    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
 +        hir_ty::could_unify(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
 +        hir_ty::could_coerce(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
 +        match self.ty.kind(Interner) {
 +            TyKind::Placeholder(p) => Some(TypeParam {
 +                id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Callable {
 +    ty: Type,
 +    sig: CallableSig,
 +    callee: Callee,
 +    pub(crate) is_bound_method: bool,
 +}
 +
 +#[derive(Debug)]
 +enum Callee {
 +    Def(CallableDefId),
 +    Closure(ClosureId),
 +    FnPtr,
 +}
 +
 +pub enum CallableKind {
 +    Function(Function),
 +    TupleStruct(Struct),
 +    TupleEnumVariant(Variant),
 +    Closure,
 +    FnPtr,
 +}
 +
 +impl Callable {
 +    pub fn kind(&self) -> CallableKind {
 +        use Callee::*;
 +        match self.callee {
 +            Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
 +            Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
 +            Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
 +            Closure(_) => CallableKind::Closure,
 +            FnPtr => CallableKind::FnPtr,
 +        }
 +    }
 +    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
 +        let func = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
 +            _ => return None,
 +        };
 +        let src = func.lookup(db.upcast()).source(db.upcast());
 +        let param_list = src.value.param_list()?;
 +        param_list.self_param()
 +    }
 +    pub fn n_params(&self) -> usize {
 +        self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
 +    }
 +    pub fn params(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
 +        let types = self
 +            .sig
 +            .params()
 +            .iter()
 +            .skip(if self.is_bound_method { 1 } else { 0 })
 +            .map(|ty| self.ty.derived(ty.clone()));
 +        let map_param = |it: ast::Param| it.pat().map(Either::Right);
 +        let patterns = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(func)) => {
 +                let src = func.lookup(db.upcast()).source(db.upcast());
 +                src.value.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                })
 +            }
 +            Callee::Closure(closure_id) => match closure_source(db, closure_id) {
 +                Some(src) => src.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                }),
 +                None => None,
 +            },
 +            _ => None,
 +        };
 +        patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
 +    }
 +    pub fn return_type(&self) -> Type {
 +        self.ty.derived(self.sig.ret().clone())
 +    }
 +}
 +
 +fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
 +    let (owner, expr_id) = db.lookup_intern_closure(closure.into());
 +    let (_, source_map) = db.body_with_source_map(owner);
 +    let ast = source_map.expr_syntax(expr_id).ok()?;
 +    let root = ast.file_syntax(db.upcast());
 +    let expr = ast.value.to_node(&root);
 +    match expr {
 +        ast::Expr::ClosureExpr(it) => Some(it),
 +        _ => None,
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +/// For IDE only
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDef),
 +    GenericParam(GenericParam),
 +    ImplSelfType(Impl),
 +    AdtSelfType(Adt),
 +    Local(Local),
 +    Label(Label),
 +    Unknown,
 +}
 +
 +impl ScopeDef {
 +    pub fn all_items(def: PerNs) -> ArrayVec<Self, 3> {
 +        let mut items = ArrayVec::new();
 +
 +        match (def.take_types(), def.take_values()) {
 +            (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
 +            (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
 +            (Some(m1), Some(m2)) => {
 +                // Some items, like unit structs and enum variants, are
 +                // returned as both a type and a value. Here we want
 +                // to de-duplicate them.
 +                if m1 != m2 {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                    items.push(ScopeDef::ModuleDef(m2.into()));
 +                } else {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                }
 +            }
 +            (None, None) => {}
 +        };
 +
 +        if let Some(macro_def_id) = def.take_macros() {
 +            items.push(ScopeDef::ModuleDef(ModuleDef::Macro(macro_def_id.into())));
 +        }
 +
 +        if items.is_empty() {
 +            items.push(ScopeDef::Unknown);
 +        }
 +
 +        items
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.attrs(db),
 +            ScopeDef::GenericParam(it) => Some(it.attrs(db)),
 +            ScopeDef::ImplSelfType(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => None,
 +        }
 +    }
 +
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()),
 +            ScopeDef::GenericParam(it) => Some(it.module(db).krate()),
 +            ScopeDef::ImplSelfType(_) => None,
 +            ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()),
 +            ScopeDef::Local(it) => Some(it.module(db).krate()),
 +            ScopeDef::Label(it) => Some(it.module(db).krate()),
 +            ScopeDef::Unknown => None,
 +        }
 +    }
 +}
 +
 +impl From<ItemInNs> for ScopeDef {
 +    fn from(item: ItemInNs) -> Self {
 +        match item {
 +            ItemInNs::Types(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Values(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)),
 +        }
 +    }
 +}
 +
 +pub trait HasVisibility {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
 +    fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
 +        let vis = self.visibility(db);
 +        vis.is_visible_from(db.upcast(), module.id)
 +    }
 +}
 +
 +/// Trait for obtaining the defining crate of an item.
 +pub trait HasCrate {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate;
 +}
 +
 +impl<T: hir_def::HasModule> HasCrate for T {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db.upcast()).krate().into()
 +    }
 +}
 +
 +impl HasCrate for AssocItem {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Struct {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Union {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Field {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.parent_def(db).module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Variant {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Function {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Const {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for TypeAlias {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Type {
 +    fn krate(&self, _db: &dyn HirDatabase) -> Crate {
 +        self.env.krate.into()
 +    }
 +}
 +
 +impl HasCrate for Macro {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Trait {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Static {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Adt {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Module {
 +    fn krate(&self, _: &dyn HirDatabase) -> Crate {
 +        Module::krate(*self)
 +    }
 +}
index d4d148c774578f13996383cde831f3002d60103b,0000000000000000000000000000000000000000..60d1588a44e54dba41e753f2511ffd879ac64f73
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,17 @@@
 +//! Settings for tweaking assists.
 +//!
 +//! The fun thing here is `SnippetCap` -- this type can only be created in this
 +//! module, and we use to statically check that we only produce snippet
 +//! assists if we are allowed to.
 +
 +use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
 +
 +use crate::AssistKind;
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct AssistConfig {
 +    pub snippet_cap: Option<SnippetCap>,
 +    pub allowed: Option<Vec<AssistKind>>,
 +    pub insert_use: InsertUseConfig,
++    pub prefer_no_std: bool,
 +}
index 1a7919a5a104d64ca22c3e6b09392ea5670587be,0000000000000000000000000000000000000000..73f4db4e5ff2ba065a20ee39c7aa368ff91f754e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1710 -1,0 +1,1717 @@@
-                     build_pat(ctx.db(), module, variant)?,
 +use std::iter::{self, Peekable};
 +
 +use either::Either;
 +use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
 +use ide_db::RootDatabase;
 +use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 +use itertools::Itertools;
 +use syntax::ast::edit_in_place::Removable;
 +use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
 +
 +use crate::{
 +    utils::{self, render_snippet, Cursor},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: add_missing_match_arms
 +//
 +// Adds missing clauses to a `match` expression.
 +//
 +// ```
 +// enum Action { Move { distance: u32 }, Stop }
 +//
 +// fn handle(action: Action) {
 +//     match action {
 +//         $0
 +//     }
 +// }
 +// ```
 +// ->
 +// ```
 +// enum Action { Move { distance: u32 }, Stop }
 +//
 +// fn handle(action: Action) {
 +//     match action {
 +//         $0Action::Move { distance } => todo!(),
 +//         Action::Stop => todo!(),
 +//     }
 +// }
 +// ```
 +pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?;
 +    let match_arm_list = match_expr.match_arm_list()?;
 +    let target_range = ctx.sema.original_range(match_expr.syntax()).range;
 +
 +    if let None = cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list) {
 +        let arm_list_range = ctx.sema.original_range(match_arm_list.syntax()).range;
 +        let cursor_in_range = arm_list_range.contains_range(ctx.selection_trimmed());
 +        if cursor_in_range {
 +            cov_mark::hit!(not_applicable_outside_of_range_right);
 +            return None;
 +        }
 +    }
 +
 +    let expr = match_expr.expr()?;
 +
 +    let mut has_catch_all_arm = false;
 +
 +    let top_lvl_pats: Vec<_> = match_arm_list
 +        .arms()
 +        .filter_map(|arm| Some((arm.pat()?, arm.guard().is_some())))
 +        .flat_map(|(pat, has_guard)| {
 +            match pat {
 +                // Special case OrPat as separate top-level pats
 +                Pat::OrPat(or_pat) => Either::Left(or_pat.pats()),
 +                _ => Either::Right(iter::once(pat)),
 +            }
 +            .map(move |pat| (pat, has_guard))
 +        })
 +        .map(|(pat, has_guard)| {
 +            has_catch_all_arm |= !has_guard && matches!(pat, Pat::WildcardPat(_));
 +            pat
 +        })
 +        // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
 +        .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
 +        .collect();
 +
 +    let module = ctx.sema.scope(expr.syntax())?.module();
 +    let (mut missing_pats, is_non_exhaustive): (
 +        Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
 +        bool,
 +    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
 +        let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
 +
 +        let variants = enum_def.variants(ctx.db());
 +
 +        let missing_pats = variants
 +            .into_iter()
 +            .filter_map(|variant| {
 +                Some((
-                 let patterns =
-                     variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
++                    build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)?,
 +                    variant.should_be_hidden(ctx.db(), module.krate()),
 +                ))
 +            })
 +            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 +
 +        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option().map(lift_enum);
 +        let missing_pats: Box<dyn Iterator<Item = _>> = if Some(enum_def) == option_enum {
 +            // Match `Some` variant first.
 +            cov_mark::hit!(option_order);
 +            Box::new(missing_pats.rev())
 +        } else {
 +            Box::new(missing_pats)
 +        };
 +        (missing_pats.peekable(), is_non_exhaustive)
 +    } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
 +        let is_non_exhaustive =
 +            enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate()));
 +
 +        let mut n_arms = 1;
 +        let variants_of_enums: Vec<Vec<ExtendedVariant>> = enum_defs
 +            .into_iter()
 +            .map(|enum_def| enum_def.variants(ctx.db()))
 +            .inspect(|variants| n_arms *= variants.len())
 +            .collect();
 +
 +        // When calculating the match arms for a tuple of enums, we want
 +        // to create a match arm for each possible combination of enum
 +        // values. The `multi_cartesian_product` method transforms
 +        // Vec<Vec<EnumVariant>> into Vec<(EnumVariant, .., EnumVariant)>
 +        // where each tuple represents a proposed match arm.
 +
 +        // A number of arms grows very fast on even a small tuple of large enums.
 +        // We skip the assist beyond an arbitrary threshold.
 +        if n_arms > 256 {
 +            return None;
 +        }
 +        let missing_pats = variants_of_enums
 +            .into_iter()
 +            .multi_cartesian_product()
 +            .inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
 +            .map(|variants| {
 +                let is_hidden = variants
 +                    .iter()
 +                    .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
- fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option<ast::Pat> {
++                let patterns = variants.into_iter().filter_map(|variant| {
++                    build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)
++                });
 +
 +                (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
 +            })
 +            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 +        ((Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(), is_non_exhaustive)
 +    } else {
 +        return None;
 +    };
 +
 +    let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm;
 +
 +    if !needs_catch_all_arm && missing_pats.peek().is_none() {
 +        return None;
 +    }
 +
 +    acc.add(
 +        AssistId("add_missing_match_arms", AssistKind::QuickFix),
 +        "Fill match arms",
 +        target_range,
 +        |builder| {
 +            let new_match_arm_list = match_arm_list.clone_for_update();
 +            let missing_arms = missing_pats
 +                .map(|(pat, hidden)| {
 +                    (make::match_arm(iter::once(pat), None, make::ext::expr_todo()), hidden)
 +                })
 +                .map(|(it, hidden)| (it.clone_for_update(), hidden));
 +
 +            let catch_all_arm = new_match_arm_list
 +                .arms()
 +                .find(|arm| matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))));
 +            if let Some(arm) = catch_all_arm {
 +                let is_empty_expr = arm.expr().map_or(true, |e| match e {
 +                    ast::Expr::BlockExpr(b) => {
 +                        b.statements().next().is_none() && b.tail_expr().is_none()
 +                    }
 +                    ast::Expr::TupleExpr(t) => t.fields().next().is_none(),
 +                    _ => false,
 +                });
 +                if is_empty_expr {
 +                    arm.remove();
 +                } else {
 +                    cov_mark::hit!(add_missing_match_arms_empty_expr);
 +                }
 +            }
 +            let mut first_new_arm = None;
 +            for (arm, hidden) in missing_arms {
 +                if hidden {
 +                    needs_catch_all_arm = !has_catch_all_arm;
 +                } else {
 +                    first_new_arm.get_or_insert_with(|| arm.clone());
 +                    new_match_arm_list.add_arm(arm);
 +                }
 +            }
 +            if needs_catch_all_arm && !has_catch_all_arm {
 +                cov_mark::hit!(added_wildcard_pattern);
 +                let arm = make::match_arm(
 +                    iter::once(make::wildcard_pat().into()),
 +                    None,
 +                    make::ext::expr_todo(),
 +                )
 +                .clone_for_update();
 +                first_new_arm.get_or_insert_with(|| arm.clone());
 +                new_match_arm_list.add_arm(arm);
 +            }
 +
 +            let old_range = ctx.sema.original_range(match_arm_list.syntax()).range;
 +            match (first_new_arm, ctx.config.snippet_cap) {
 +                (Some(first_new_arm), Some(cap)) => {
 +                    let extend_lifetime;
 +                    let cursor =
 +                        match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast)
 +                        {
 +                            Some(it) => {
 +                                extend_lifetime = it.syntax().clone();
 +                                Cursor::Replace(&extend_lifetime)
 +                            }
 +                            None => Cursor::Before(first_new_arm.syntax()),
 +                        };
 +                    let snippet = render_snippet(cap, new_match_arm_list.syntax(), cursor);
 +                    builder.replace_snippet(cap, old_range, snippet);
 +                }
 +                _ => builder.replace(old_range, new_match_arm_list.to_string()),
 +            }
 +        },
 +    )
 +}
 +
 +fn cursor_at_trivial_match_arm_list(
 +    ctx: &AssistContext<'_>,
 +    match_expr: &MatchExpr,
 +    match_arm_list: &MatchArmList,
 +) -> Option<()> {
 +    // match x { $0 }
 +    if match_arm_list.arms().next() == None {
 +        cov_mark::hit!(add_missing_match_arms_empty_body);
 +        return Some(());
 +    }
 +
 +    // match x {
 +    //     bar => baz,
 +    //     $0
 +    // }
 +    if let Some(last_arm) = match_arm_list.arms().last() {
 +        let last_arm_range = last_arm.syntax().text_range();
 +        let match_expr_range = match_expr.syntax().text_range();
 +        if last_arm_range.end() <= ctx.offset() && ctx.offset() < match_expr_range.end() {
 +            cov_mark::hit!(add_missing_match_arms_end_of_last_arm);
 +            return Some(());
 +        }
 +    }
 +
 +    // match { _$0 => {...} }
 +    let wild_pat = ctx.find_node_at_offset_with_descend::<ast::WildcardPat>()?;
 +    let arm = wild_pat.syntax().parent().and_then(ast::MatchArm::cast)?;
 +    let arm_match_expr = arm.syntax().ancestors().nth(2).and_then(ast::MatchExpr::cast)?;
 +    if arm_match_expr == *match_expr {
 +        cov_mark::hit!(add_missing_match_arms_trivial_arm);
 +        return Some(());
 +    }
 +
 +    None
 +}
 +
 +fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool {
 +    !existing_pats.iter().any(|pat| does_pat_match_variant(pat, var))
 +}
 +
 +// Fixme: this is still somewhat limited, use hir_ty::diagnostics::match_check?
 +fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
 +    match (pat, var) {
 +        (Pat::WildcardPat(_), _) => true,
 +        (Pat::TuplePat(tpat), Pat::TuplePat(tvar)) => {
 +            tpat.fields().zip(tvar.fields()).all(|(p, v)| does_pat_match_variant(&p, &v))
 +        }
 +        _ => utils::does_pat_match_variant(pat, var),
 +    }
 +}
 +
 +#[derive(Eq, PartialEq, Clone, Copy)]
 +enum ExtendedEnum {
 +    Bool,
 +    Enum(hir::Enum),
 +}
 +
 +#[derive(Eq, PartialEq, Clone, Copy)]
 +enum ExtendedVariant {
 +    True,
 +    False,
 +    Variant(hir::Variant),
 +}
 +
 +impl ExtendedVariant {
 +    fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool {
 +        match self {
 +            ExtendedVariant::Variant(var) => {
 +                var.attrs(db).has_doc_hidden() && var.module(db).krate() != krate
 +            }
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn lift_enum(e: hir::Enum) -> ExtendedEnum {
 +    ExtendedEnum::Enum(e)
 +}
 +
 +impl ExtendedEnum {
 +    fn is_non_exhaustive(self, db: &RootDatabase, krate: Crate) -> bool {
 +        match self {
 +            ExtendedEnum::Enum(e) => {
 +                e.attrs(db).by_key("non_exhaustive").exists() && e.module(db).krate() != krate
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> {
 +        match self {
 +            ExtendedEnum::Enum(e) => {
 +                e.variants(db).into_iter().map(ExtendedVariant::Variant).collect::<Vec<_>>()
 +            }
 +            ExtendedEnum::Bool => {
 +                Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False])
 +            }
 +        }
 +    }
 +}
 +
 +fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> {
 +    sema.type_of_expr(expr)?.adjusted().autoderef(sema.db).find_map(|ty| match ty.as_adt() {
 +        Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)),
 +        _ => ty.is_bool().then(|| ExtendedEnum::Bool),
 +    })
 +}
 +
 +fn resolve_tuple_of_enum_def(
 +    sema: &Semantics<'_, RootDatabase>,
 +    expr: &ast::Expr,
 +) -> Option<Vec<ExtendedEnum>> {
 +    sema.type_of_expr(expr)?
 +        .adjusted()
 +        .tuple_fields(sema.db)
 +        .iter()
 +        .map(|ty| {
 +            ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
 +                Some(Adt::Enum(e)) => Some(lift_enum(e)),
 +                // For now we only handle expansion for a tuple of enums. Here
 +                // we map non-enum items to None and rely on `collect` to
 +                // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>.
 +                _ => ty.is_bool().then(|| ExtendedEnum::Bool),
 +            })
 +        })
 +        .collect()
 +}
 +
-             let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
++fn build_pat(
++    db: &RootDatabase,
++    module: hir::Module,
++    var: ExtendedVariant,
++    prefer_no_std: bool,
++) -> Option<ast::Pat> {
 +    match var {
 +        ExtendedVariant::Variant(var) => {
++            let path =
++                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_no_std)?);
 +
 +            // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
 +            let pat: ast::Pat = match var.source(db)?.value.kind() {
 +                ast::StructKind::Tuple(field_list) => {
 +                    let pats =
 +                        iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
 +                    make::tuple_struct_pat(path, pats).into()
 +                }
 +                ast::StructKind::Record(field_list) => {
 +                    let pats = field_list
 +                        .fields()
 +                        .map(|f| make::ext::simple_ident_pat(f.name().unwrap()).into());
 +                    make::record_pat(path, pats).into()
 +                }
 +                ast::StructKind::Unit => make::path_pat(path),
 +            };
 +
 +            Some(pat)
 +        }
 +        ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
 +        ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{
 +        check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved,
 +    };
 +
 +    use super::add_missing_match_arms;
 +
 +    #[test]
 +    fn all_match_arms_provided() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +enum A {
 +    As,
 +    Bs{x:i32, y:Option<i32>},
 +    Cs(i32, Option<i32>),
 +}
 +fn main() {
 +    match A::As$0 {
 +        A::As,
 +        A::Bs{x,y:Some(_)} => {}
 +        A::Cs(_, Some(_)) => {}
 +    }
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_outside_of_range_left() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +enum A { X, Y }
 +
 +fn foo(a: A) {
 +    $0 match a {
 +        A::X => { }
 +    }
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_outside_of_range_right() {
 +        cov_mark::check!(not_applicable_outside_of_range_right);
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +enum A { X, Y }
 +
 +fn foo(a: A) {
 +    match a {$0
 +        A::X => { }
 +    }
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn all_boolean_match_arms_provided() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match a$0 {
 +        true => {}
 +        false => {}
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn tuple_of_non_enum() {
 +        // for now this case is not handled, although it potentially could be
 +        // in the future
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +fn main() {
 +    match (0, false)$0 {
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_boolean() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match a$0 {
 +    }
 +}
 +"#,
 +            r#"
 +fn foo(a: bool) {
 +    match a {
 +        $0true => todo!(),
 +        false => todo!(),
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn partial_fill_boolean() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match a$0 {
 +        true => {}
 +    }
 +}
 +"#,
 +            r#"
 +fn foo(a: bool) {
 +    match a {
 +        true => {}
 +        $0false => todo!(),
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn all_boolean_tuple_arms_provided() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match (a, a)$0 {
 +        (true, true) => {}
 +        (true, false) => {}
 +        (false, true) => {}
 +        (false, false) => {}
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn fill_boolean_tuple() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match (a, a)$0 {
 +    }
 +}
 +"#,
 +            r#"
 +fn foo(a: bool) {
 +    match (a, a) {
 +        $0(true, true) => todo!(),
 +        (true, false) => todo!(),
 +        (false, true) => todo!(),
 +        (false, false) => todo!(),
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn partial_fill_boolean_tuple() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(a: bool) {
 +    match (a, a)$0 {
 +        (false, true) => {}
 +    }
 +}
 +"#,
 +            r#"
 +fn foo(a: bool) {
 +    match (a, a) {
 +        (false, true) => {}
 +        $0(true, true) => todo!(),
 +        (true, false) => todo!(),
 +        (false, false) => todo!(),
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn partial_fill_record_tuple() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A {
 +    As,
 +    Bs { x: i32, y: Option<i32> },
 +    Cs(i32, Option<i32>),
 +}
 +fn main() {
 +    match A::As$0 {
 +        A::Bs { x, y: Some(_) } => {}
 +        A::Cs(_, Some(_)) => {}
 +    }
 +}
 +"#,
 +            r#"
 +enum A {
 +    As,
 +    Bs { x: i32, y: Option<i32> },
 +    Cs(i32, Option<i32>),
 +}
 +fn main() {
 +    match A::As {
 +        A::Bs { x, y: Some(_) } => {}
 +        A::Cs(_, Some(_)) => {}
 +        $0A::As => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn partial_fill_option() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- minicore: option
 +fn main() {
 +    match None$0 {
 +        None => {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    match None {
 +        None => {}
 +        Some(${0:_}) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn partial_fill_or_pat() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { As, Bs, Cs(Option<i32>) }
 +fn main() {
 +    match A::As$0 {
 +        A::Cs(_) | A::Bs => {}
 +    }
 +}
 +"#,
 +            r#"
 +enum A { As, Bs, Cs(Option<i32>) }
 +fn main() {
 +    match A::As {
 +        A::Cs(_) | A::Bs => {}
 +        $0A::As => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn partial_fill() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { As, Bs, Cs, Ds(String), Es(B) }
 +enum B { Xs, Ys }
 +fn main() {
 +    match A::As$0 {
 +        A::Bs if 0 < 1 => {}
 +        A::Ds(_value) => { let x = 1; }
 +        A::Es(B::Xs) => (),
 +    }
 +}
 +"#,
 +            r#"
 +enum A { As, Bs, Cs, Ds(String), Es(B) }
 +enum B { Xs, Ys }
 +fn main() {
 +    match A::As {
 +        A::Bs if 0 < 1 => {}
 +        A::Ds(_value) => { let x = 1; }
 +        A::Es(B::Xs) => (),
 +        $0A::As => todo!(),
 +        A::Cs => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn partial_fill_bind_pat() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { As, Bs, Cs(Option<i32>) }
 +fn main() {
 +    match A::As$0 {
 +        A::As(_) => {}
 +        a @ A::Bs(_) => {}
 +    }
 +}
 +"#,
 +            r#"
 +enum A { As, Bs, Cs(Option<i32>) }
 +fn main() {
 +    match A::As {
 +        A::As(_) => {}
 +        a @ A::Bs(_) => {}
 +        A::Cs(${0:_}) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_empty_body() {
 +        cov_mark::check!(add_missing_match_arms_empty_body);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
 +
 +fn main() {
 +    let a = A::As;
 +    match a {$0}
 +}
 +"#,
 +            r#"
 +enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
 +
 +fn main() {
 +    let a = A::As;
 +    match a {
 +        $0A::As => todo!(),
 +        A::Bs => todo!(),
 +        A::Cs(_) => todo!(),
 +        A::Ds(_, _) => todo!(),
 +        A::Es { x, y } => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_end_of_last_arm() {
 +        cov_mark::check!(add_missing_match_arms_end_of_last_arm);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a, b) {
 +        (A::Two, B::One) => {},$0
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a, b) {
 +        (A::Two, B::One) => {},
 +        $0(A::One, B::One) => todo!(),
 +        (A::One, B::Two) => todo!(),
 +        (A::Two, B::Two) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_tuple_of_enum() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a$0, b) {}
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a, b) {
 +        $0(A::One, B::One) => todo!(),
 +        (A::One, B::Two) => todo!(),
 +        (A::Two, B::One) => todo!(),
 +        (A::Two, B::Two) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_tuple_of_enum_ref() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (&a$0, &b) {}
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (&a, &b) {
 +        $0(A::One, B::One) => todo!(),
 +        (A::One, B::Two) => todo!(),
 +        (A::Two, B::One) => todo!(),
 +        (A::Two, B::Two) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_tuple_of_enum_partial() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a$0, b) {
 +        (A::Two, B::One) => {}
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a, b) {
 +        (A::Two, B::One) => {}
 +        $0(A::One, B::One) => todo!(),
 +        (A::One, B::Two) => todo!(),
 +        (A::Two, B::Two) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_tuple_of_enum_partial_with_wildcards() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- minicore: option
 +fn main() {
 +    let a = Some(1);
 +    let b = Some(());
 +    match (a$0, b) {
 +        (Some(_), _) => {}
 +        (None, Some(_)) => {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let a = Some(1);
 +    let b = Some(());
 +    match (a, b) {
 +        (Some(_), _) => {}
 +        (None, Some(_)) => {}
 +        $0(None, None) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_partial_with_deep_pattern() {
 +        // Fixme: cannot handle deep patterns
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +//- minicore: option
 +fn main() {
 +    match $0Some(true) {
 +        Some(true) => {}
 +        None => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_tuple_of_enum_not_applicable() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +enum B { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    let b = B::One;
 +    match (a$0, b) {
 +        (A::Two, B::One) => {}
 +        (A::One, B::One) => {}
 +        (A::One, B::Two) => {}
 +        (A::Two, B::Two) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_single_element_tuple_of_enum() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    match (a$0, ) {
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +
 +fn main() {
 +    let a = A::One;
 +    match (a, ) {
 +        $0(A::One,) => todo!(),
 +        (A::Two,) => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_match_arm_refs() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { As }
 +
 +fn foo(a: &A) {
 +    match a$0 {
 +    }
 +}
 +"#,
 +            r#"
 +enum A { As }
 +
 +fn foo(a: &A) {
 +    match a {
 +        $0A::As => todo!(),
 +    }
 +}
 +"#,
 +        );
 +
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A {
 +    Es { x: usize, y: usize }
 +}
 +
 +fn foo(a: &mut A) {
 +    match a$0 {
 +    }
 +}
 +"#,
 +            r#"
 +enum A {
 +    Es { x: usize, y: usize }
 +}
 +
 +fn foo(a: &mut A) {
 +    match a {
 +        $0A::Es { x, y } => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_target_simple() {
 +        check_assist_target(
 +            add_missing_match_arms,
 +            r#"
 +enum E { X, Y }
 +
 +fn main() {
 +    match E::X$0 {}
 +}
 +"#,
 +            "match E::X {}",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_target_complex() {
 +        check_assist_target(
 +            add_missing_match_arms,
 +            r#"
 +enum E { X, Y }
 +
 +fn main() {
 +    match E::X$0 {
 +        E::X => {}
 +    }
 +}
 +"#,
 +            "match E::X {
 +        E::X => {}
 +    }",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_trivial_arm() {
 +        cov_mark::check!(add_missing_match_arms_trivial_arm);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum E { X, Y }
 +
 +fn main() {
 +    match E::X {
 +        $0_ => {}
 +    }
 +}
 +"#,
 +            r#"
 +enum E { X, Y }
 +
 +fn main() {
 +    match E::X {
 +        $0E::X => todo!(),
 +        E::Y => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn wildcard_inside_expression_not_applicable() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +enum E { X, Y }
 +
 +fn foo(e : E) {
 +    match e {
 +        _ => {
 +            println!("1");$0
 +            println!("2");
 +        }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_qualifies_path() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +mod foo { pub enum E { X, Y } }
 +use foo::E::X;
 +
 +fn main() {
 +    match X {
 +        $0
 +    }
 +}
 +"#,
 +            r#"
 +mod foo { pub enum E { X, Y } }
 +use foo::E::X;
 +
 +fn main() {
 +    match X {
 +        $0X => todo!(),
 +        foo::E::Y => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_preserves_comments() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +fn foo(a: A) {
 +    match a $0 {
 +        // foo bar baz
 +        A::One => {}
 +        // This is where the rest should be
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +fn foo(a: A) {
 +    match a  {
 +        // foo bar baz
 +        A::One => {}
 +        $0A::Two => todo!(),
 +        // This is where the rest should be
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_preserves_comments_empty() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two }
 +fn foo(a: A) {
 +    match a {
 +        // foo bar baz$0
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two }
 +fn foo(a: A) {
 +    match a {
 +        $0A::One => todo!(),
 +        A::Two => todo!(),
 +        // foo bar baz
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_missing_match_arms_placeholder() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two, }
 +fn foo(a: A) {
 +    match a$0 {
 +        _ => (),
 +    }
 +}
 +"#,
 +            r#"
 +enum A { One, Two, }
 +fn foo(a: A) {
 +    match a {
 +        $0A::One => todo!(),
 +        A::Two => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn option_order() {
 +        cov_mark::check!(option_order);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- minicore: option
 +fn foo(opt: Option<i32>) {
 +    match opt$0 {
 +    }
 +}
 +"#,
 +            r#"
 +fn foo(opt: Option<i32>) {
 +    match opt {
 +        Some(${0:_}) => todo!(),
 +        None => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_inside_macro_call() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +macro_rules! m { ($expr:expr) => {$expr}}
 +enum Test {
 +    A,
 +    B,
 +    C,
 +}
 +
 +fn foo(t: Test) {
 +    m!(match t$0 {});
 +}"#,
 +            r#"
 +macro_rules! m { ($expr:expr) => {$expr}}
 +enum Test {
 +    A,
 +    B,
 +    C,
 +}
 +
 +fn foo(t: Test) {
 +    m!(match t {
 +    $0Test::A => todo!(),
 +    Test::B => todo!(),
 +    Test::C => todo!(),
 +});
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn lazy_computation() {
 +        // Computing a single missing arm is enough to determine applicability of the assist.
 +        cov_mark::check_count!(add_missing_match_arms_lazy_computation, 1);
 +        check_assist_unresolved(
 +            add_missing_match_arms,
 +            r#"
 +enum A { One, Two, }
 +fn foo(tuple: (A, A)) {
 +    match $0tuple {};
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn adds_comma_before_new_arms() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(t: bool) {
 +    match $0t {
 +        true => 1 + 2
 +    }
 +}"#,
 +            r#"
 +fn foo(t: bool) {
 +    match t {
 +        true => 1 + 2,
 +        $0false => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_add_extra_comma() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(t: bool) {
 +    match $0t {
 +        true => 1 + 2,
 +    }
 +}"#,
 +            r#"
 +fn foo(t: bool) {
 +    match t {
 +        true => 1 + 2,
 +        $0false => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_remove_catch_all_with_non_empty_expr() {
 +        cov_mark::check!(add_missing_match_arms_empty_expr);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +fn foo(t: bool) {
 +    match $0t {
 +        _ => 1 + 2,
 +    }
 +}"#,
 +            r#"
 +fn foo(t: bool) {
 +    match t {
 +        _ => 1 + 2,
 +        $0true => todo!(),
 +        false => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_fill_hidden_variants() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { A, #[doc(hidden)] B, }
 +"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        $0e::E::A => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_fill_hidden_variants_tuple() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: (bool, ::e::E)) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { A, #[doc(hidden)] B, }
 +"#,
 +            r#"
 +fn foo(t: (bool, ::e::E)) {
 +    match t {
 +        $0(true, e::E::A) => todo!(),
 +        (false, e::E::A) => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fills_wildcard_with_only_hidden_variants() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { #[doc(hidden)] A, }
 +"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        ${0:_} => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_fill_wildcard_when_hidden_variants_are_explicit() {
 +        check_assist_not_applicable(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +        e::E::A => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { #[doc(hidden)] A, }
 +"#,
 +        );
 +    }
 +
 +    // FIXME: I don't think the assist should be applicable in this case
 +    #[test]
 +    fn does_not_fill_wildcard_with_wildcard() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +        _ => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { #[doc(hidden)] A, }
 +"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fills_wildcard_on_non_exhaustive_with_explicit_matches() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +        e::E::A => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +#[non_exhaustive]
 +pub enum E { A, }
 +"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        e::E::A => todo!(),
 +        ${0:_} => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fills_wildcard_on_non_exhaustive_without_matches() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +#[non_exhaustive]
 +pub enum E { A, }
 +"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        $0e::E::A => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fills_wildcard_on_non_exhaustive_with_doc_hidden() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +#[non_exhaustive]
 +pub enum E { A, #[doc(hidden)] B }"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        $0e::E::A => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fills_wildcard_on_non_exhaustive_with_doc_hidden_with_explicit_arms() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +        e::E::A => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +#[non_exhaustive]
 +pub enum E { A, #[doc(hidden)] B }"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        e::E::A => todo!(),
 +        ${0:_} => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fill_wildcard_with_partial_wildcard() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E, b: bool) {
 +    match $0t {
 +        _ if b => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { #[doc(hidden)] A, }"#,
 +            r#"
 +fn foo(t: ::e::E, b: bool) {
 +    match t {
 +        _ if b => todo!(),
 +        ${0:_} => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_fill_wildcard_with_partial_wildcard_and_wildcard() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E, b: bool) {
 +    match $0t {
 +        _ if b => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +//- /e.rs crate:e
 +pub enum E { #[doc(hidden)] A, }"#,
 +            r#"
 +fn foo(t: ::e::E, b: bool) {
 +    match t {
 +        _ if b => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn non_exhaustive_doc_hidden_tuple_fills_wildcard() {
 +        cov_mark::check!(added_wildcard_pattern);
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +//- /main.rs crate:main deps:e
 +fn foo(t: ::e::E) {
 +    match $0t {
 +    }
 +}
 +//- /e.rs crate:e
 +#[non_exhaustive]
 +pub enum E { A, #[doc(hidden)] B, }"#,
 +            r#"
 +fn foo(t: ::e::E) {
 +    match t {
 +        $0e::E::A => todo!(),
 +        _ => todo!(),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn ignores_doc_hidden_for_crate_local_enums() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +enum E { A, #[doc(hidden)] B, }
 +
 +fn foo(t: E) {
 +    match $0t {
 +    }
 +}"#,
 +            r#"
 +enum E { A, #[doc(hidden)] B, }
 +
 +fn foo(t: E) {
 +    match t {
 +        $0E::A => todo!(),
 +        E::B => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn ignores_non_exhaustive_for_crate_local_enums() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +#[non_exhaustive]
 +enum E { A, B, }
 +
 +fn foo(t: E) {
 +    match $0t {
 +    }
 +}"#,
 +            r#"
 +#[non_exhaustive]
 +enum E { A, B, }
 +
 +fn foo(t: E) {
 +    match t {
 +        $0E::A => todo!(),
 +        E::B => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn ignores_doc_hidden_and_non_exhaustive_for_crate_local_enums() {
 +        check_assist(
 +            add_missing_match_arms,
 +            r#"
 +#[non_exhaustive]
 +enum E { A, #[doc(hidden)] B, }
 +
 +fn foo(t: E) {
 +    match $0t {
 +    }
 +}"#,
 +            r#"
 +#[non_exhaustive]
 +enum E { A, #[doc(hidden)] B, }
 +
 +fn foo(t: E) {
 +    match t {
 +        $0E::A => todo!(),
 +        E::B => todo!(),
 +    }
 +}"#,
 +        );
 +    }
 +}
index 949cf3167a8a1d94e4c177bf49958a73beda21ea,0000000000000000000000000000000000000000..e257218ba937686275d3c8f78f998d0f49e4d073
mode 100644,000000..100644
--- /dev/null
@@@ -1,1292 -1,0 +1,1295 @@@
-     let mut proposed_imports =
-         import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
 +use std::cmp::Reverse;
 +
 +use hir::{db::HirDatabase, Module};
 +use ide_db::{
 +    helpers::mod_path_to_ast,
 +    imports::{
 +        import_assets::{ImportAssets, ImportCandidate, LocatedImport},
 +        insert_use::{insert_use, ImportScope},
 +    },
 +};
 +use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
 +
 +use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 +
 +// Feature: Auto Import
 +//
 +// Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
 +// When inserting an import it will do so in a structured manner by keeping imports grouped,
 +// separated by a newline in the following order:
 +//
 +// - `std` and `core`
 +// - External Crates
 +// - Current Crate, paths prefixed by `crate`
 +// - Current Module, paths prefixed by `self`
 +// - Super Module, paths prefixed by `super`
 +//
 +// Example:
 +// ```rust
 +// use std::fs::File;
 +//
 +// use itertools::Itertools;
 +// use syntax::ast;
 +//
 +// use crate::utils::insert_use;
 +//
 +// use self::auto_import;
 +//
 +// use super::AssistContext;
 +// ```
 +//
 +// .Import Granularity
 +//
 +// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
 +// It has the following configurations:
 +//
 +// - `crate`: Merge imports from the same crate into a single use statement. This kind of
 +//  nesting is only supported in Rust versions later than 1.24.
 +// - `module`: Merge imports from the same module into a single use statement.
 +// - `item`: Don't merge imports at all, creating one import per item.
 +// - `preserve`: Do not change the granularity of any imports. For auto-import this has the same
 +//  effect as `item`.
 +//
 +// In `VS Code` the configuration for this is `rust-analyzer.imports.granularity.group`.
 +//
 +// .Import Prefix
 +//
 +// The style of imports in the same crate is configurable through the `imports.prefix` setting.
 +// It has the following configurations:
 +//
 +// - `crate`: This setting will force paths to be always absolute, starting with the `crate`
 +//  prefix, unless the item is defined outside of the current crate.
 +// - `self`: This setting will force paths that are relative to the current module to always
 +//  start with `self`. This will result in paths that always start with either `crate`, `self`,
 +//  `super` or an extern crate identifier.
 +// - `plain`: This setting does not impose any restrictions in imports.
 +//
 +// In `VS Code` the configuration for this is `rust-analyzer.imports.prefix`.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
 +
 +// Assist: auto_import
 +//
 +// If the name is unresolved, provides all possible imports for it.
 +//
 +// ```
 +// fn main() {
 +//     let map = HashMap$0::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +// ->
 +// ```
 +// use std::collections::HashMap;
 +//
 +// fn main() {
 +//     let map = HashMap::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
++    let mut proposed_imports = import_assets.search_for_imports(
++        &ctx.sema,
++        ctx.config.insert_use.prefix_kind,
++        ctx.config.prefer_no_std,
++    );
 +    if proposed_imports.is_empty() {
 +        return None;
 +    }
 +
 +    let range = match &syntax_under_caret {
 +        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
 +        NodeOrToken::Token(token) => token.text_range(),
 +    };
 +    let group_label = group_label(import_assets.import_candidate());
 +    let scope = ImportScope::find_insert_use_container(
 +        &match syntax_under_caret {
 +            NodeOrToken::Node(it) => it,
 +            NodeOrToken::Token(it) => it.parent()?,
 +        },
 +        &ctx.sema,
 +    )?;
 +
 +    // we aren't interested in different namespaces
 +    proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
 +
 +    let current_node = match ctx.covering_element() {
 +        NodeOrToken::Node(node) => Some(node),
 +        NodeOrToken::Token(token) => token.parent(),
 +    };
 +
 +    let current_module =
 +        current_node.as_ref().and_then(|node| ctx.sema.scope(node)).map(|scope| scope.module());
 +
 +    // prioritize more relevant imports
 +    proposed_imports
 +        .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
 +
 +    for import in proposed_imports {
 +        acc.add_group(
 +            &group_label,
 +            AssistId("auto_import", AssistKind::QuickFix),
 +            format!("Import `{}`", import.import_path),
 +            range,
 +            |builder| {
 +                let scope = match scope.clone() {
 +                    ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
 +                    ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
 +                    ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
 +                };
 +                insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
 +            },
 +        );
 +    }
 +    Some(())
 +}
 +
 +pub(super) fn find_importable_node(
 +    ctx: &AssistContext<'_>,
 +) -> Option<(ImportAssets, SyntaxElement)> {
 +    if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
 +        ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
 +            .zip(Some(path_under_caret.syntax().clone().into()))
 +    } else if let Some(method_under_caret) =
 +        ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
 +    {
 +        ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
 +            .zip(Some(method_under_caret.syntax().clone().into()))
 +    } else if let Some(pat) = ctx
 +        .find_node_at_offset_with_descend::<ast::IdentPat>()
 +        .filter(ast::IdentPat::is_simple_ident)
 +    {
 +        ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
 +    let name = match import_candidate {
 +        ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
 +        ImportCandidate::TraitAssocItem(candidate) => {
 +            format!("Import a trait for item {}", candidate.assoc_item_name.text())
 +        }
 +        ImportCandidate::TraitMethod(candidate) => {
 +            format!("Import a trait for method {}", candidate.assoc_item_name.text())
 +        }
 +    };
 +    GroupLabel(name)
 +}
 +
 +/// Determine how relevant a given import is in the current context. Higher scores are more
 +/// relevant.
 +fn relevance_score(
 +    ctx: &AssistContext<'_>,
 +    import: &LocatedImport,
 +    current_module: Option<&Module>,
 +) -> i32 {
 +    let mut score = 0;
 +
 +    let db = ctx.db();
 +
 +    let item_module = match import.item_to_import {
 +        hir::ItemInNs::Types(item) | hir::ItemInNs::Values(item) => item.module(db),
 +        hir::ItemInNs::Macros(makro) => Some(makro.module(db)),
 +    };
 +
 +    match item_module.zip(current_module) {
 +        // get the distance between the imported path and the current module
 +        // (prefer items that are more local)
 +        Some((item_module, current_module)) => {
 +            score -= module_distance_hueristic(db, &current_module, &item_module) as i32;
 +        }
 +
 +        // could not find relevant modules, so just use the length of the path as an estimate
 +        None => return -(2 * import.import_path.len() as i32),
 +    }
 +
 +    score
 +}
 +
 +/// A heuristic that gives a higher score to modules that are more separated.
 +fn module_distance_hueristic(db: &dyn HirDatabase, current: &Module, item: &Module) -> usize {
 +    // get the path starting from the item to the respective crate roots
 +    let mut current_path = current.path_to_root(db);
 +    let mut item_path = item.path_to_root(db);
 +
 +    // we want paths going from the root to the item
 +    current_path.reverse();
 +    item_path.reverse();
 +
 +    // length of the common prefix of the two paths
 +    let prefix_length = current_path.iter().zip(&item_path).take_while(|(a, b)| a == b).count();
 +
 +    // how many modules differ between the two paths (all modules, removing any duplicates)
 +    let distinct_length = current_path.len() + item_path.len() - 2 * prefix_length;
 +
 +    // cost of importing from another crate
 +    let crate_boundary_cost = if current.krate() == item.krate() {
 +        0
 +    } else if item.krate().is_builtin(db) {
 +        2
 +    } else {
 +        4
 +    };
 +
 +    distinct_length + crate_boundary_cost
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use hir::Semantics;
 +    use ide_db::{
 +        assists::AssistResolveStrategy,
 +        base_db::{fixture::WithFixture, FileRange},
 +        RootDatabase,
 +    };
 +
 +    use crate::tests::{
 +        check_assist, check_assist_not_applicable, check_assist_target, TEST_CONFIG,
 +    };
 +
 +    fn check_auto_import_order(before: &str, order: &[&str]) {
 +        let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
 +        let frange = FileRange { file_id, range: range_or_offset.into() };
 +
 +        let sema = Semantics::new(&db);
 +        let config = TEST_CONFIG;
 +        let ctx = AssistContext::new(sema, &config, frange);
 +        let mut acc = Assists::new(&ctx, AssistResolveStrategy::All);
 +        auto_import(&mut acc, &ctx);
 +        let assists = acc.finish();
 +
 +        let labels = assists.iter().map(|assist| assist.label.to_string()).collect::<Vec<_>>();
 +
 +        assert_eq!(labels, order);
 +    }
 +
 +    #[test]
 +    fn prefer_shorter_paths() {
 +        let before = r"
 +//- /main.rs crate:main deps:foo,bar
 +HashMap$0::new();
 +
 +//- /lib.rs crate:foo
 +pub mod collections { pub struct HashMap; }
 +
 +//- /lib.rs crate:bar
 +pub mod collections { pub mod hash_map { pub struct HashMap; } }
 +        ";
 +
 +        check_auto_import_order(
 +            before,
 +            &["Import `foo::collections::HashMap`", "Import `bar::collections::hash_map::HashMap`"],
 +        )
 +    }
 +
 +    #[test]
 +    fn prefer_same_crate() {
 +        let before = r"
 +//- /main.rs crate:main deps:foo
 +HashMap$0::new();
 +
 +mod collections {
 +    pub mod hash_map {
 +        pub struct HashMap;
 +    }
 +}
 +
 +//- /lib.rs crate:foo
 +pub struct HashMap;
 +        ";
 +
 +        check_auto_import_order(
 +            before,
 +            &["Import `collections::hash_map::HashMap`", "Import `foo::HashMap`"],
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_if_scope_inside_macro() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +mod bar {
 +    pub struct Baz;
 +}
 +macro_rules! foo {
 +    ($it:ident) => {
 +        mod __ {
 +            fn __(x: $it) {}
 +        }
 +    };
 +}
 +foo! {
 +    Baz$0
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_in_attributes() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +mod foo {
 +    mod bar {
 +        const _: Baz$0 = ();
 +    }
 +}
 +mod baz {
 +    pub struct Baz;
 +}
 +",
 +            r"
 +#[proc_macros::identity]
 +mod foo {
 +    mod bar {
 +        use crate::baz::Baz;
 +
 +        const _: Baz = ();
 +    }
 +}
 +mod baz {
 +    pub struct Baz;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import_partial() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod std {
 +                pub mod fmt {
 +                    pub struct Formatter;
 +                }
 +            }
 +
 +            use std::fmt;
 +
 +            $0Formatter
 +            ",
 +            r"
 +            mod std {
 +                pub mod fmt {
 +                    pub struct Formatter;
 +                }
 +            }
 +
 +            use std::fmt::{self, Formatter};
 +
 +            Formatter
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            $0PubStruct
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod::PubStruct;
 +
 +            PubStruct
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import_in_macros() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            macro_rules! foo {
 +                ($i:ident) => { fn foo(a: $i) {} }
 +            }
 +            foo!(Pub$0Struct);
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod::PubStruct;
 +
 +            macro_rules! foo {
 +                ($i:ident) => { fn foo(a: $i) {} }
 +            }
 +            foo!(PubStruct);
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_multiple_imports() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            PubSt$0ruct
 +
 +            pub mod PubMod1 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod2 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod3 {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod3::PubStruct;
 +
 +            PubStruct
 +
 +            pub mod PubMod1 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod2 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod3 {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_already_imported_types() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            use PubMod::PubStruct;
 +
 +            PubStruct$0
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_types_with_private_paths() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            PrivateStruct$0
 +
 +            pub mod PubMod {
 +                struct PrivateStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_no_imports_found() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            "
 +            PubStruct$0",
 +        );
 +    }
 +
 +    #[test]
 +    fn function_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            test_function$0
 +
 +            pub mod PubMod {
 +                pub fn test_function() {};
 +            }
 +            ",
 +            r"
 +            use PubMod::test_function;
 +
 +            test_function
 +
 +            pub mod PubMod {
 +                pub fn test_function() {};
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:crate_with_macro
 +#[macro_export]
 +macro_rules! foo {
 +    () => ()
 +}
 +
 +//- /main.rs crate:main deps:crate_with_macro
 +fn main() {
 +    foo$0
 +}
 +",
 +            r"use crate_with_macro::foo;
 +
 +fn main() {
 +    foo
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn auto_import_target() {
 +        check_assist_target(
 +            auto_import,
 +            r"
 +            struct AssistInfo {
 +                group_label: Option<$0GroupLabel>,
 +            }
 +
 +            mod m { pub struct GroupLabel; }
 +            ",
 +            "GroupLabel",
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_path_start_is_imported() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            pub mod mod1 {
 +                pub mod mod2 {
 +                    pub mod mod3 {
 +                        pub struct TestStruct;
 +                    }
 +                }
 +            }
 +
 +            use mod1::mod2;
 +            fn main() {
 +                mod2::mod3::TestStruct$0
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_function() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            pub mod test_mod {
 +                pub fn test_function() {}
 +            }
 +
 +            use test_mod::test_function;
 +            fn main() {
 +                test_function$0
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_function() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    pub fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::test_function$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestStruct;
 +
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    pub fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_const() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::TEST_CONST$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestStruct;
 +
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::TEST_CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_trait_function() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::test_function$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_function() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub trait TestTrait2 {
 +                    fn test_function();
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    fn test_function() {}
 +                }
 +                impl TestTrait for TestEnum {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                test_mod::TestEnum::test_function$0;
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn associated_trait_const() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::TEST_CONST$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::TEST_CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_const() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub trait TestTrait2 {
 +                    const TEST_CONST: f64;
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    const TEST_CONST: f64 = 42.0;
 +                }
 +                impl TestTrait for TestEnum {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                test_mod::TestEnum::TEST_CONST$0;
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn trait_method() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            fn main() {
 +                let test_struct = test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            fn main() {
 +                let test_struct = test_mod::TestStruct {};
 +                test_struct.test_method()
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_method()
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                dep::test_mod::TestStruct::test_func$0tion
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                dep::test_mod::TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_const_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                dep::test_mod::TestStruct::CONST$0
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    const CONST: bool;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const CONST: bool = true;
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                dep::test_mod::TestStruct::CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_as_method_cross_crate() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_func$0tion()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn private_trait_cross_crate() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_method() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub trait TestTrait2 {
 +                    fn test_method(&self);
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    fn test_method(&self) {}
 +                }
 +                impl TestTrait for TestEnum {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                let one = test_mod::TestEnum::One;
 +                one.test$0_method();
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn dep_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct Struct;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Struct$0
 +}
 +",
 +            r"use dep::Struct;
 +
 +fn main() {
 +    Struct
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn whole_segment() {
 +        // Tests that only imports whose last segment matches the identifier get suggested.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub mod fmt {
 +    pub trait Display {}
 +}
 +
 +pub fn panic_fmt() {}
 +
 +//- /main.rs crate:main deps:dep
 +struct S;
 +
 +impl f$0mt::Display for S {}
 +",
 +            r"use dep::fmt;
 +
 +struct S;
 +
 +impl fmt::Display for S {}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_generated() {
 +        // Tests that macro-generated items are suggested from external crates.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +macro_rules! mac {
 +    () => {
 +        pub struct Cheese;
 +    };
 +}
 +
 +mac!();
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Cheese$0;
 +}
 +",
 +            r"use dep::Cheese;
 +
 +fn main() {
 +    Cheese;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn casing() {
 +        // Tests that differently cased names don't interfere and we only suggest the matching one.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct FMT;
 +pub struct fmt;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    FMT$0;
 +}
 +",
 +            r"use dep::FMT;
 +
 +fn main() {
 +    FMT;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn inner_items() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    fn bar() {
 +        Foo$0;
 +        println!("Hallo");
 +    }
 +}
 +"#,
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    use crate::baz::Foo;
 +
 +    fn bar() {
 +        Foo;
 +        println!("Hallo");
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn uses_abs_path_with_extern_crate_clash() {
 +        cov_mark::check!(ambiguous_crate_start);
 +        check_assist(
 +            auto_import,
 +            r#"
 +//- /main.rs crate:main deps:foo
 +mod foo {}
 +
 +const _: () = {
 +    Foo$0
 +};
 +//- /foo.rs crate:foo
 +pub struct Foo
 +"#,
 +            r#"
 +use ::foo::Foo;
 +
 +mod foo {}
 +
 +const _: () = {
 +    Foo
 +};
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_on_ident_patterns() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod foo {
 +    pub struct Foo {}
 +}
 +fn foo() {
 +    let Foo$0;
 +}
 +"#,
 +            r#"
 +use foo::Foo;
 +
 +mod foo {
 +    pub struct Foo {}
 +}
 +fn foo() {
 +    let Foo;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_derives() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(Copy$0)]
 +struct Foo;
 +"#,
 +            r#"
 +use foo::Copy;
 +
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(Copy)]
 +struct Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_use_start() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo$0::Foo;
 +"#,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use bar::foo;
 +use foo::Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_in_non_start_use() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo::Foo$0;
 +",
 +        );
 +    }
 +}
index 30f6dd41a1d6d53398855c686adfb3df50d87616,0000000000000000000000000000000000000000..95d11abe8bc0f6fea075297b0c1473e81ec7a77b
mode 100644,000000..100644
--- /dev/null
@@@ -1,351 -1,0 +1,351 @@@
-         mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
 +use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait};
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{AssistContext, AssistId, AssistKind, Assists};
 +
 +// FIXME: this should be a diagnostic
 +
 +// Assist: convert_into_to_from
 +//
 +// Converts an Into impl to an equivalent From impl.
 +//
 +// ```
 +// # //- minicore: from
 +// impl $0Into<Thing> for usize {
 +//     fn into(self) -> Thing {
 +//         Thing {
 +//             b: self.to_string(),
 +//             a: self
 +//         }
 +//     }
 +// }
 +// ```
 +// ->
 +// ```
 +// impl From<usize> for Thing {
 +//     fn from(val: usize) -> Self {
 +//         Thing {
 +//             b: val.to_string(),
 +//             a: val
 +//         }
 +//     }
 +// }
 +// ```
 +pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let impl_ = ctx.find_node_at_offset::<ast::Impl>()?;
 +    let src_type = impl_.self_ty()?;
 +    let ast_trait = impl_.trait_()?;
 +
 +    let module = ctx.sema.scope(impl_.syntax())?.module();
 +
 +    let trait_ = resolve_target_trait(&ctx.sema, &impl_)?;
 +    if trait_ != FamousDefs(&ctx.sema, module.krate()).core_convert_Into()? {
 +        return None;
 +    }
 +
 +    let src_type_path = {
 +        let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?;
 +        let src_type_def = match ctx.sema.resolve_path(&src_type_path) {
 +            Some(hir::PathResolution::Def(module_def)) => module_def,
 +            _ => return None,
 +        };
 +
++        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_no_std)?)
 +    };
 +
 +    let dest_type = match &ast_trait {
 +        ast::Type::PathType(path) => {
 +            path.path()?.segment()?.generic_arg_list()?.generic_args().next()?
 +        }
 +        _ => return None,
 +    };
 +
 +    let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| {
 +        if let ast::AssocItem::Fn(f) = item {
 +            if f.name()?.text() == "into" {
 +                return Some(f);
 +            }
 +        };
 +        None
 +    })?;
 +
 +    let into_fn_name = into_fn.name()?;
 +    let into_fn_params = into_fn.param_list()?;
 +    let into_fn_return = into_fn.ret_type()?;
 +
 +    let selfs = into_fn
 +        .body()?
 +        .syntax()
 +        .descendants()
 +        .filter_map(ast::NameRef::cast)
 +        .filter(|name| name.text() == "self" || name.text() == "Self");
 +
 +    acc.add(
 +        AssistId("convert_into_to_from", AssistKind::RefactorRewrite),
 +        "Convert Into to From",
 +        impl_.syntax().text_range(),
 +        |builder| {
 +            builder.replace(src_type.syntax().text_range(), dest_type.to_string());
 +            builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type));
 +            builder.replace(into_fn_return.syntax().text_range(), "-> Self");
 +            builder.replace(into_fn_params.syntax().text_range(), format!("(val: {})", src_type));
 +            builder.replace(into_fn_name.syntax().text_range(), "from");
 +
 +            for s in selfs {
 +                match s.text().as_ref() {
 +                    "self" => builder.replace(s.syntax().text_range(), "val"),
 +                    "Self" => builder.replace(s.syntax().text_range(), src_type_path.to_string()),
 +                    _ => {}
 +                }
 +            }
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    #[test]
 +    fn convert_into_to_from_converts_a_struct() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +struct Thing {
 +    a: String,
 +    b: usize
 +}
 +
 +impl $0core::convert::Into<Thing> for usize {
 +    fn into(self) -> Thing {
 +        Thing {
 +            b: self.to_string(),
 +            a: self
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +struct Thing {
 +    a: String,
 +    b: usize
 +}
 +
 +impl From<usize> for Thing {
 +    fn from(val: usize) -> Self {
 +        Thing {
 +            b: val.to_string(),
 +            a: val
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_converts_enums() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +enum Thing {
 +    Foo(String),
 +    Bar(String)
 +}
 +
 +impl $0core::convert::Into<String> for Thing {
 +    fn into(self) -> String {
 +        match self {
 +            Self::Foo(s) => s,
 +            Self::Bar(s) => s
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +enum Thing {
 +    Foo(String),
 +    Bar(String)
 +}
 +
 +impl From<Thing> for String {
 +    fn from(val: Thing) -> Self {
 +        match val {
 +            Thing::Foo(s) => s,
 +            Thing::Bar(s) => s
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_on_enum_with_lifetimes() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +enum Thing<'a> {
 +    Foo(&'a str),
 +    Bar(&'a str)
 +}
 +
 +impl<'a> $0core::convert::Into<&'a str> for Thing<'a> {
 +    fn into(self) -> &'a str {
 +        match self {
 +            Self::Foo(s) => s,
 +            Self::Bar(s) => s
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +enum Thing<'a> {
 +    Foo(&'a str),
 +    Bar(&'a str)
 +}
 +
 +impl<'a> From<Thing<'a>> for &'a str {
 +    fn from(val: Thing<'a>) -> Self {
 +        match val {
 +            Thing::Foo(s) => s,
 +            Thing::Bar(s) => s
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_works_on_references() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +struct Thing(String);
 +
 +impl $0core::convert::Into<String> for &Thing {
 +    fn into(self) -> Thing {
 +        self.0.clone()
 +    }
 +}
 +"#,
 +            r#"
 +struct Thing(String);
 +
 +impl From<&Thing> for String {
 +    fn from(val: &Thing) -> Self {
 +        val.0.clone()
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_works_on_qualified_structs() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +mod things {
 +    pub struct Thing(String);
 +    pub struct BetterThing(String);
 +}
 +
 +impl $0core::convert::Into<things::BetterThing> for &things::Thing {
 +    fn into(self) -> Thing {
 +        things::BetterThing(self.0.clone())
 +    }
 +}
 +"#,
 +            r#"
 +mod things {
 +    pub struct Thing(String);
 +    pub struct BetterThing(String);
 +}
 +
 +impl From<&things::Thing> for things::BetterThing {
 +    fn from(val: &things::Thing) -> Self {
 +        things::BetterThing(val.0.clone())
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_works_on_qualified_enums() {
 +        check_assist(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +mod things {
 +    pub enum Thing {
 +        A(String)
 +    }
 +    pub struct BetterThing {
 +        B(String)
 +    }
 +}
 +
 +impl $0core::convert::Into<things::BetterThing> for &things::Thing {
 +    fn into(self) -> Thing {
 +        match self {
 +            Self::A(s) => things::BetterThing::B(s)
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +mod things {
 +    pub enum Thing {
 +        A(String)
 +    }
 +    pub struct BetterThing {
 +        B(String)
 +    }
 +}
 +
 +impl From<&things::Thing> for things::BetterThing {
 +    fn from(val: &things::Thing) -> Self {
 +        match val {
 +            things::Thing::A(s) => things::BetterThing::B(s)
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn convert_into_to_from_not_applicable_on_any_trait_named_into() {
 +        check_assist_not_applicable(
 +            convert_into_to_from,
 +            r#"
 +//- minicore: from
 +pub trait Into<T> {
 +    pub fn into(self) -> T;
 +}
 +
 +struct Thing {
 +    a: String,
 +}
 +
 +impl $0Into<Thing> for String {
 +    fn into(self) -> Thing {
 +        Thing {
 +            a: self
 +        }
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index 52a55ead3af9629e518dd1ffb621af3738a1b7ec,0000000000000000000000000000000000000000..d6c8ea785f84aa87f1b2904e06ddcdab103eafc1
mode 100644,000000..100644
--- /dev/null
@@@ -1,5333 -1,0 +1,5334 @@@
 +use std::iter;
 +
 +use ast::make;
 +use either::Either;
 +use hir::{
 +    HasSource, HirDisplay, InFile, Local, ModuleDef, PathResolution, Semantics, TypeInfo, TypeParam,
 +};
 +use ide_db::{
 +    defs::{Definition, NameRefClass},
 +    famous_defs::FamousDefs,
 +    helpers::mod_path_to_ast,
 +    imports::insert_use::{insert_use, ImportScope},
 +    search::{FileReference, ReferenceCategory, SearchScope},
 +    syntax_helpers::node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr},
 +    FxIndexSet, RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::format_to;
 +use syntax::{
 +    ast::{
 +        self,
 +        edit::{AstNodeEdit, IndentLevel},
 +        AstNode, HasGenericParams,
 +    },
 +    match_ast, ted, SyntaxElement,
 +    SyntaxKind::{self, COMMENT},
 +    SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists, TreeMutator},
 +    utils::generate_impl_text,
 +    AssistId,
 +};
 +
 +// Assist: extract_function
 +//
 +// Extracts selected statements and comments into new function.
 +//
 +// ```
 +// fn main() {
 +//     let n = 1;
 +//     $0let m = n + 2;
 +//     // calculate
 +//     let k = m + n;$0
 +//     let g = 3;
 +// }
 +// ```
 +// ->
 +// ```
 +// fn main() {
 +//     let n = 1;
 +//     fun_name(n);
 +//     let g = 3;
 +// }
 +//
 +// fn $0fun_name(n: i32) {
 +//     let m = n + 2;
 +//     // calculate
 +//     let k = m + n;
 +// }
 +// ```
 +pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let range = ctx.selection_trimmed();
 +    if range.is_empty() {
 +        return None;
 +    }
 +
 +    let node = ctx.covering_element();
 +    if node.kind() == COMMENT {
 +        cov_mark::hit!(extract_function_in_comment_is_not_applicable);
 +        return None;
 +    }
 +
 +    let node = match node {
 +        syntax::NodeOrToken::Node(n) => n,
 +        syntax::NodeOrToken::Token(t) => t.parent()?,
 +    };
 +
 +    let body = extraction_target(&node, range)?;
 +    let container_info = body.analyze_container(&ctx.sema)?;
 +
 +    let (locals_used, self_param) = body.analyze(&ctx.sema);
 +
 +    let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
 +    let insert_after = node_to_insert_after(&body, anchor)?;
 +    let semantics_scope = ctx.sema.scope(&insert_after)?;
 +    let module = semantics_scope.module();
 +
 +    let ret_ty = body.return_ty(ctx)?;
 +    let control_flow = body.external_control_flow(ctx, &container_info)?;
 +    let ret_values = body.ret_values(ctx, node.parent().as_ref().unwrap_or(&node));
 +
 +    let target_range = body.text_range();
 +
 +    let scope = ImportScope::find_insert_use_container(&node, &ctx.sema)?;
 +
 +    acc.add(
 +        AssistId("extract_function", crate::AssistKind::RefactorExtract),
 +        "Extract into function",
 +        target_range,
 +        move |builder| {
 +            let outliving_locals: Vec<_> = ret_values.collect();
 +            if stdx::never!(!outliving_locals.is_empty() && !ret_ty.is_unit()) {
 +                // We should not have variables that outlive body if we have expression block
 +                return;
 +            }
 +
 +            let params =
 +                body.extracted_function_params(ctx, &container_info, locals_used.iter().copied());
 +
 +            let extracted_from_trait_impl = body.extracted_from_trait_impl();
 +
 +            let name = make_function_name(&semantics_scope);
 +
 +            let fun = Function {
 +                name,
 +                self_param,
 +                params,
 +                control_flow,
 +                ret_ty,
 +                body,
 +                outliving_locals,
 +                mods: container_info,
 +            };
 +
 +            let new_indent = IndentLevel::from_node(&insert_after);
 +            let old_indent = fun.body.indent_level();
 +
 +            builder.replace(target_range, make_call(ctx, &fun, old_indent));
 +
 +            let fn_def = match fun.self_param_adt(ctx) {
 +                Some(adt) if extracted_from_trait_impl => {
 +                    let fn_def = format_function(ctx, module, &fun, old_indent, new_indent + 1);
 +                    generate_impl_text(&adt, &fn_def).replace("{\n\n", "{")
 +                }
 +                _ => format_function(ctx, module, &fun, old_indent, new_indent),
 +            };
 +
 +            if fn_def.contains("ControlFlow") {
 +                let scope = match scope {
 +                    ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
 +                    ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
 +                    ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
 +                };
 +
 +                let control_flow_enum =
 +                    FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow();
 +
 +                if let Some(control_flow_enum) = control_flow_enum {
 +                    let mod_path = module.find_use_path_prefixed(
 +                        ctx.sema.db,
 +                        ModuleDef::from(control_flow_enum),
 +                        ctx.config.insert_use.prefix_kind,
++                        ctx.config.prefer_no_std,
 +                    );
 +
 +                    if let Some(mod_path) = mod_path {
 +                        insert_use(&scope, mod_path_to_ast(&mod_path), &ctx.config.insert_use);
 +                    }
 +                }
 +            }
 +
 +            let insert_offset = insert_after.text_range().end();
 +
 +            match ctx.config.snippet_cap {
 +                Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
 +                None => builder.insert(insert_offset, fn_def),
 +            };
 +        },
 +    )
 +}
 +
 +fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef {
 +    let mut names_in_scope = vec![];
 +    semantics_scope.process_all_names(&mut |name, _| names_in_scope.push(name.to_string()));
 +
 +    let default_name = "fun_name";
 +
 +    let mut name = default_name.to_string();
 +    let mut counter = 0;
 +    while names_in_scope.contains(&name) {
 +        counter += 1;
 +        name = format!("{}{}", &default_name, counter)
 +    }
 +    make::name_ref(&name)
 +}
 +
 +/// Try to guess what user wants to extract
 +///
 +/// We have basically have two cases:
 +/// * We want whole node, like `loop {}`, `2 + 2`, `{ let n = 1; }` exprs.
 +///   Then we can use `ast::Expr`
 +/// * We want a few statements for a block. E.g.
 +///   ```rust,no_run
 +///   fn foo() -> i32 {
 +///     let m = 1;
 +///     $0
 +///     let n = 2;
 +///     let k = 3;
 +///     k + n
 +///     $0
 +///   }
 +///   ```
 +///
 +fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<FunctionBody> {
 +    if let Some(stmt) = ast::Stmt::cast(node.clone()) {
 +        return match stmt {
 +            ast::Stmt::Item(_) => None,
 +            ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => Some(FunctionBody::from_range(
 +                node.parent().and_then(ast::StmtList::cast)?,
 +                node.text_range(),
 +            )),
 +        };
 +    }
 +
 +    // Covering element returned the parent block of one or multiple statements that have been selected
 +    if let Some(stmt_list) = ast::StmtList::cast(node.clone()) {
 +        if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) {
 +            if block_expr.syntax().text_range() == selection_range {
 +                return FunctionBody::from_expr(block_expr.into());
 +            }
 +        }
 +
 +        // Extract the full statements.
 +        return Some(FunctionBody::from_range(stmt_list, selection_range));
 +    }
 +
 +    let expr = ast::Expr::cast(node.clone())?;
 +    // A node got selected fully
 +    if node.text_range() == selection_range {
 +        return FunctionBody::from_expr(expr);
 +    }
 +
 +    node.ancestors().find_map(ast::Expr::cast).and_then(FunctionBody::from_expr)
 +}
 +
 +#[derive(Debug)]
 +struct Function {
 +    name: ast::NameRef,
 +    self_param: Option<ast::SelfParam>,
 +    params: Vec<Param>,
 +    control_flow: ControlFlow,
 +    ret_ty: RetType,
 +    body: FunctionBody,
 +    outliving_locals: Vec<OutlivedLocal>,
 +    mods: ContainerInfo,
 +}
 +
 +#[derive(Debug)]
 +struct Param {
 +    var: Local,
 +    ty: hir::Type,
 +    move_local: bool,
 +    requires_mut: bool,
 +    is_copy: bool,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +enum ParamKind {
 +    Value,
 +    MutValue,
 +    SharedRef,
 +    MutRef,
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +enum FunType {
 +    Unit,
 +    Single(hir::Type),
 +    Tuple(Vec<hir::Type>),
 +}
 +
 +/// Where to put extracted function definition
 +#[derive(Debug)]
 +enum Anchor {
 +    /// Extract free function and put right after current top-level function
 +    Freestanding,
 +    /// Extract method and put right after current function in the impl-block
 +    Method,
 +}
 +
 +// FIXME: ControlFlow and ContainerInfo both track some function modifiers, feels like these two should
 +// probably be merged somehow.
 +#[derive(Debug)]
 +struct ControlFlow {
 +    kind: Option<FlowKind>,
 +    is_async: bool,
 +    is_unsafe: bool,
 +}
 +
 +/// The thing whose expression we are extracting from. Can be a function, const, static, const arg, ...
 +#[derive(Clone, Debug)]
 +struct ContainerInfo {
 +    is_const: bool,
 +    is_in_tail: bool,
 +    parent_loop: Option<SyntaxNode>,
 +    /// The function's return type, const's type etc.
 +    ret_type: Option<hir::Type>,
 +    generic_param_lists: Vec<ast::GenericParamList>,
 +    where_clauses: Vec<ast::WhereClause>,
 +}
 +
 +/// Control flow that is exported from extracted function
 +///
 +/// E.g.:
 +/// ```rust,no_run
 +/// loop {
 +///     $0
 +///     if 42 == 42 {
 +///         break;
 +///     }
 +///     $0
 +/// }
 +/// ```
 +#[derive(Debug, Clone)]
 +enum FlowKind {
 +    /// Return with value (`return $expr;`)
 +    Return(Option<ast::Expr>),
 +    Try {
 +        kind: TryKind,
 +    },
 +    /// Break with label and value (`break 'label $expr;`)
 +    Break(Option<ast::Lifetime>, Option<ast::Expr>),
 +    /// Continue with label (`continue 'label;`)
 +    Continue(Option<ast::Lifetime>),
 +}
 +
 +#[derive(Debug, Clone)]
 +enum TryKind {
 +    Option,
 +    Result { ty: hir::Type },
 +}
 +
 +#[derive(Debug)]
 +enum RetType {
 +    Expr(hir::Type),
 +    Stmt,
 +}
 +
 +impl RetType {
 +    fn is_unit(&self) -> bool {
 +        match self {
 +            RetType::Expr(ty) => ty.is_unit(),
 +            RetType::Stmt => true,
 +        }
 +    }
 +}
 +
 +/// Semantically same as `ast::Expr`, but preserves identity when using only part of the Block
 +/// This is the future function body, the part that is being extracted.
 +#[derive(Debug)]
 +enum FunctionBody {
 +    Expr(ast::Expr),
 +    Span { parent: ast::StmtList, text_range: TextRange },
 +}
 +
 +#[derive(Debug)]
 +struct OutlivedLocal {
 +    local: Local,
 +    mut_usage_outside_body: bool,
 +}
 +
 +/// Container of local variable usages
 +///
 +/// Semanticall same as `UsageSearchResult`, but provides more convenient interface
 +struct LocalUsages(ide_db::search::UsageSearchResult);
 +
 +impl LocalUsages {
 +    fn find_local_usages(ctx: &AssistContext<'_>, var: Local) -> Self {
 +        Self(
 +            Definition::Local(var)
 +                .usages(&ctx.sema)
 +                .in_scope(SearchScope::single_file(ctx.file_id()))
 +                .all(),
 +        )
 +    }
 +
 +    fn iter(&self) -> impl Iterator<Item = &FileReference> + '_ {
 +        self.0.iter().flat_map(|(_, rs)| rs)
 +    }
 +}
 +
 +impl Function {
 +    fn return_type(&self, ctx: &AssistContext<'_>) -> FunType {
 +        match &self.ret_ty {
 +            RetType::Expr(ty) if ty.is_unit() => FunType::Unit,
 +            RetType::Expr(ty) => FunType::Single(ty.clone()),
 +            RetType::Stmt => match self.outliving_locals.as_slice() {
 +                [] => FunType::Unit,
 +                [var] => FunType::Single(var.local.ty(ctx.db())),
 +                vars => {
 +                    let types = vars.iter().map(|v| v.local.ty(ctx.db())).collect();
 +                    FunType::Tuple(types)
 +                }
 +            },
 +        }
 +    }
 +
 +    fn self_param_adt(&self, ctx: &AssistContext<'_>) -> Option<ast::Adt> {
 +        let self_param = self.self_param.as_ref()?;
 +        let def = ctx.sema.to_def(self_param)?;
 +        let adt = def.ty(ctx.db()).strip_references().as_adt()?;
 +        let InFile { file_id: _, value } = adt.source(ctx.db())?;
 +        Some(value)
 +    }
 +}
 +
 +impl ParamKind {
 +    fn is_ref(&self) -> bool {
 +        matches!(self, ParamKind::SharedRef | ParamKind::MutRef)
 +    }
 +}
 +
 +impl Param {
 +    fn kind(&self) -> ParamKind {
 +        match (self.move_local, self.requires_mut, self.is_copy) {
 +            (false, true, _) => ParamKind::MutRef,
 +            (false, false, false) => ParamKind::SharedRef,
 +            (true, true, _) => ParamKind::MutValue,
 +            (_, false, _) => ParamKind::Value,
 +        }
 +    }
 +
 +    fn to_arg(&self, ctx: &AssistContext<'_>) -> ast::Expr {
 +        let var = path_expr_from_local(ctx, self.var);
 +        match self.kind() {
 +            ParamKind::Value | ParamKind::MutValue => var,
 +            ParamKind::SharedRef => make::expr_ref(var, false),
 +            ParamKind::MutRef => make::expr_ref(var, true),
 +        }
 +    }
 +
 +    fn to_param(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Param {
 +        let var = self.var.name(ctx.db()).to_string();
 +        let var_name = make::name(&var);
 +        let pat = match self.kind() {
 +            ParamKind::MutValue => make::ident_pat(false, true, var_name),
 +            ParamKind::Value | ParamKind::SharedRef | ParamKind::MutRef => {
 +                make::ext::simple_ident_pat(var_name)
 +            }
 +        };
 +
 +        let ty = make_ty(&self.ty, ctx, module);
 +        let ty = match self.kind() {
 +            ParamKind::Value | ParamKind::MutValue => ty,
 +            ParamKind::SharedRef => make::ty_ref(ty, false),
 +            ParamKind::MutRef => make::ty_ref(ty, true),
 +        };
 +
 +        make::param(pat.into(), ty)
 +    }
 +}
 +
 +impl TryKind {
 +    fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>) -> Option<TryKind> {
 +        if ty.is_unknown() {
 +            // We favour Result for `expr?`
 +            return Some(TryKind::Result { ty });
 +        }
 +        let adt = ty.as_adt()?;
 +        let name = adt.name(ctx.db());
 +        // FIXME: use lang items to determine if it is std type or user defined
 +        //        E.g. if user happens to define type named `Option`, we would have false positive
 +        match name.to_string().as_str() {
 +            "Option" => Some(TryKind::Option),
 +            "Result" => Some(TryKind::Result { ty }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl FlowKind {
 +    fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr {
 +        match self {
 +            FlowKind::Return(_) => make::expr_return(expr),
 +            FlowKind::Break(label, _) => make::expr_break(label.clone(), expr),
 +            FlowKind::Try { .. } => {
 +                stdx::never!("cannot have result handler with try");
 +                expr.unwrap_or_else(|| make::expr_return(None))
 +            }
 +            FlowKind::Continue(label) => {
 +                stdx::always!(expr.is_none(), "continue with value is not possible");
 +                make::expr_continue(label.clone())
 +            }
 +        }
 +    }
 +
 +    fn expr_ty(&self, ctx: &AssistContext<'_>) -> Option<hir::Type> {
 +        match self {
 +            FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => {
 +                ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted)
 +            }
 +            FlowKind::Try { .. } => {
 +                stdx::never!("try does not have defined expr_ty");
 +                None
 +            }
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl FunctionBody {
 +    fn parent(&self) -> Option<SyntaxNode> {
 +        match self {
 +            FunctionBody::Expr(expr) => expr.syntax().parent(),
 +            FunctionBody::Span { parent, .. } => Some(parent.syntax().clone()),
 +        }
 +    }
 +
 +    fn node(&self) -> &SyntaxNode {
 +        match self {
 +            FunctionBody::Expr(e) => e.syntax(),
 +            FunctionBody::Span { parent, .. } => parent.syntax(),
 +        }
 +    }
 +
 +    fn extracted_from_trait_impl(&self) -> bool {
 +        match self.node().ancestors().find_map(ast::Impl::cast) {
 +            Some(c) => return c.trait_().is_some(),
 +            None => false,
 +        }
 +    }
 +
 +    fn descendants(&self) -> impl Iterator<Item = SyntaxNode> {
 +        match self {
 +            FunctionBody::Expr(expr) => expr.syntax().descendants(),
 +            FunctionBody::Span { parent, .. } => parent.syntax().descendants(),
 +        }
 +    }
 +
 +    fn descendant_paths(&self) -> impl Iterator<Item = ast::Path> {
 +        self.descendants().filter_map(|node| {
 +            match_ast! {
 +                match node {
 +                    ast::Path(it) => Some(it),
 +                    _ => None
 +                }
 +            }
 +        })
 +    }
 +
 +    fn from_expr(expr: ast::Expr) -> Option<Self> {
 +        match expr {
 +            ast::Expr::BreakExpr(it) => it.expr().map(Self::Expr),
 +            ast::Expr::ReturnExpr(it) => it.expr().map(Self::Expr),
 +            ast::Expr::BlockExpr(it) if !it.is_standalone() => None,
 +            expr => Some(Self::Expr(expr)),
 +        }
 +    }
 +
 +    fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
 +        let full_body = parent.syntax().children_with_tokens();
 +
 +        let mut text_range = full_body
 +            .filter(|it| ast::Stmt::can_cast(it.kind()) || it.kind() == COMMENT)
 +            .map(|element| element.text_range())
 +            .filter(|&range| selected.intersect(range).filter(|it| !it.is_empty()).is_some())
 +            .reduce(|acc, stmt| acc.cover(stmt));
 +
 +        if let Some(tail_range) = parent
 +            .tail_expr()
 +            .map(|it| it.syntax().text_range())
 +            .filter(|&it| selected.intersect(it).is_some())
 +        {
 +            text_range = Some(match text_range {
 +                Some(text_range) => text_range.cover(tail_range),
 +                None => tail_range,
 +            });
 +        }
 +        Self::Span { parent, text_range: text_range.unwrap_or(selected) }
 +    }
 +
 +    fn indent_level(&self) -> IndentLevel {
 +        match &self {
 +            FunctionBody::Expr(expr) => IndentLevel::from_node(expr.syntax()),
 +            FunctionBody::Span { parent, .. } => IndentLevel::from_node(parent.syntax()) + 1,
 +        }
 +    }
 +
 +    fn tail_expr(&self) -> Option<ast::Expr> {
 +        match &self {
 +            FunctionBody::Expr(expr) => Some(expr.clone()),
 +            FunctionBody::Span { parent, text_range } => {
 +                let tail_expr = parent.tail_expr()?;
 +                text_range.contains_range(tail_expr.syntax().text_range()).then(|| tail_expr)
 +            }
 +        }
 +    }
 +
 +    fn walk_expr(&self, cb: &mut dyn FnMut(ast::Expr)) {
 +        match self {
 +            FunctionBody::Expr(expr) => walk_expr(expr, cb),
 +            FunctionBody::Span { parent, text_range } => {
 +                parent
 +                    .statements()
 +                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
 +                    .filter_map(|stmt| match stmt {
 +                        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(),
 +                        ast::Stmt::Item(_) => None,
 +                        ast::Stmt::LetStmt(stmt) => stmt.initializer(),
 +                    })
 +                    .for_each(|expr| walk_expr(&expr, cb));
 +                if let Some(expr) = parent
 +                    .tail_expr()
 +                    .filter(|it| text_range.contains_range(it.syntax().text_range()))
 +                {
 +                    walk_expr(&expr, cb);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn preorder_expr(&self, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
 +        match self {
 +            FunctionBody::Expr(expr) => preorder_expr(expr, cb),
 +            FunctionBody::Span { parent, text_range } => {
 +                parent
 +                    .statements()
 +                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
 +                    .filter_map(|stmt| match stmt {
 +                        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(),
 +                        ast::Stmt::Item(_) => None,
 +                        ast::Stmt::LetStmt(stmt) => stmt.initializer(),
 +                    })
 +                    .for_each(|expr| preorder_expr(&expr, cb));
 +                if let Some(expr) = parent
 +                    .tail_expr()
 +                    .filter(|it| text_range.contains_range(it.syntax().text_range()))
 +                {
 +                    preorder_expr(&expr, cb);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn walk_pat(&self, cb: &mut dyn FnMut(ast::Pat)) {
 +        match self {
 +            FunctionBody::Expr(expr) => walk_patterns_in_expr(expr, cb),
 +            FunctionBody::Span { parent, text_range } => {
 +                parent
 +                    .statements()
 +                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
 +                    .for_each(|stmt| match stmt {
 +                        ast::Stmt::ExprStmt(expr_stmt) => {
 +                            if let Some(expr) = expr_stmt.expr() {
 +                                walk_patterns_in_expr(&expr, cb)
 +                            }
 +                        }
 +                        ast::Stmt::Item(_) => (),
 +                        ast::Stmt::LetStmt(stmt) => {
 +                            if let Some(pat) = stmt.pat() {
 +                                walk_pat(&pat, cb);
 +                            }
 +                            if let Some(expr) = stmt.initializer() {
 +                                walk_patterns_in_expr(&expr, cb);
 +                            }
 +                        }
 +                    });
 +                if let Some(expr) = parent
 +                    .tail_expr()
 +                    .filter(|it| text_range.contains_range(it.syntax().text_range()))
 +                {
 +                    walk_patterns_in_expr(&expr, cb);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn text_range(&self) -> TextRange {
 +        match self {
 +            FunctionBody::Expr(expr) => expr.syntax().text_range(),
 +            &FunctionBody::Span { text_range, .. } => text_range,
 +        }
 +    }
 +
 +    fn contains_range(&self, range: TextRange) -> bool {
 +        self.text_range().contains_range(range)
 +    }
 +
 +    fn precedes_range(&self, range: TextRange) -> bool {
 +        self.text_range().end() <= range.start()
 +    }
 +
 +    fn contains_node(&self, node: &SyntaxNode) -> bool {
 +        self.contains_range(node.text_range())
 +    }
 +}
 +
 +impl FunctionBody {
 +    /// Analyzes a function body, returning the used local variables that are referenced in it as well as
 +    /// whether it contains an await expression.
 +    fn analyze(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
 +    ) -> (FxIndexSet<Local>, Option<ast::SelfParam>) {
 +        let mut self_param = None;
 +        let mut res = FxIndexSet::default();
 +        let mut cb = |name_ref: Option<_>| {
 +            let local_ref =
 +                match name_ref.and_then(|name_ref| NameRefClass::classify(sema, &name_ref)) {
 +                    Some(
 +                        NameRefClass::Definition(Definition::Local(local_ref))
 +                        | NameRefClass::FieldShorthand { local_ref, field_ref: _ },
 +                    ) => local_ref,
 +                    _ => return,
 +                };
 +            let InFile { file_id, value } = local_ref.source(sema.db);
 +            // locals defined inside macros are not relevant to us
 +            if !file_id.is_macro() {
 +                match value {
 +                    Either::Right(it) => {
 +                        self_param.replace(it);
 +                    }
 +                    Either::Left(_) => {
 +                        res.insert(local_ref);
 +                    }
 +                }
 +            }
 +        };
 +        self.walk_expr(&mut |expr| match expr {
 +            ast::Expr::PathExpr(path_expr) => {
 +                cb(path_expr.path().and_then(|it| it.as_single_name_ref()))
 +            }
 +            ast::Expr::ClosureExpr(closure_expr) => {
 +                if let Some(body) = closure_expr.body() {
 +                    body.syntax().descendants().map(ast::NameRef::cast).for_each(|it| cb(it));
 +                }
 +            }
 +            ast::Expr::MacroExpr(expr) => {
 +                if let Some(tt) = expr.macro_call().and_then(|call| call.token_tree()) {
 +                    tt.syntax()
 +                        .children_with_tokens()
 +                        .flat_map(SyntaxElement::into_token)
 +                        .filter(|it| it.kind() == SyntaxKind::IDENT)
 +                        .flat_map(|t| sema.descend_into_macros(t))
 +                        .for_each(|t| cb(t.parent().and_then(ast::NameRef::cast)));
 +                }
 +            }
 +            _ => (),
 +        });
 +        (res, self_param)
 +    }
 +
 +    fn analyze_container(&self, sema: &Semantics<'_, RootDatabase>) -> Option<ContainerInfo> {
 +        let mut ancestors = self.parent()?.ancestors();
 +        let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
 +        let mut parent_loop = None;
 +        let mut set_parent_loop = |loop_: &dyn ast::HasLoopBody| {
 +            if loop_
 +                .loop_body()
 +                .map_or(false, |it| it.syntax().text_range().contains_range(self.text_range()))
 +            {
 +                parent_loop.get_or_insert(loop_.syntax().clone());
 +            }
 +        };
 +
 +        let (is_const, expr, ty) = loop {
 +            let anc = ancestors.next()?;
 +            break match_ast! {
 +                match anc {
 +                    ast::ClosureExpr(closure) => (false, closure.body(), infer_expr_opt(closure.body())),
 +                    ast::BlockExpr(block_expr) => {
 +                        let (constness, block) = match block_expr.modifier() {
 +                            Some(ast::BlockModifier::Const(_)) => (true, block_expr),
 +                            Some(ast::BlockModifier::Try(_)) => (false, block_expr),
 +                            Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr),
 +                            _ => continue,
 +                        };
 +                        let expr = Some(ast::Expr::BlockExpr(block));
 +                        (constness, expr.clone(), infer_expr_opt(expr))
 +                    },
 +                    ast::Fn(fn_) => {
 +                        let func = sema.to_def(&fn_)?;
 +                        let mut ret_ty = func.ret_type(sema.db);
 +                        if func.is_async(sema.db) {
 +                            if let Some(async_ret) = func.async_ret_type(sema.db) {
 +                                ret_ty = async_ret;
 +                            }
 +                        }
 +                        (fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(ret_ty))
 +                    },
 +                    ast::Static(statik) => {
 +                        (true, statik.body(), Some(sema.to_def(&statik)?.ty(sema.db)))
 +                    },
 +                    ast::ConstArg(ca) => {
 +                        (true, ca.expr(), infer_expr_opt(ca.expr()))
 +                    },
 +                    ast::Const(konst) => {
 +                        (true, konst.body(), Some(sema.to_def(&konst)?.ty(sema.db)))
 +                    },
 +                    ast::ConstParam(cp) => {
 +                        (true, cp.default_val(), Some(sema.to_def(&cp)?.ty(sema.db)))
 +                    },
 +                    ast::ConstBlockPat(cbp) => {
 +                        let expr = cbp.block_expr().map(ast::Expr::BlockExpr);
 +                        (true, expr.clone(), infer_expr_opt(expr))
 +                    },
 +                    ast::Variant(__) => return None,
 +                    ast::Meta(__) => return None,
 +                    ast::LoopExpr(it) => {
 +                        set_parent_loop(&it);
 +                        continue;
 +                    },
 +                    ast::ForExpr(it) => {
 +                        set_parent_loop(&it);
 +                        continue;
 +                    },
 +                    ast::WhileExpr(it) => {
 +                        set_parent_loop(&it);
 +                        continue;
 +                    },
 +                    _ => continue,
 +                }
 +            };
 +        };
 +        let container_tail = match expr? {
 +            ast::Expr::BlockExpr(block) => block.tail_expr(),
 +            expr => Some(expr),
 +        };
 +        let is_in_tail =
 +            container_tail.zip(self.tail_expr()).map_or(false, |(container_tail, body_tail)| {
 +                container_tail.syntax().text_range().contains_range(body_tail.syntax().text_range())
 +            });
 +
 +        let parent = self.parent()?;
 +        let parents = generic_parents(&parent);
 +        let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect();
 +        let where_clauses = parents.iter().filter_map(|it| it.where_clause()).collect();
 +
 +        Some(ContainerInfo {
 +            is_in_tail,
 +            is_const,
 +            parent_loop,
 +            ret_type: ty,
 +            generic_param_lists,
 +            where_clauses,
 +        })
 +    }
 +
 +    fn return_ty(&self, ctx: &AssistContext<'_>) -> Option<RetType> {
 +        match self.tail_expr() {
 +            Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::original).map(RetType::Expr),
 +            None => Some(RetType::Stmt),
 +        }
 +    }
 +
 +    /// Local variables defined inside `body` that are accessed outside of it
 +    fn ret_values<'a>(
 +        &self,
 +        ctx: &'a AssistContext<'_>,
 +        parent: &SyntaxNode,
 +    ) -> impl Iterator<Item = OutlivedLocal> + 'a {
 +        let parent = parent.clone();
 +        let range = self.text_range();
 +        locals_defined_in_body(&ctx.sema, self)
 +            .into_iter()
 +            .filter_map(move |local| local_outlives_body(ctx, range, local, &parent))
 +    }
 +
 +    /// Analyses the function body for external control flow.
 +    fn external_control_flow(
 +        &self,
 +        ctx: &AssistContext<'_>,
 +        container_info: &ContainerInfo,
 +    ) -> Option<ControlFlow> {
 +        let mut ret_expr = None;
 +        let mut try_expr = None;
 +        let mut break_expr = None;
 +        let mut continue_expr = None;
 +        let mut is_async = false;
 +        let mut _is_unsafe = false;
 +
 +        let mut unsafe_depth = 0;
 +        let mut loop_depth = 0;
 +
 +        self.preorder_expr(&mut |expr| {
 +            let expr = match expr {
 +                WalkEvent::Enter(e) => e,
 +                WalkEvent::Leave(expr) => {
 +                    match expr {
 +                        ast::Expr::LoopExpr(_)
 +                        | ast::Expr::ForExpr(_)
 +                        | ast::Expr::WhileExpr(_) => loop_depth -= 1,
 +                        ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
 +                            unsafe_depth -= 1
 +                        }
 +                        _ => (),
 +                    }
 +                    return false;
 +                }
 +            };
 +            match expr {
 +                ast::Expr::LoopExpr(_) | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) => {
 +                    loop_depth += 1;
 +                }
 +                ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
 +                    unsafe_depth += 1
 +                }
 +                ast::Expr::ReturnExpr(it) => {
 +                    ret_expr = Some(it);
 +                }
 +                ast::Expr::TryExpr(it) => {
 +                    try_expr = Some(it);
 +                }
 +                ast::Expr::BreakExpr(it) if loop_depth == 0 => {
 +                    break_expr = Some(it);
 +                }
 +                ast::Expr::ContinueExpr(it) if loop_depth == 0 => {
 +                    continue_expr = Some(it);
 +                }
 +                ast::Expr::AwaitExpr(_) => is_async = true,
 +                // FIXME: Do unsafe analysis on expression, sem highlighting knows this so we should be able
 +                // to just lift that out of there
 +                // expr if unsafe_depth ==0 && expr.is_unsafe => is_unsafe = true,
 +                _ => {}
 +            }
 +            false
 +        });
 +
 +        let kind = match (try_expr, ret_expr, break_expr, continue_expr) {
 +            (Some(_), _, None, None) => {
 +                let ret_ty = container_info.ret_type.clone()?;
 +                let kind = TryKind::of_ty(ret_ty, ctx)?;
 +
 +                Some(FlowKind::Try { kind })
 +            }
 +            (Some(_), _, _, _) => {
 +                cov_mark::hit!(external_control_flow_try_and_bc);
 +                return None;
 +            }
 +            (None, Some(r), None, None) => Some(FlowKind::Return(r.expr())),
 +            (None, Some(_), _, _) => {
 +                cov_mark::hit!(external_control_flow_return_and_bc);
 +                return None;
 +            }
 +            (None, None, Some(_), Some(_)) => {
 +                cov_mark::hit!(external_control_flow_break_and_continue);
 +                return None;
 +            }
 +            (None, None, Some(b), None) => Some(FlowKind::Break(b.lifetime(), b.expr())),
 +            (None, None, None, Some(c)) => Some(FlowKind::Continue(c.lifetime())),
 +            (None, None, None, None) => None,
 +        };
 +
 +        Some(ControlFlow { kind, is_async, is_unsafe: _is_unsafe })
 +    }
 +
 +    /// find variables that should be extracted as params
 +    ///
 +    /// Computes additional info that affects param type and mutability
 +    fn extracted_function_params(
 +        &self,
 +        ctx: &AssistContext<'_>,
 +        container_info: &ContainerInfo,
 +        locals: impl Iterator<Item = Local>,
 +    ) -> Vec<Param> {
 +        locals
 +            .map(|local| (local, local.source(ctx.db())))
 +            .filter(|(_, src)| is_defined_outside_of_body(ctx, self, src))
 +            .filter_map(|(local, src)| match src.value {
 +                Either::Left(src) => Some((local, src)),
 +                Either::Right(_) => {
 +                    stdx::never!(false, "Local::is_self returned false, but source is SelfParam");
 +                    None
 +                }
 +            })
 +            .map(|(var, src)| {
 +                let usages = LocalUsages::find_local_usages(ctx, var);
 +                let ty = var.ty(ctx.db());
 +
 +                let defined_outside_parent_loop = container_info
 +                    .parent_loop
 +                    .as_ref()
 +                    .map_or(true, |it| it.text_range().contains_range(src.syntax().text_range()));
 +
 +                let is_copy = ty.is_copy(ctx.db());
 +                let has_usages = self.has_usages_after_body(&usages);
 +                let requires_mut =
 +                    !ty.is_mutable_reference() && has_exclusive_usages(ctx, &usages, self);
 +                // We can move the value into the function call if it's not used after the call,
 +                // if the var is not used but defined outside a loop we are extracting from we can't move it either
 +                // as the function will reuse it in the next iteration.
 +                let move_local = (!has_usages && defined_outside_parent_loop) || ty.is_reference();
 +                Param { var, ty, move_local, requires_mut, is_copy }
 +            })
 +            .collect()
 +    }
 +
 +    fn has_usages_after_body(&self, usages: &LocalUsages) -> bool {
 +        usages.iter().any(|reference| self.precedes_range(reference.range))
 +    }
 +}
 +
 +enum GenericParent {
 +    Fn(ast::Fn),
 +    Impl(ast::Impl),
 +    Trait(ast::Trait),
 +}
 +
 +impl GenericParent {
 +    fn generic_param_list(&self) -> Option<ast::GenericParamList> {
 +        match self {
 +            GenericParent::Fn(fn_) => fn_.generic_param_list(),
 +            GenericParent::Impl(impl_) => impl_.generic_param_list(),
 +            GenericParent::Trait(trait_) => trait_.generic_param_list(),
 +        }
 +    }
 +
 +    fn where_clause(&self) -> Option<ast::WhereClause> {
 +        match self {
 +            GenericParent::Fn(fn_) => fn_.where_clause(),
 +            GenericParent::Impl(impl_) => impl_.where_clause(),
 +            GenericParent::Trait(trait_) => trait_.where_clause(),
 +        }
 +    }
 +}
 +
 +/// Search `parent`'s ancestors for items with potentially applicable generic parameters
 +fn generic_parents(parent: &SyntaxNode) -> Vec<GenericParent> {
 +    let mut list = Vec::new();
 +    if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) {
 +        match parent_item {
 +            ast::Item::Fn(ref fn_) => {
 +                if let Some(parent_parent) = parent_item
 +                    .syntax()
 +                    .parent()
 +                    .and_then(|it| it.parent())
 +                    .and_then(ast::Item::cast)
 +                {
 +                    match parent_parent {
 +                        ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
 +                        ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
 +                        _ => (),
 +                    }
 +                }
 +                list.push(GenericParent::Fn(fn_.clone()));
 +            }
 +            _ => (),
 +        }
 +    }
 +    list
 +}
 +
 +/// checks if relevant var is used with `&mut` access inside body
 +fn has_exclusive_usages(
 +    ctx: &AssistContext<'_>,
 +    usages: &LocalUsages,
 +    body: &FunctionBody,
 +) -> bool {
 +    usages
 +        .iter()
 +        .filter(|reference| body.contains_range(reference.range))
 +        .any(|reference| reference_is_exclusive(reference, body, ctx))
 +}
 +
 +/// checks if this reference requires `&mut` access inside node
 +fn reference_is_exclusive(
 +    reference: &FileReference,
 +    node: &dyn HasTokenAtOffset,
 +    ctx: &AssistContext<'_>,
 +) -> bool {
 +    // we directly modify variable with set: `n = 0`, `n += 1`
 +    if reference.category == Some(ReferenceCategory::Write) {
 +        return true;
 +    }
 +
 +    // we take `&mut` reference to variable: `&mut v`
 +    let path = match path_element_of_reference(node, reference) {
 +        Some(path) => path,
 +        None => return false,
 +    };
 +
 +    expr_require_exclusive_access(ctx, &path).unwrap_or(false)
 +}
 +
 +/// checks if this expr requires `&mut` access, recurses on field access
 +fn expr_require_exclusive_access(ctx: &AssistContext<'_>, expr: &ast::Expr) -> Option<bool> {
 +    if let ast::Expr::MacroExpr(_) = expr {
 +        // FIXME: expand macro and check output for mutable usages of the variable?
 +        return None;
 +    }
 +
 +    let parent = expr.syntax().parent()?;
 +
 +    if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
 +        if matches!(bin_expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
 +            return Some(bin_expr.lhs()?.syntax() == expr.syntax());
 +        }
 +        return Some(false);
 +    }
 +
 +    if let Some(ref_expr) = ast::RefExpr::cast(parent.clone()) {
 +        return Some(ref_expr.mut_token().is_some());
 +    }
 +
 +    if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
 +        let func = ctx.sema.resolve_method_call(&method_call)?;
 +        let self_param = func.self_param(ctx.db())?;
 +        let access = self_param.access(ctx.db());
 +
 +        return Some(matches!(access, hir::Access::Exclusive));
 +    }
 +
 +    if let Some(field) = ast::FieldExpr::cast(parent) {
 +        return expr_require_exclusive_access(ctx, &field.into());
 +    }
 +
 +    Some(false)
 +}
 +
 +trait HasTokenAtOffset {
 +    fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken>;
 +}
 +
 +impl HasTokenAtOffset for SyntaxNode {
 +    fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
 +        SyntaxNode::token_at_offset(self, offset)
 +    }
 +}
 +
 +impl HasTokenAtOffset for FunctionBody {
 +    fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
 +        match self {
 +            FunctionBody::Expr(expr) => expr.syntax().token_at_offset(offset),
 +            FunctionBody::Span { parent, text_range } => {
 +                match parent.syntax().token_at_offset(offset) {
 +                    TokenAtOffset::None => TokenAtOffset::None,
 +                    TokenAtOffset::Single(t) => {
 +                        if text_range.contains_range(t.text_range()) {
 +                            TokenAtOffset::Single(t)
 +                        } else {
 +                            TokenAtOffset::None
 +                        }
 +                    }
 +                    TokenAtOffset::Between(a, b) => {
 +                        match (
 +                            text_range.contains_range(a.text_range()),
 +                            text_range.contains_range(b.text_range()),
 +                        ) {
 +                            (true, true) => TokenAtOffset::Between(a, b),
 +                            (true, false) => TokenAtOffset::Single(a),
 +                            (false, true) => TokenAtOffset::Single(b),
 +                            (false, false) => TokenAtOffset::None,
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// find relevant `ast::Expr` for reference
 +///
 +/// # Preconditions
 +///
 +/// `node` must cover `reference`, that is `node.text_range().contains_range(reference.range)`
 +fn path_element_of_reference(
 +    node: &dyn HasTokenAtOffset,
 +    reference: &FileReference,
 +) -> Option<ast::Expr> {
 +    let token = node.token_at_offset(reference.range.start()).right_biased().or_else(|| {
 +        stdx::never!(false, "cannot find token at variable usage: {:?}", reference);
 +        None
 +    })?;
 +    let path = token.parent_ancestors().find_map(ast::Expr::cast).or_else(|| {
 +        stdx::never!(false, "cannot find path parent of variable usage: {:?}", token);
 +        None
 +    })?;
 +    stdx::always!(
 +        matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroExpr(_)),
 +        "unexpected expression type for variable usage: {:?}",
 +        path
 +    );
 +    Some(path)
 +}
 +
 +/// list local variables defined inside `body`
 +fn locals_defined_in_body(
 +    sema: &Semantics<'_, RootDatabase>,
 +    body: &FunctionBody,
 +) -> FxIndexSet<Local> {
 +    // FIXME: this doesn't work well with macros
 +    //        see https://github.com/rust-lang/rust-analyzer/pull/7535#discussion_r570048550
 +    let mut res = FxIndexSet::default();
 +    body.walk_pat(&mut |pat| {
 +        if let ast::Pat::IdentPat(pat) = pat {
 +            if let Some(local) = sema.to_def(&pat) {
 +                res.insert(local);
 +            }
 +        }
 +    });
 +    res
 +}
 +
 +/// Returns usage details if local variable is used after(outside of) body
 +fn local_outlives_body(
 +    ctx: &AssistContext<'_>,
 +    body_range: TextRange,
 +    local: Local,
 +    parent: &SyntaxNode,
 +) -> Option<OutlivedLocal> {
 +    let usages = LocalUsages::find_local_usages(ctx, local);
 +    let mut has_mut_usages = false;
 +    let mut any_outlives = false;
 +    for usage in usages.iter() {
 +        if body_range.end() <= usage.range.start() {
 +            has_mut_usages |= reference_is_exclusive(usage, parent, ctx);
 +            any_outlives |= true;
 +            if has_mut_usages {
 +                break; // no need to check more elements we have all the info we wanted
 +            }
 +        }
 +    }
 +    if !any_outlives {
 +        return None;
 +    }
 +    Some(OutlivedLocal { local, mut_usage_outside_body: has_mut_usages })
 +}
 +
 +/// checks if the relevant local was defined before(outside of) body
 +fn is_defined_outside_of_body(
 +    ctx: &AssistContext<'_>,
 +    body: &FunctionBody,
 +    src: &hir::InFile<Either<ast::IdentPat, ast::SelfParam>>,
 +) -> bool {
 +    src.file_id.original_file(ctx.db()) == ctx.file_id()
 +        && !body.contains_node(either_syntax(&src.value))
 +}
 +
 +fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode {
 +    match value {
 +        Either::Left(pat) => pat.syntax(),
 +        Either::Right(it) => it.syntax(),
 +    }
 +}
 +
 +/// find where to put extracted function definition
 +///
 +/// Function should be put right after returned node
 +fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNode> {
 +    let node = body.node();
 +    let mut ancestors = node.ancestors().peekable();
 +    let mut last_ancestor = None;
 +    while let Some(next_ancestor) = ancestors.next() {
 +        match next_ancestor.kind() {
 +            SyntaxKind::SOURCE_FILE => break,
 +            SyntaxKind::ITEM_LIST if !matches!(anchor, Anchor::Freestanding) => continue,
 +            SyntaxKind::ITEM_LIST => {
 +                if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) {
 +                    break;
 +                }
 +            }
 +            SyntaxKind::ASSOC_ITEM_LIST if !matches!(anchor, Anchor::Method) => continue,
 +            SyntaxKind::ASSOC_ITEM_LIST if body.extracted_from_trait_impl() => continue,
 +            SyntaxKind::ASSOC_ITEM_LIST => {
 +                if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::IMPL) {
 +                    break;
 +                }
 +            }
 +            _ => (),
 +        }
 +        last_ancestor = Some(next_ancestor);
 +    }
 +    last_ancestor
 +}
 +
 +fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String {
 +    let ret_ty = fun.return_type(ctx);
 +
 +    let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx)));
 +    let name = fun.name.clone();
 +    let mut call_expr = if fun.self_param.is_some() {
 +        let self_arg = make::expr_path(make::ext::ident_path("self"));
 +        make::expr_method_call(self_arg, name, args)
 +    } else {
 +        let func = make::expr_path(make::path_unqualified(make::path_segment(name)));
 +        make::expr_call(func, args)
 +    };
 +
 +    let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
 +
 +    if fun.control_flow.is_async {
 +        call_expr = make::expr_await(call_expr);
 +    }
 +    let expr = handler.make_call_expr(call_expr).indent(indent);
 +
 +    let mut_modifier = |var: &OutlivedLocal| if var.mut_usage_outside_body { "mut " } else { "" };
 +
 +    let mut buf = String::new();
 +    match fun.outliving_locals.as_slice() {
 +        [] => {}
 +        [var] => {
 +            format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()))
 +        }
 +        vars => {
 +            buf.push_str("let (");
 +            let bindings = vars.iter().format_with(", ", |local, f| {
 +                f(&format_args!("{}{}", mut_modifier(local), local.local.name(ctx.db())))
 +            });
 +            format_to!(buf, "{}", bindings);
 +            buf.push_str(") = ");
 +        }
 +    }
 +
 +    format_to!(buf, "{}", expr);
 +    let insert_comma = fun
 +        .body
 +        .parent()
 +        .and_then(ast::MatchArm::cast)
 +        .map_or(false, |it| it.comma_token().is_none());
 +    if insert_comma {
 +        buf.push(',');
 +    } else if fun.ret_ty.is_unit() && (!fun.outliving_locals.is_empty() || !expr.is_block_like()) {
 +        buf.push(';');
 +    }
 +    buf
 +}
 +
 +enum FlowHandler {
 +    None,
 +    Try { kind: TryKind },
 +    If { action: FlowKind },
 +    IfOption { action: FlowKind },
 +    MatchOption { none: FlowKind },
 +    MatchResult { err: FlowKind },
 +}
 +
 +impl FlowHandler {
 +    fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
 +        match &fun.control_flow.kind {
 +            None => FlowHandler::None,
 +            Some(flow_kind) => {
 +                let action = flow_kind.clone();
 +                if *ret_ty == FunType::Unit {
 +                    match flow_kind {
 +                        FlowKind::Return(None)
 +                        | FlowKind::Break(_, None)
 +                        | FlowKind::Continue(_) => FlowHandler::If { action },
 +                        FlowKind::Return(_) | FlowKind::Break(_, _) => {
 +                            FlowHandler::IfOption { action }
 +                        }
 +                        FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
 +                    }
 +                } else {
 +                    match flow_kind {
 +                        FlowKind::Return(None)
 +                        | FlowKind::Break(_, None)
 +                        | FlowKind::Continue(_) => FlowHandler::MatchOption { none: action },
 +                        FlowKind::Return(_) | FlowKind::Break(_, _) => {
 +                            FlowHandler::MatchResult { err: action }
 +                        }
 +                        FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn make_call_expr(&self, call_expr: ast::Expr) -> ast::Expr {
 +        match self {
 +            FlowHandler::None => call_expr,
 +            FlowHandler::Try { kind: _ } => make::expr_try(call_expr),
 +            FlowHandler::If { action } => {
 +                let action = action.make_result_handler(None);
 +                let stmt = make::expr_stmt(action);
 +                let block = make::block_expr(iter::once(stmt.into()), None);
 +                let controlflow_break_path = make::path_from_text("ControlFlow::Break");
 +                let condition = make::expr_let(
 +                    make::tuple_struct_pat(
 +                        controlflow_break_path,
 +                        iter::once(make::wildcard_pat().into()),
 +                    )
 +                    .into(),
 +                    call_expr,
 +                );
 +                make::expr_if(condition.into(), block, None)
 +            }
 +            FlowHandler::IfOption { action } => {
 +                let path = make::ext::ident_path("Some");
 +                let value_pat = make::ext::simple_ident_pat(make::name("value"));
 +                let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
 +                let cond = make::expr_let(pattern.into(), call_expr);
 +                let value = make::expr_path(make::ext::ident_path("value"));
 +                let action_expr = action.make_result_handler(Some(value));
 +                let action_stmt = make::expr_stmt(action_expr);
 +                let then = make::block_expr(iter::once(action_stmt.into()), None);
 +                make::expr_if(cond.into(), then, None)
 +            }
 +            FlowHandler::MatchOption { none } => {
 +                let some_name = "value";
 +
 +                let some_arm = {
 +                    let path = make::ext::ident_path("Some");
 +                    let value_pat = make::ext::simple_ident_pat(make::name(some_name));
 +                    let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
 +                    let value = make::expr_path(make::ext::ident_path(some_name));
 +                    make::match_arm(iter::once(pat.into()), None, value)
 +                };
 +                let none_arm = {
 +                    let path = make::ext::ident_path("None");
 +                    let pat = make::path_pat(path);
 +                    make::match_arm(iter::once(pat), None, none.make_result_handler(None))
 +                };
 +                let arms = make::match_arm_list(vec![some_arm, none_arm]);
 +                make::expr_match(call_expr, arms)
 +            }
 +            FlowHandler::MatchResult { err } => {
 +                let ok_name = "value";
 +                let err_name = "value";
 +
 +                let ok_arm = {
 +                    let path = make::ext::ident_path("Ok");
 +                    let value_pat = make::ext::simple_ident_pat(make::name(ok_name));
 +                    let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
 +                    let value = make::expr_path(make::ext::ident_path(ok_name));
 +                    make::match_arm(iter::once(pat.into()), None, value)
 +                };
 +                let err_arm = {
 +                    let path = make::ext::ident_path("Err");
 +                    let value_pat = make::ext::simple_ident_pat(make::name(err_name));
 +                    let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
 +                    let value = make::expr_path(make::ext::ident_path(err_name));
 +                    make::match_arm(
 +                        iter::once(pat.into()),
 +                        None,
 +                        err.make_result_handler(Some(value)),
 +                    )
 +                };
 +                let arms = make::match_arm_list(vec![ok_arm, err_arm]);
 +                make::expr_match(call_expr, arms)
 +            }
 +        }
 +    }
 +}
 +
 +fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local) -> ast::Expr {
 +    let name = var.name(ctx.db()).to_string();
 +    make::expr_path(make::ext::ident_path(&name))
 +}
 +
 +fn format_function(
 +    ctx: &AssistContext<'_>,
 +    module: hir::Module,
 +    fun: &Function,
 +    old_indent: IndentLevel,
 +    new_indent: IndentLevel,
 +) -> String {
 +    let mut fn_def = String::new();
 +    let params = fun.make_param_list(ctx, module);
 +    let ret_ty = fun.make_ret_ty(ctx, module);
 +    let body = make_body(ctx, old_indent, new_indent, fun);
 +    let const_kw = if fun.mods.is_const { "const " } else { "" };
 +    let async_kw = if fun.control_flow.is_async { "async " } else { "" };
 +    let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
 +    let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
 +    match ctx.config.snippet_cap {
 +        Some(_) => format_to!(
 +            fn_def,
 +            "\n\n{}{}{}{}fn $0{}",
 +            new_indent,
 +            const_kw,
 +            async_kw,
 +            unsafe_kw,
 +            fun.name,
 +        ),
 +        None => format_to!(
 +            fn_def,
 +            "\n\n{}{}{}{}fn {}",
 +            new_indent,
 +            const_kw,
 +            async_kw,
 +            unsafe_kw,
 +            fun.name,
 +        ),
 +    }
 +
 +    if let Some(generic_params) = generic_params {
 +        format_to!(fn_def, "{}", generic_params);
 +    }
 +
 +    format_to!(fn_def, "{}", params);
 +
 +    if let Some(ret_ty) = ret_ty {
 +        format_to!(fn_def, " {}", ret_ty);
 +    }
 +
 +    if let Some(where_clause) = where_clause {
 +        format_to!(fn_def, " {}", where_clause);
 +    }
 +
 +    format_to!(fn_def, " {}", body);
 +
 +    fn_def
 +}
 +
 +fn make_generic_params_and_where_clause(
 +    ctx: &AssistContext<'_>,
 +    fun: &Function,
 +) -> (Option<ast::GenericParamList>, Option<ast::WhereClause>) {
 +    let used_type_params = fun.type_params(ctx);
 +
 +    let generic_param_list = make_generic_param_list(ctx, fun, &used_type_params);
 +    let where_clause = make_where_clause(ctx, fun, &used_type_params);
 +
 +    (generic_param_list, where_clause)
 +}
 +
 +fn make_generic_param_list(
 +    ctx: &AssistContext<'_>,
 +    fun: &Function,
 +    used_type_params: &[TypeParam],
 +) -> Option<ast::GenericParamList> {
 +    let mut generic_params = fun
 +        .mods
 +        .generic_param_lists
 +        .iter()
 +        .flat_map(|parent_params| {
 +            parent_params
 +                .generic_params()
 +                .filter(|param| param_is_required(ctx, param, used_type_params))
 +        })
 +        .peekable();
 +
 +    if generic_params.peek().is_some() {
 +        Some(make::generic_param_list(generic_params))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn param_is_required(
 +    ctx: &AssistContext<'_>,
 +    param: &ast::GenericParam,
 +    used_type_params: &[TypeParam],
 +) -> bool {
 +    match param {
 +        ast::GenericParam::ConstParam(_) | ast::GenericParam::LifetimeParam(_) => false,
 +        ast::GenericParam::TypeParam(type_param) => match &ctx.sema.to_def(type_param) {
 +            Some(def) => used_type_params.contains(def),
 +            _ => false,
 +        },
 +    }
 +}
 +
 +fn make_where_clause(
 +    ctx: &AssistContext<'_>,
 +    fun: &Function,
 +    used_type_params: &[TypeParam],
 +) -> Option<ast::WhereClause> {
 +    let mut predicates = fun
 +        .mods
 +        .where_clauses
 +        .iter()
 +        .flat_map(|parent_where_clause| {
 +            parent_where_clause
 +                .predicates()
 +                .filter(|pred| pred_is_required(ctx, pred, used_type_params))
 +        })
 +        .peekable();
 +
 +    if predicates.peek().is_some() {
 +        Some(make::where_clause(predicates))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn pred_is_required(
 +    ctx: &AssistContext<'_>,
 +    pred: &ast::WherePred,
 +    used_type_params: &[TypeParam],
 +) -> bool {
 +    match resolved_type_param(ctx, pred) {
 +        Some(it) => used_type_params.contains(&it),
 +        None => false,
 +    }
 +}
 +
 +fn resolved_type_param(ctx: &AssistContext<'_>, pred: &ast::WherePred) -> Option<TypeParam> {
 +    let path = match pred.ty()? {
 +        ast::Type::PathType(path_type) => path_type.path(),
 +        _ => None,
 +    }?;
 +
 +    match ctx.sema.resolve_path(&path)? {
 +        PathResolution::TypeParam(type_param) => Some(type_param),
 +        _ => None,
 +    }
 +}
 +
 +impl Function {
 +    /// Collect all the `TypeParam`s used in the `body` and `params`.
 +    fn type_params(&self, ctx: &AssistContext<'_>) -> Vec<TypeParam> {
 +        let type_params_in_descendant_paths =
 +            self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
 +                Some(PathResolution::TypeParam(type_param)) => Some(type_param),
 +                _ => None,
 +            });
 +        let type_params_in_params = self.params.iter().filter_map(|p| p.ty.as_type_param(ctx.db()));
 +        type_params_in_descendant_paths.chain(type_params_in_params).collect()
 +    }
 +
 +    fn make_param_list(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::ParamList {
 +        let self_param = self.self_param.clone();
 +        let params = self.params.iter().map(|param| param.to_param(ctx, module));
 +        make::param_list(self_param, params)
 +    }
 +
 +    fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option<ast::RetType> {
 +        let fun_ty = self.return_type(ctx);
 +        let handler = if self.mods.is_in_tail {
 +            FlowHandler::None
 +        } else {
 +            FlowHandler::from_ret_ty(self, &fun_ty)
 +        };
 +        let ret_ty = match &handler {
 +            FlowHandler::None => {
 +                if matches!(fun_ty, FunType::Unit) {
 +                    return None;
 +                }
 +                fun_ty.make_ty(ctx, module)
 +            }
 +            FlowHandler::Try { kind: TryKind::Option } => {
 +                make::ext::ty_option(fun_ty.make_ty(ctx, module))
 +            }
 +            FlowHandler::Try { kind: TryKind::Result { ty: parent_ret_ty } } => {
 +                let handler_ty = parent_ret_ty
 +                    .type_arguments()
 +                    .nth(1)
 +                    .map(|ty| make_ty(&ty, ctx, module))
 +                    .unwrap_or_else(make::ty_placeholder);
 +                make::ext::ty_result(fun_ty.make_ty(ctx, module), handler_ty)
 +            }
 +            FlowHandler::If { .. } => make::ty("ControlFlow<()>"),
 +            FlowHandler::IfOption { action } => {
 +                let handler_ty = action
 +                    .expr_ty(ctx)
 +                    .map(|ty| make_ty(&ty, ctx, module))
 +                    .unwrap_or_else(make::ty_placeholder);
 +                make::ext::ty_option(handler_ty)
 +            }
 +            FlowHandler::MatchOption { .. } => make::ext::ty_option(fun_ty.make_ty(ctx, module)),
 +            FlowHandler::MatchResult { err } => {
 +                let handler_ty = err
 +                    .expr_ty(ctx)
 +                    .map(|ty| make_ty(&ty, ctx, module))
 +                    .unwrap_or_else(make::ty_placeholder);
 +                make::ext::ty_result(fun_ty.make_ty(ctx, module), handler_ty)
 +            }
 +        };
 +        Some(make::ret_type(ret_ty))
 +    }
 +}
 +
 +impl FunType {
 +    fn make_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
 +        match self {
 +            FunType::Unit => make::ty_unit(),
 +            FunType::Single(ty) => make_ty(ty, ctx, module),
 +            FunType::Tuple(types) => match types.as_slice() {
 +                [] => {
 +                    stdx::never!("tuple type with 0 elements");
 +                    make::ty_unit()
 +                }
 +                [ty] => {
 +                    stdx::never!("tuple type with 1 element");
 +                    make_ty(ty, ctx, module)
 +                }
 +                types => {
 +                    let types = types.iter().map(|ty| make_ty(ty, ctx, module));
 +                    make::ty_tuple(types)
 +                }
 +            },
 +        }
 +    }
 +}
 +
 +fn make_body(
 +    ctx: &AssistContext<'_>,
 +    old_indent: IndentLevel,
 +    new_indent: IndentLevel,
 +    fun: &Function,
 +) -> ast::BlockExpr {
 +    let ret_ty = fun.return_type(ctx);
 +    let handler = if fun.mods.is_in_tail {
 +        FlowHandler::None
 +    } else {
 +        FlowHandler::from_ret_ty(fun, &ret_ty)
 +    };
 +
 +    let block = match &fun.body {
 +        FunctionBody::Expr(expr) => {
 +            let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
 +            let expr = ast::Expr::cast(expr).unwrap();
 +            match expr {
 +                ast::Expr::BlockExpr(block) => {
 +                    // If the extracted expression is itself a block, there is no need to wrap it inside another block.
 +                    let block = block.dedent(old_indent);
 +                    // Recreate the block for formatting consistency with other extracted functions.
 +                    make::block_expr(block.statements(), block.tail_expr())
 +                }
 +                _ => {
 +                    let expr = expr.dedent(old_indent).indent(IndentLevel(1));
 +
 +                    make::block_expr(Vec::new(), Some(expr))
 +                }
 +            }
 +        }
 +        FunctionBody::Span { parent, text_range } => {
 +            let mut elements: Vec<_> = parent
 +                .syntax()
 +                .children_with_tokens()
 +                .filter(|it| text_range.contains_range(it.text_range()))
 +                .map(|it| match &it {
 +                    syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
 +                        rewrite_body_segment(ctx, &fun.params, &handler, n),
 +                    ),
 +                    _ => it,
 +                })
 +                .collect();
 +
 +            let mut tail_expr = match &elements.last() {
 +                Some(syntax::NodeOrToken::Node(node)) if ast::Expr::can_cast(node.kind()) => {
 +                    ast::Expr::cast(node.clone())
 +                }
 +                _ => None,
 +            };
 +
 +            match tail_expr {
 +                Some(_) => {
 +                    elements.pop();
 +                }
 +                None => match fun.outliving_locals.as_slice() {
 +                    [] => {}
 +                    [var] => {
 +                        tail_expr = Some(path_expr_from_local(ctx, var.local));
 +                    }
 +                    vars => {
 +                        let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local));
 +                        let expr = make::expr_tuple(exprs);
 +                        tail_expr = Some(expr);
 +                    }
 +                },
 +            };
 +
 +            let body_indent = IndentLevel(1);
 +            let elements = elements
 +                .into_iter()
 +                .map(|node_or_token| match &node_or_token {
 +                    syntax::NodeOrToken::Node(node) => match ast::Stmt::cast(node.clone()) {
 +                        Some(stmt) => {
 +                            let indented = stmt.dedent(old_indent).indent(body_indent);
 +                            let ast_node = indented.syntax().clone_subtree();
 +                            syntax::NodeOrToken::Node(ast_node)
 +                        }
 +                        _ => node_or_token,
 +                    },
 +                    _ => node_or_token,
 +                })
 +                .collect::<Vec<SyntaxElement>>();
 +            let tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent));
 +
 +            make::hacky_block_expr_with_comments(elements, tail_expr)
 +        }
 +    };
 +
 +    let block = match &handler {
 +        FlowHandler::None => block,
 +        FlowHandler::Try { kind } => {
 +            let block = with_default_tail_expr(block, make::expr_unit());
 +            map_tail_expr(block, |tail_expr| {
 +                let constructor = match kind {
 +                    TryKind::Option => "Some",
 +                    TryKind::Result { .. } => "Ok",
 +                };
 +                let func = make::expr_path(make::ext::ident_path(constructor));
 +                let args = make::arg_list(iter::once(tail_expr));
 +                make::expr_call(func, args)
 +            })
 +        }
 +        FlowHandler::If { .. } => {
 +            let controlflow_continue = make::expr_call(
 +                make::expr_path(make::path_from_text("ControlFlow::Continue")),
 +                make::arg_list(iter::once(make::expr_unit())),
 +            );
 +            with_tail_expr(block, controlflow_continue)
 +        }
 +        FlowHandler::IfOption { .. } => {
 +            let none = make::expr_path(make::ext::ident_path("None"));
 +            with_tail_expr(block, none)
 +        }
 +        FlowHandler::MatchOption { .. } => map_tail_expr(block, |tail_expr| {
 +            let some = make::expr_path(make::ext::ident_path("Some"));
 +            let args = make::arg_list(iter::once(tail_expr));
 +            make::expr_call(some, args)
 +        }),
 +        FlowHandler::MatchResult { .. } => map_tail_expr(block, |tail_expr| {
 +            let ok = make::expr_path(make::ext::ident_path("Ok"));
 +            let args = make::arg_list(iter::once(tail_expr));
 +            make::expr_call(ok, args)
 +        }),
 +    };
 +
 +    block.indent(new_indent)
 +}
 +
 +fn map_tail_expr(block: ast::BlockExpr, f: impl FnOnce(ast::Expr) -> ast::Expr) -> ast::BlockExpr {
 +    let tail_expr = match block.tail_expr() {
 +        Some(tail_expr) => tail_expr,
 +        None => return block,
 +    };
 +    make::block_expr(block.statements(), Some(f(tail_expr)))
 +}
 +
 +fn with_default_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr {
 +    match block.tail_expr() {
 +        Some(_) => block,
 +        None => make::block_expr(block.statements(), Some(tail_expr)),
 +    }
 +}
 +
 +fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr {
 +    let stmt_tail = block.tail_expr().map(|expr| make::expr_stmt(expr).into());
 +    let stmts = block.statements().chain(stmt_tail);
 +    make::block_expr(stmts, Some(tail_expr))
 +}
 +
 +fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String {
 +    ty.display_source_code(ctx.db(), module.into()).ok().unwrap_or_else(|| "_".to_string())
 +}
 +
 +fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
 +    let ty_str = format_type(ty, ctx, module);
 +    make::ty(&ty_str)
 +}
 +
 +fn rewrite_body_segment(
 +    ctx: &AssistContext<'_>,
 +    params: &[Param],
 +    handler: &FlowHandler,
 +    syntax: &SyntaxNode,
 +) -> SyntaxNode {
 +    let syntax = fix_param_usages(ctx, params, syntax);
 +    update_external_control_flow(handler, &syntax);
 +    syntax
 +}
 +
 +/// change all usages to account for added `&`/`&mut` for some params
 +fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode {
 +    let mut usages_for_param: Vec<(&Param, Vec<ast::Expr>)> = Vec::new();
 +
 +    let tm = TreeMutator::new(syntax);
 +
 +    for param in params {
 +        if !param.kind().is_ref() {
 +            continue;
 +        }
 +
 +        let usages = LocalUsages::find_local_usages(ctx, param.var);
 +        let usages = usages
 +            .iter()
 +            .filter(|reference| syntax.text_range().contains_range(reference.range))
 +            .filter_map(|reference| path_element_of_reference(syntax, reference))
 +            .map(|expr| tm.make_mut(&expr));
 +
 +        usages_for_param.push((param, usages.collect()));
 +    }
 +
 +    let res = tm.make_syntax_mut(syntax);
 +
 +    for (param, usages) in usages_for_param {
 +        for usage in usages {
 +            match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
 +                Some(ast::Expr::MethodCallExpr(_) | ast::Expr::FieldExpr(_)) => {
 +                    // do nothing
 +                }
 +                Some(ast::Expr::RefExpr(node))
 +                    if param.kind() == ParamKind::MutRef && node.mut_token().is_some() =>
 +                {
 +                    ted::replace(node.syntax(), node.expr().unwrap().syntax());
 +                }
 +                Some(ast::Expr::RefExpr(node))
 +                    if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() =>
 +                {
 +                    ted::replace(node.syntax(), node.expr().unwrap().syntax());
 +                }
 +                Some(_) | None => {
 +                    let p = &make::expr_prefix(T![*], usage.clone()).clone_for_update();
 +                    ted::replace(usage.syntax(), p.syntax())
 +                }
 +            }
 +        }
 +    }
 +
 +    res
 +}
 +
 +fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
 +    let mut nested_loop = None;
 +    let mut nested_scope = None;
 +    for event in syntax.preorder() {
 +        match event {
 +            WalkEvent::Enter(e) => match e.kind() {
 +                SyntaxKind::LOOP_EXPR | SyntaxKind::WHILE_EXPR | SyntaxKind::FOR_EXPR => {
 +                    if nested_loop.is_none() {
 +                        nested_loop = Some(e.clone());
 +                    }
 +                }
 +                SyntaxKind::FN
 +                | SyntaxKind::CONST
 +                | SyntaxKind::STATIC
 +                | SyntaxKind::IMPL
 +                | SyntaxKind::MODULE => {
 +                    if nested_scope.is_none() {
 +                        nested_scope = Some(e.clone());
 +                    }
 +                }
 +                _ => {}
 +            },
 +            WalkEvent::Leave(e) => {
 +                if nested_scope.is_none() {
 +                    if let Some(expr) = ast::Expr::cast(e.clone()) {
 +                        match expr {
 +                            ast::Expr::ReturnExpr(return_expr) if nested_scope.is_none() => {
 +                                let expr = return_expr.expr();
 +                                if let Some(replacement) = make_rewritten_flow(handler, expr) {
 +                                    ted::replace(return_expr.syntax(), replacement.syntax())
 +                                }
 +                            }
 +                            ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => {
 +                                let expr = break_expr.expr();
 +                                if let Some(replacement) = make_rewritten_flow(handler, expr) {
 +                                    ted::replace(break_expr.syntax(), replacement.syntax())
 +                                }
 +                            }
 +                            ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => {
 +                                if let Some(replacement) = make_rewritten_flow(handler, None) {
 +                                    ted::replace(continue_expr.syntax(), replacement.syntax())
 +                                }
 +                            }
 +                            _ => {
 +                                // do nothing
 +                            }
 +                        }
 +                    }
 +                }
 +
 +                if nested_loop.as_ref() == Some(&e) {
 +                    nested_loop = None;
 +                }
 +                if nested_scope.as_ref() == Some(&e) {
 +                    nested_scope = None;
 +                }
 +            }
 +        };
 +    }
 +}
 +
 +fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
 +    let value = match handler {
 +        FlowHandler::None | FlowHandler::Try { .. } => return None,
 +        FlowHandler::If { .. } => make::expr_call(
 +            make::expr_path(make::path_from_text("ControlFlow::Break")),
 +            make::arg_list(iter::once(make::expr_unit())),
 +        ),
 +        FlowHandler::IfOption { .. } => {
 +            let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
 +            let args = make::arg_list(iter::once(expr));
 +            make::expr_call(make::expr_path(make::ext::ident_path("Some")), args)
 +        }
 +        FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")),
 +        FlowHandler::MatchResult { .. } => {
 +            let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
 +            let args = make::arg_list(iter::once(expr));
 +            make::expr_call(make::expr_path(make::ext::ident_path("Err")), args)
 +        }
 +    };
 +    Some(make::expr_return(Some(value)).clone_for_update())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn no_args_from_binary_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    foo($01 + 1$0);
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    foo(fun_name());
 +}
 +
 +fn $0fun_name() -> i32 {
 +    1 + 1
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_binary_expr_in_module() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +mod bar {
 +    fn foo() {
 +        foo($01 + 1$0);
 +    }
 +}
 +"#,
 +            r#"
 +mod bar {
 +    fn foo() {
 +        foo(fun_name());
 +    }
 +
 +    fn $0fun_name() -> i32 {
 +        1 + 1
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_binary_expr_indented() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0{ 1 + 1 }$0;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() -> i32 {
 +    1 + 1
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_stmt_with_last_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    let k = 1;
 +    $0let m = 1;
 +    m + 1$0
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    let k = 1;
 +    fun_name()
 +}
 +
 +fn $0fun_name() -> i32 {
 +    let m = 1;
 +    m + 1
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_stmt_unit() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let k = 3;
 +    $0let m = 1;
 +    let n = m + 1;$0
 +    let g = 5;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let k = 3;
 +    fun_name();
 +    let g = 5;
 +}
 +
 +fn $0fun_name() {
 +    let m = 1;
 +    let n = m + 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_if() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0if true { }$0
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    if true { }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_if_else() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    $0if true { 1 } else { 2 }$0
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    fun_name()
 +}
 +
 +fn $0fun_name() -> i32 {
 +    if true { 1 } else { 2 }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_if_let_else() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    $0if let true = false { 1 } else { 2 }$0
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    fun_name()
 +}
 +
 +fn $0fun_name() -> i32 {
 +    if let true = false { 1 } else { 2 }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_match() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    $0match true {
 +        true => 1,
 +        false => 2,
 +    }$0
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    fun_name()
 +}
 +
 +fn $0fun_name() -> i32 {
 +    match true {
 +        true => 1,
 +        false => 2,
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_while() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0while true { }$0
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    while true { }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_for() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0for v in &[0, 1] { }$0
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    for v in &[0, 1] { }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_loop_unit() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0loop {
 +        let m = 1;
 +    }$0
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name()
 +}
 +
 +fn $0fun_name() -> ! {
 +    loop {
 +        let m = 1;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_loop_with_return() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let v = $0loop {
 +        let m = 1;
 +        break m;
 +    }$0;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let v = fun_name();
 +}
 +
 +fn $0fun_name() -> i32 {
 +    loop {
 +        let m = 1;
 +        break m;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_args_from_match() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let v: i32 = $0match Some(1) {
 +        Some(x) => x,
 +        None => 0,
 +    }$0;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let v: i32 = fun_name();
 +}
 +
 +fn $0fun_name() -> i32 {
 +    match Some(1) {
 +        Some(x) => x,
 +        None => 0,
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_partial_block_single_line() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let mut v = $0n * n;$0
 +    v += 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let mut v = fun_name(n);
 +    v += 1;
 +}
 +
 +fn $0fun_name(n: i32) -> i32 {
 +    let mut v = n * n;
 +    v
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_partial_block() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let m = 2;
 +    let n = 1;
 +    let mut v = m $0* n;
 +    let mut w = 3;$0
 +    v += 1;
 +    w += 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let m = 2;
 +    let n = 1;
 +    let (mut v, mut w) = fun_name(m, n);
 +    v += 1;
 +    w += 1;
 +}
 +
 +fn $0fun_name(m: i32, n: i32) -> (i32, i32) {
 +    let mut v = m * n;
 +    let mut w = 3;
 +    (v, w)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn argument_form_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    $0n+2$0
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    fun_name(n)
 +}
 +
 +fn $0fun_name(n: u32) -> u32 {
 +    n+2
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn argument_used_twice_form_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    $0n+n$0
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    fun_name(n)
 +}
 +
 +fn $0fun_name(n: u32) -> u32 {
 +    n+n
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn two_arguments_form_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    let m = 3;
 +    $0n+n*m$0
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    let m = 3;
 +    fun_name(n, m)
 +}
 +
 +fn $0fun_name(n: u32, m: u32) -> u32 {
 +    n+n*m
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn argument_and_locals() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    $0let m = 1;
 +    n + m$0
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    let n = 2;
 +    fun_name(n)
 +}
 +
 +fn $0fun_name(n: u32) -> u32 {
 +    let m = 1;
 +    n + m
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn in_comment_is_not_applicable() {
 +        cov_mark::check!(extract_function_in_comment_is_not_applicable);
 +        check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
 +    }
 +
 +    #[test]
 +    fn part_of_expr_stmt() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $01$0 + 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name() + 1;
 +}
 +
 +fn $0fun_name() -> i32 {
 +    1
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0bar(1 + 1)$0
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    bar(1 + 1)
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn extract_from_nested() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    let x = true;
 +    let tuple = match x {
 +        true => ($02 + 2$0, true)
 +        _ => (0, false)
 +    };
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let x = true;
 +    let tuple = match x {
 +        true => (fun_name(), true)
 +        _ => (0, false)
 +    };
 +}
 +
 +fn $0fun_name() -> i32 {
 +    2 + 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_from_closure() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    let lambda = |x: u32| $0x * 2$0;
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let lambda = |x: u32| fun_name(x);
 +}
 +
 +fn $0fun_name(x: u32) -> u32 {
 +    x * 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_return_stmt() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +    $0return 2 + 2$0;
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    return fun_name();
 +}
 +
 +fn $0fun_name() -> u32 {
 +    2 + 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_add_extra_whitespace() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> u32 {
 +
 +
 +    $0return 2 + 2$0;
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +
 +
 +    return fun_name();
 +}
 +
 +fn $0fun_name() -> u32 {
 +    2 + 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_stmt() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    let result = loop {
 +        $0break 2 + 2$0;
 +    };
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let result = loop {
 +        break fun_name();
 +    };
 +}
 +
 +fn $0fun_name() -> i32 {
 +    2 + 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_cast() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    let v = $00f32 as u32$0;
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let v = fun_name();
 +}
 +
 +fn $0fun_name() -> u32 {
 +    0f32 as u32
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_not_applicable() {
 +        check_assist_not_applicable(extract_function, r"fn foo() { $0return$0; } ");
 +    }
 +
 +    #[test]
 +    fn method_to_freestanding() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct S;
 +
 +impl S {
 +    fn foo(&self) -> i32 {
 +        $01+1$0
 +    }
 +}
 +"#,
 +            r#"
 +struct S;
 +
 +impl S {
 +    fn foo(&self) -> i32 {
 +        fun_name()
 +    }
 +}
 +
 +fn $0fun_name() -> i32 {
 +    1+1
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_with_reference() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct S { f: i32 };
 +
 +impl S {
 +    fn foo(&self) -> i32 {
 +        $0self.f+self.f$0
 +    }
 +}
 +"#,
 +            r#"
 +struct S { f: i32 };
 +
 +impl S {
 +    fn foo(&self) -> i32 {
 +        self.fun_name()
 +    }
 +
 +    fn $0fun_name(&self) -> i32 {
 +        self.f+self.f
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_with_mut() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct S { f: i32 };
 +
 +impl S {
 +    fn foo(&mut self) {
 +        $0self.f += 1;$0
 +    }
 +}
 +"#,
 +            r#"
 +struct S { f: i32 };
 +
 +impl S {
 +    fn foo(&mut self) {
 +        self.fun_name();
 +    }
 +
 +    fn $0fun_name(&mut self) {
 +        self.f += 1;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn variable_defined_inside_and_used_after_no_ret() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    $0let k = n * n;$0
 +    let m = k + 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let k = fun_name(n);
 +    let m = k + 1;
 +}
 +
 +fn $0fun_name(n: i32) -> i32 {
 +    let k = n * n;
 +    k
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn variable_defined_inside_and_used_after_mutably_no_ret() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    $0let mut k = n * n;$0
 +    k += 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let mut k = fun_name(n);
 +    k += 1;
 +}
 +
 +fn $0fun_name(n: i32) -> i32 {
 +    let mut k = n * n;
 +    k
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn two_variables_defined_inside_and_used_after_no_ret() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    $0let k = n * n;
 +    let m = k + 2;$0
 +    let h = k + m;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let (k, m) = fun_name(n);
 +    let h = k + m;
 +}
 +
 +fn $0fun_name(n: i32) -> (i32, i32) {
 +    let k = n * n;
 +    let m = k + 2;
 +    (k, m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn multi_variables_defined_inside_and_used_after_mutably_no_ret() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    $0let mut k = n * n;
 +    let mut m = k + 2;
 +    let mut o = m + 3;
 +    o += 1;$0
 +    k += o;
 +    m = 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 1;
 +    let (mut k, mut m, o) = fun_name(n);
 +    k += o;
 +    m = 1;
 +}
 +
 +fn $0fun_name(n: i32) -> (i32, i32, i32) {
 +    let mut k = n * n;
 +    let mut m = k + 2;
 +    let mut o = m + 3;
 +    o += 1;
 +    (k, m, o)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn nontrivial_patterns_define_variables() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Counter(i32);
 +fn foo() {
 +    $0let Counter(n) = Counter(0);$0
 +    let m = n;
 +}
 +"#,
 +            r#"
 +struct Counter(i32);
 +fn foo() {
 +    let n = fun_name();
 +    let m = n;
 +}
 +
 +fn $0fun_name() -> i32 {
 +    let Counter(n) = Counter(0);
 +    n
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_with_two_fields_pattern_define_variables() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Counter { n: i32, m: i32 };
 +fn foo() {
 +    $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0
 +    let h = n + k;
 +}
 +"#,
 +            r#"
 +struct Counter { n: i32, m: i32 };
 +fn foo() {
 +    let (n, k) = fun_name();
 +    let h = n + k;
 +}
 +
 +fn $0fun_name() -> (i32, i32) {
 +    let Counter { n, m: k } = Counter { n: 1, m: 2 };
 +    (n, k)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_var_from_outer_scope() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    $0n += 1;$0
 +    let m = n + 1;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(&mut n);
 +    let m = n + 1;
 +}
 +
 +fn $0fun_name(n: &mut i32) {
 +    *n += 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_field_from_outer_scope() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct C { n: i32 }
 +fn foo() {
 +    let mut c = C { n: 0 };
 +    $0c.n += 1;$0
 +    let m = c.n + 1;
 +}
 +"#,
 +            r#"
 +struct C { n: i32 }
 +fn foo() {
 +    let mut c = C { n: 0 };
 +    fun_name(&mut c);
 +    let m = c.n + 1;
 +}
 +
 +fn $0fun_name(c: &mut C) {
 +    c.n += 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_nested_field_from_outer_scope() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct P { n: i32}
 +struct C { p: P }
 +fn foo() {
 +    let mut c = C { p: P { n: 0 } };
 +    let mut v = C { p: P { n: 0 } };
 +    let u = C { p: P { n: 0 } };
 +    $0c.p.n += u.p.n;
 +    let r = &mut v.p.n;$0
 +    let m = c.p.n + v.p.n + u.p.n;
 +}
 +"#,
 +            r#"
 +struct P { n: i32}
 +struct C { p: P }
 +fn foo() {
 +    let mut c = C { p: P { n: 0 } };
 +    let mut v = C { p: P { n: 0 } };
 +    let u = C { p: P { n: 0 } };
 +    fun_name(&mut c, &u, &mut v);
 +    let m = c.p.n + v.p.n + u.p.n;
 +}
 +
 +fn $0fun_name(c: &mut C, u: &C, v: &mut C) {
 +    c.p.n += u.p.n;
 +    let r = &mut v.p.n;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param_many_usages_stmt() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn bar(k: i32) {}
 +trait I: Copy {
 +    fn succ(&self) -> Self;
 +    fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
 +}
 +impl I for i32 {
 +    fn succ(&self) -> Self { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    $0n += n;
 +    bar(n);
 +    bar(n+1);
 +    bar(n*n);
 +    bar(&n);
 +    n.inc();
 +    let v = &mut n;
 +    *v = v.succ();
 +    n.succ();$0
 +    let m = n + 1;
 +}
 +"#,
 +            r#"
 +fn bar(k: i32) {}
 +trait I: Copy {
 +    fn succ(&self) -> Self;
 +    fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
 +}
 +impl I for i32 {
 +    fn succ(&self) -> Self { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(&mut n);
 +    let m = n + 1;
 +}
 +
 +fn $0fun_name(n: &mut i32) {
 +    *n += *n;
 +    bar(*n);
 +    bar(*n+1);
 +    bar(*n**n);
 +    bar(&*n);
 +    n.inc();
 +    let v = n;
 +    *v = v.succ();
 +    n.succ();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param_many_usages_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn bar(k: i32) {}
 +trait I: Copy {
 +    fn succ(&self) -> Self;
 +    fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
 +}
 +impl I for i32 {
 +    fn succ(&self) -> Self { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    $0{
 +        n += n;
 +        bar(n);
 +        bar(n+1);
 +        bar(n*n);
 +        bar(&n);
 +        n.inc();
 +        let v = &mut n;
 +        *v = v.succ();
 +        n.succ();
 +    }$0
 +    let m = n + 1;
 +}
 +"#,
 +            r#"
 +fn bar(k: i32) {}
 +trait I: Copy {
 +    fn succ(&self) -> Self;
 +    fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
 +}
 +impl I for i32 {
 +    fn succ(&self) -> Self { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(&mut n);
 +    let m = n + 1;
 +}
 +
 +fn $0fun_name(n: &mut i32) {
 +    *n += *n;
 +    bar(*n);
 +    bar(*n+1);
 +    bar(*n**n);
 +    bar(&*n);
 +    n.inc();
 +    let v = n;
 +    *v = v.succ();
 +    n.succ();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param_by_value() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    $0n += 1;$0
 +}
 +"#,
 +            r"
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(n);
 +}
 +
 +fn $0fun_name(mut n: i32) {
 +    n += 1;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param_because_of_mut_ref() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    $0let v = &mut n;
 +    *v += 1;$0
 +    let k = n;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(&mut n);
 +    let k = n;
 +}
 +
 +fn $0fun_name(n: &mut i32) {
 +    let v = n;
 +    *v += 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param_by_value_because_of_mut_ref() {
 +        check_assist(
 +            extract_function,
 +            r"
 +fn foo() {
 +    let mut n = 1;
 +    $0let v = &mut n;
 +    *v += 1;$0
 +}
 +",
 +            r#"
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(n);
 +}
 +
 +fn $0fun_name(mut n: i32) {
 +    let v = &mut n;
 +    *v += 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_method_call() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +trait I {
 +    fn inc(&mut self);
 +}
 +impl I for i32 {
 +    fn inc(&mut self) { *self += 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    $0n.inc();$0
 +}
 +"#,
 +            r#"
 +trait I {
 +    fn inc(&mut self);
 +}
 +impl I for i32 {
 +    fn inc(&mut self) { *self += 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(n);
 +}
 +
 +fn $0fun_name(mut n: i32) {
 +    n.inc();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shared_method_call() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +trait I {
 +    fn succ(&self);
 +}
 +impl I for i32 {
 +    fn succ(&self) { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    $0n.succ();$0
 +}
 +"#,
 +            r"
 +trait I {
 +    fn succ(&self);
 +}
 +impl I for i32 {
 +    fn succ(&self) { *self + 1 }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(n);
 +}
 +
 +fn $0fun_name(n: i32) {
 +    n.succ();
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_method_call_with_other_receiver() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +trait I {
 +    fn inc(&mut self, n: i32);
 +}
 +impl I for i32 {
 +    fn inc(&mut self, n: i32) { *self += n }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    $0let mut m = 2;
 +    m.inc(n);$0
 +}
 +"#,
 +            r"
 +trait I {
 +    fn inc(&mut self, n: i32);
 +}
 +impl I for i32 {
 +    fn inc(&mut self, n: i32) { *self += n }
 +}
 +fn foo() {
 +    let mut n = 1;
 +    fun_name(n);
 +}
 +
 +fn $0fun_name(n: i32) {
 +    let mut m = 2;
 +    m.inc(n);
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn non_copy_without_usages_after() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    $0let n = c.0;$0
 +}
 +"#,
 +            r"
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    fun_name(c);
 +}
 +
 +fn $0fun_name(c: Counter) {
 +    let n = c.0;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn non_copy_used_after() {
 +        check_assist(
 +            extract_function,
 +            r"
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    $0let n = c.0;$0
 +    let m = c.0;
 +}
 +",
 +            r#"
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    fun_name(&c);
 +    let m = c.0;
 +}
 +
 +fn $0fun_name(c: &Counter) {
 +    let n = c.0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn copy_used_after() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: copy
 +fn foo() {
 +    let n = 0;
 +    $0let m = n;$0
 +    let k = n;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let n = 0;
 +    fun_name(n);
 +    let k = n;
 +}
 +
 +fn $0fun_name(n: i32) {
 +    let m = n;
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn copy_custom_used_after() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: copy, derive
 +#[derive(Clone, Copy)]
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    $0let n = c.0;$0
 +    let m = c.0;
 +}
 +"#,
 +            r#"
 +#[derive(Clone, Copy)]
 +struct Counter(i32);
 +fn foo() {
 +    let c = Counter(0);
 +    fun_name(c);
 +    let m = c.0;
 +}
 +
 +fn $0fun_name(c: Counter) {
 +    let n = c.0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn indented_stmts() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    if true {
 +        loop {
 +            $0let n = 1;
 +            let m = 2;$0
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    if true {
 +        loop {
 +            fun_name();
 +        }
 +    }
 +}
 +
 +fn $0fun_name() {
 +    let n = 1;
 +    let m = 2;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn indented_stmts_inside_mod() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +mod bar {
 +    fn foo() {
 +        if true {
 +            loop {
 +                $0let n = 1;
 +                let m = 2;$0
 +            }
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +mod bar {
 +    fn foo() {
 +        if true {
 +            loop {
 +                fun_name();
 +            }
 +        }
 +    }
 +
 +    fn $0fun_name() {
 +        let n = 1;
 +        let m = 2;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_loop() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: option
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let m = n + 1;
 +        break;
 +        let k = 2;$0
 +        let h = 1 + k;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        let k = match fun_name(n) {
 +            Some(value) => value,
 +            None => break,
 +        };
 +        let h = 1 + k;
 +    }
 +}
 +
 +fn $0fun_name(n: i32) -> Option<i32> {
 +    let m = n + 1;
 +    return None;
 +    let k = 2;
 +    Some(k)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_to_parent() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: copy, result
 +fn foo() -> i64 {
 +    let n = 1;
 +    $0let m = n + 1;
 +    return 1;
 +    let k = 2;$0
 +    (n + k) as i64
 +}
 +"#,
 +            r#"
 +fn foo() -> i64 {
 +    let n = 1;
 +    let k = match fun_name(n) {
 +        Ok(value) => value,
 +        Err(value) => return value,
 +    };
 +    (n + k) as i64
 +}
 +
 +fn $0fun_name(n: i32) -> Result<i32, i64> {
 +    let m = n + 1;
 +    return Err(1);
 +    let k = 2;
 +    Ok(k)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_and_continue() {
 +        cov_mark::check!(external_control_flow_break_and_continue);
 +        check_assist_not_applicable(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let m = n + 1;
 +        break;
 +        let k = 2;
 +        continue;
 +        let k = k + 1;$0
 +        let r = n + k;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_and_break() {
 +        cov_mark::check!(external_control_flow_return_and_bc);
 +        check_assist_not_applicable(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let m = n + 1;
 +        break;
 +        let k = 2;
 +        return;
 +        let k = k + 1;$0
 +        let r = n + k;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_loop_with_if() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: try
 +fn foo() {
 +    loop {
 +        let mut n = 1;
 +        $0let m = n + 1;
 +        break;
 +        n += m;$0
 +        let h = 1 + n;
 +    }
 +}
 +"#,
 +            r#"
 +use core::ops::ControlFlow;
 +
 +fn foo() {
 +    loop {
 +        let mut n = 1;
 +        if let ControlFlow::Break(_) = fun_name(&mut n) {
 +            break;
 +        }
 +        let h = 1 + n;
 +    }
 +}
 +
 +fn $0fun_name(n: &mut i32) -> ControlFlow<()> {
 +    let m = *n + 1;
 +    return ControlFlow::Break(());
 +    *n += m;
 +    ControlFlow::Continue(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_loop_nested() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: try
 +fn foo() {
 +    loop {
 +        let mut n = 1;
 +        $0let m = n + 1;
 +        if m == 42 {
 +            break;
 +        }$0
 +        let h = 1;
 +    }
 +}
 +"#,
 +            r#"
 +use core::ops::ControlFlow;
 +
 +fn foo() {
 +    loop {
 +        let mut n = 1;
 +        if let ControlFlow::Break(_) = fun_name(n) {
 +            break;
 +        }
 +        let h = 1;
 +    }
 +}
 +
 +fn $0fun_name(n: i32) -> ControlFlow<()> {
 +    let m = n + 1;
 +    if m == 42 {
 +        return ControlFlow::Break(());
 +    }
 +    ControlFlow::Continue(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_loop_nested_labeled() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: try
 +fn foo() {
 +    'bar: loop {
 +        loop {
 +            $0break 'bar;$0
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +use core::ops::ControlFlow;
 +
 +fn foo() {
 +    'bar: loop {
 +        loop {
 +            if let ControlFlow::Break(_) = fun_name() {
 +                break 'bar;
 +            }
 +        }
 +    }
 +}
 +
 +fn $0fun_name() -> ControlFlow<()> {
 +    return ControlFlow::Break(());
 +    ControlFlow::Continue(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn continue_loop_nested_labeled() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: try
 +fn foo() {
 +    'bar: loop {
 +        loop {
 +            $0continue 'bar;$0
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +use core::ops::ControlFlow;
 +
 +fn foo() {
 +    'bar: loop {
 +        loop {
 +            if let ControlFlow::Break(_) = fun_name() {
 +                continue 'bar;
 +            }
 +        }
 +    }
 +}
 +
 +fn $0fun_name() -> ControlFlow<()> {
 +    return ControlFlow::Break(());
 +    ControlFlow::Continue(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_from_nested_loop() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;$0
 +        let k = 1;
 +        loop {
 +            return;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        let m = match fun_name() {
 +            Some(value) => value,
 +            None => return,
 +        };
 +        let h = 1 + m;
 +    }
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = 1;
 +    loop {
 +        return None;
 +    }
 +    let m = k + 1;
 +    Some(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_from_nested_loop() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let k = 1;
 +        loop {
 +            break;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        let m = fun_name();
 +        let h = 1 + m;
 +    }
 +}
 +
 +fn $0fun_name() -> i32 {
 +    let k = 1;
 +    loop {
 +        break;
 +    }
 +    let m = k + 1;
 +    m
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_from_nested_and_outer_loops() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let k = 1;
 +        loop {
 +            break;
 +        }
 +        if k == 42 {
 +            break;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        let m = match fun_name() {
 +            Some(value) => value,
 +            None => break,
 +        };
 +        let h = 1 + m;
 +    }
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = 1;
 +    loop {
 +        break;
 +    }
 +    if k == 42 {
 +        return None;
 +    }
 +    let m = k + 1;
 +    Some(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_from_nested_fn() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        $0let k = 1;
 +        fn test() {
 +            return;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let n = 1;
 +        let m = fun_name();
 +        let h = 1 + m;
 +    }
 +}
 +
 +fn $0fun_name() -> i32 {
 +    let k = 1;
 +    fn test() {
 +        return;
 +    }
 +    let m = k + 1;
 +    m
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_with_value() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    loop {
 +        let n = 1;
 +        $0let k = 1;
 +        if k == 42 {
 +            break 3;
 +        }
 +        let m = k + 1;$0
 +        let h = 1;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    loop {
 +        let n = 1;
 +        if let Some(value) = fun_name() {
 +            break value;
 +        }
 +        let h = 1;
 +    }
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = 1;
 +    if k == 42 {
 +        return Some(3);
 +    }
 +    let m = k + 1;
 +    None
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_with_value_and_label() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i32 {
 +    'bar: loop {
 +        let n = 1;
 +        $0let k = 1;
 +        if k == 42 {
 +            break 'bar 4;
 +        }
 +        let m = k + 1;$0
 +        let h = 1;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() -> i32 {
 +    'bar: loop {
 +        let n = 1;
 +        if let Some(value) = fun_name() {
 +            break 'bar value;
 +        }
 +        let h = 1;
 +    }
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = 1;
 +    if k == 42 {
 +        return Some(4);
 +    }
 +    let m = k + 1;
 +    None
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn break_with_value_and_return() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() -> i64 {
 +    loop {
 +        let n = 1;$0
 +        let k = 1;
 +        if k == 42 {
 +            break 3;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() -> i64 {
 +    loop {
 +        let n = 1;
 +        let m = match fun_name() {
 +            Ok(value) => value,
 +            Err(value) => break value,
 +        };
 +        let h = 1 + m;
 +    }
 +}
 +
 +fn $0fun_name() -> Result<i32, i64> {
 +    let k = 1;
 +    if k == 42 {
 +        return Err(3);
 +    }
 +    let m = k + 1;
 +    Ok(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_option() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: option
 +fn bar() -> Option<i32> { None }
 +fn foo() -> Option<()> {
 +    let n = bar()?;
 +    $0let k = foo()?;
 +    let m = k + 1;$0
 +    let h = 1 + m;
 +    Some(())
 +}
 +"#,
 +            r#"
 +fn bar() -> Option<i32> { None }
 +fn foo() -> Option<()> {
 +    let n = bar()?;
 +    let m = fun_name()?;
 +    let h = 1 + m;
 +    Some(())
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = foo()?;
 +    let m = k + 1;
 +    Some(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_option_unit() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: option
 +fn foo() -> Option<()> {
 +    let n = 1;
 +    $0let k = foo()?;
 +    let m = k + 1;$0
 +    let h = 1 + n;
 +    Some(())
 +}
 +"#,
 +            r#"
 +fn foo() -> Option<()> {
 +    let n = 1;
 +    fun_name()?;
 +    let h = 1 + n;
 +    Some(())
 +}
 +
 +fn $0fun_name() -> Option<()> {
 +    let k = foo()?;
 +    let m = k + 1;
 +    Some(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_result() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: result
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    $0let k = foo()?;
 +    let m = k + 1;$0
 +    let h = 1 + m;
 +    Ok(())
 +}
 +"#,
 +            r#"
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    let m = fun_name()?;
 +    let h = 1 + m;
 +    Ok(())
 +}
 +
 +fn $0fun_name() -> Result<i32, i64> {
 +    let k = foo()?;
 +    let m = k + 1;
 +    Ok(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_option_with_return() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: option
 +fn foo() -> Option<()> {
 +    let n = 1;
 +    $0let k = foo()?;
 +    if k == 42 {
 +        return None;
 +    }
 +    let m = k + 1;$0
 +    let h = 1 + m;
 +    Some(())
 +}
 +"#,
 +            r#"
 +fn foo() -> Option<()> {
 +    let n = 1;
 +    let m = fun_name()?;
 +    let h = 1 + m;
 +    Some(())
 +}
 +
 +fn $0fun_name() -> Option<i32> {
 +    let k = foo()?;
 +    if k == 42 {
 +        return None;
 +    }
 +    let m = k + 1;
 +    Some(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_result_with_return() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: result
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    $0let k = foo()?;
 +    if k == 42 {
 +        return Err(1);
 +    }
 +    let m = k + 1;$0
 +    let h = 1 + m;
 +    Ok(())
 +}
 +"#,
 +            r#"
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    let m = fun_name()?;
 +    let h = 1 + m;
 +    Ok(())
 +}
 +
 +fn $0fun_name() -> Result<i32, i64> {
 +    let k = foo()?;
 +    if k == 42 {
 +        return Err(1);
 +    }
 +    let m = k + 1;
 +    Ok(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_and_break() {
 +        cov_mark::check!(external_control_flow_try_and_bc);
 +        check_assist_not_applicable(
 +            extract_function,
 +            r#"
 +//- minicore: option
 +fn foo() -> Option<()> {
 +    loop {
 +        let n = Some(1);
 +        $0let m = n? + 1;
 +        break;
 +        let k = 2;
 +        let k = k + 1;$0
 +        let r = n + k;
 +    }
 +    Some(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn try_and_return_ok() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: result
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    $0let k = foo()?;
 +    if k == 42 {
 +        return Ok(1);
 +    }
 +    let m = k + 1;$0
 +    let h = 1 + m;
 +    Ok(())
 +}
 +"#,
 +            r#"
 +fn foo() -> Result<(), i64> {
 +    let n = 1;
 +    let m = fun_name()?;
 +    let h = 1 + m;
 +    Ok(())
 +}
 +
 +fn $0fun_name() -> Result<i32, i64> {
 +    let k = foo()?;
 +    if k == 42 {
 +        return Ok(1);
 +    }
 +    let m = k + 1;
 +    Ok(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_usage_in_macro() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +macro_rules! m {
 +    ($val:expr) => { $val };
 +}
 +
 +fn foo() {
 +    let n = 1;
 +    $0let k = n * m!(n);$0
 +    let m = k + 1;
 +}
 +"#,
 +            r#"
 +macro_rules! m {
 +    ($val:expr) => { $val };
 +}
 +
 +fn foo() {
 +    let n = 1;
 +    let k = fun_name(n);
 +    let m = k + 1;
 +}
 +
 +fn $0fun_name(n: i32) -> i32 {
 +    let k = n * m!(n);
 +    k
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_with_await() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: future
 +fn main() {
 +    $0some_function().await;$0
 +}
 +
 +async fn some_function() {
 +
 +}
 +"#,
 +            r#"
 +fn main() {
 +    fun_name().await;
 +}
 +
 +async fn $0fun_name() {
 +    some_function().await;
 +}
 +
 +async fn some_function() {
 +
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_with_await_and_result_not_producing_match_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: future, result
 +async fn foo() -> Result<(), ()> {
 +    $0async {}.await;
 +    Err(())?$0
 +}
 +"#,
 +            r#"
 +async fn foo() -> Result<(), ()> {
 +    fun_name().await?
 +}
 +
 +async fn $0fun_name() -> Result<(), ()> {
 +    async {}.await;
 +    Err(())?
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_with_await_and_result_producing_match_expr() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: future
 +async fn foo() -> i32 {
 +    loop {
 +        let n = 1;$0
 +        let k = async { 1 }.await;
 +        if k == 42 {
 +            break 3;
 +        }
 +        let m = k + 1;$0
 +        let h = 1 + m;
 +    }
 +}
 +"#,
 +            r#"
 +async fn foo() -> i32 {
 +    loop {
 +        let n = 1;
 +        let m = match fun_name().await {
 +            Ok(value) => value,
 +            Err(value) => break value,
 +        };
 +        let h = 1 + m;
 +    }
 +}
 +
 +async fn $0fun_name() -> Result<i32, i32> {
 +    let k = async { 1 }.await;
 +    if k == 42 {
 +        return Err(3);
 +    }
 +    let m = k + 1;
 +    Ok(m)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_with_await_in_args() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: future
 +fn main() {
 +    $0function_call("a", some_function().await);$0
 +}
 +
 +async fn some_function() {
 +
 +}
 +"#,
 +            r#"
 +fn main() {
 +    fun_name().await;
 +}
 +
 +async fn $0fun_name() {
 +    function_call("a", some_function().await);
 +}
 +
 +async fn some_function() {
 +
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_does_not_extract_standalone_blocks() {
 +        check_assist_not_applicable(
 +            extract_function,
 +            r#"
 +fn main() $0{}$0
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_adds_comma_for_match_arm() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    match 6 {
 +        100 => $0{ 100 }$0
 +        _ => 0,
 +    };
 +}
 +"#,
 +            r#"
 +fn main() {
 +    match 6 {
 +        100 => fun_name(),
 +        _ => 0,
 +    };
 +}
 +
 +fn $0fun_name() -> i32 {
 +    100
 +}
 +"#,
 +        );
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn main() {
 +    match 6 {
 +        100 => $0{ 100 }$0,
 +        _ => 0,
 +    };
 +}
 +"#,
 +            r#"
 +fn main() {
 +    match 6 {
 +        100 => fun_name(),
 +        _ => 0,
 +    };
 +}
 +
 +fn $0fun_name() -> i32 {
 +    100
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_does_not_tear_comments_apart() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    /*$0*/
 +    foo();
 +    foo();
 +    /*$0*/
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    /**/
 +    foo();
 +    foo();
 +    /**/
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_does_not_tear_body_apart() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    $0foo();
 +}$0
 +"#,
 +            r#"
 +fn foo() {
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    foo();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_does_not_wrap_res_in_res() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +//- minicore: result
 +fn foo() -> Result<(), i64> {
 +    $0Result::<i32, i64>::Ok(0)?;
 +    Ok(())$0
 +}
 +"#,
 +            r#"
 +fn foo() -> Result<(), i64> {
 +    fun_name()?
 +}
 +
 +fn $0fun_name() -> Result<(), i64> {
 +    Result::<i32, i64>::Ok(0)?;
 +    Ok(())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_knows_const() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +const fn foo() {
 +    $0()$0
 +}
 +"#,
 +            r#"
 +const fn foo() {
 +    fun_name();
 +}
 +
 +const fn $0fun_name() {
 +    ()
 +}
 +"#,
 +        );
 +        check_assist(
 +            extract_function,
 +            r#"
 +const FOO: () = {
 +    $0()$0
 +};
 +"#,
 +            r#"
 +const FOO: () = {
 +    fun_name();
 +};
 +
 +const fn $0fun_name() {
 +    ()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_does_not_move_outer_loop_vars() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let mut x = 5;
 +    for _ in 0..10 {
 +        $0x += 1;$0
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let mut x = 5;
 +    for _ in 0..10 {
 +        fun_name(&mut x);
 +    }
 +}
 +
 +fn $0fun_name(x: &mut i32) {
 +    *x += 1;
 +}
 +"#,
 +        );
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    for _ in 0..10 {
 +        let mut x = 5;
 +        $0x += 1;$0
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    for _ in 0..10 {
 +        let mut x = 5;
 +        fun_name(x);
 +    }
 +}
 +
 +fn $0fun_name(mut x: i32) {
 +    x += 1;
 +}
 +"#,
 +        );
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    loop {
 +        let mut x = 5;
 +        for _ in 0..10 {
 +            $0x += 1;$0
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    loop {
 +        let mut x = 5;
 +        for _ in 0..10 {
 +            fun_name(&mut x);
 +        }
 +    }
 +}
 +
 +fn $0fun_name(x: &mut i32) {
 +    *x += 1;
 +}
 +"#,
 +        );
 +    }
 +
 +    // regression test for #9822
 +    #[test]
 +    fn extract_mut_ref_param_has_no_mut_binding_in_loop() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&mut self) {}
 +}
 +fn foo() {
 +    let mut x = Foo;
 +    while false {
 +        let y = &mut x;
 +        $0y.foo();$0
 +    }
 +    let z = x;
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&mut self) {}
 +}
 +fn foo() {
 +    let mut x = Foo;
 +    while false {
 +        let y = &mut x;
 +        fun_name(y);
 +    }
 +    let z = x;
 +}
 +
 +fn $0fun_name(y: &mut Foo) {
 +    y.foo();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_with_macro_arg() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +macro_rules! m {
 +    ($val:expr) => { $val };
 +}
 +fn main() {
 +    let bar = "bar";
 +    $0m!(bar);$0
 +}
 +"#,
 +            r#"
 +macro_rules! m {
 +    ($val:expr) => { $val };
 +}
 +fn main() {
 +    let bar = "bar";
 +    fun_name(bar);
 +}
 +
 +fn $0fun_name(bar: &str) {
 +    m!(bar);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unresolveable_types_default_to_placeholder() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn foo() {
 +    let a = __unresolved;
 +    let _ = $0{a}$0;
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    let a = __unresolved;
 +    let _ = fun_name(a);
 +}
 +
 +fn $0fun_name(a: _) -> _ {
 +    a
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn reference_mutable_param_with_further_usages() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +pub struct Foo {
 +    field: u32,
 +}
 +
 +pub fn testfn(arg: &mut Foo) {
 +    $0arg.field = 8;$0
 +    // Simulating access after the extracted portion
 +    arg.field = 16;
 +}
 +"#,
 +            r#"
 +pub struct Foo {
 +    field: u32,
 +}
 +
 +pub fn testfn(arg: &mut Foo) {
 +    fun_name(arg);
 +    // Simulating access after the extracted portion
 +    arg.field = 16;
 +}
 +
 +fn $0fun_name(arg: &mut Foo) {
 +    arg.field = 8;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn reference_mutable_param_without_further_usages() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +pub struct Foo {
 +    field: u32,
 +}
 +
 +pub fn testfn(arg: &mut Foo) {
 +    $0arg.field = 8;$0
 +}
 +"#,
 +            r#"
 +pub struct Foo {
 +    field: u32,
 +}
 +
 +pub fn testfn(arg: &mut Foo) {
 +    fun_name(arg);
 +}
 +
 +fn $0fun_name(arg: &mut Foo) {
 +    arg.field = 8;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_function_copies_comment_at_start() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    $0// comment here!
 +    let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    // comment here!
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_function_copies_comment_in_between() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;$0
 +    let a = 0;
 +    // comment here!
 +    let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    let a = 0;
 +    // comment here!
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_function_copies_comment_at_end() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    $0let x = 0;
 +    // comment here!$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    let x = 0;
 +    // comment here!
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_function_copies_comment_indented() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    $0let x = 0;
 +    while(true) {
 +        // comment here!
 +    }$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    let x = 0;
 +    while(true) {
 +        // comment here!
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    // FIXME: we do want to preserve whitespace
 +    #[test]
 +    fn extract_function_does_not_preserve_whitespace() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    $0let a = 0;
 +
 +    let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    let a = 0;
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_function_long_form_comment() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    $0/* a comment */
 +    let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn func() {
 +    let i = 0;
 +    fun_name();
 +}
 +
 +fn $0fun_name() {
 +    /* a comment */
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn it_should_not_generate_duplicate_function_names() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn fun_name() {
 +    $0let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn fun_name() {
 +    fun_name1();
 +}
 +
 +fn $0fun_name1() {
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn should_increment_suffix_until_it_finds_space() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn fun_name1() {
 +    let y = 0;
 +}
 +
 +fn fun_name() {
 +    $0let x = 0;$0
 +}
 +"#,
 +            r#"
 +fn fun_name1() {
 +    let y = 0;
 +}
 +
 +fn fun_name() {
 +    fun_name2();
 +}
 +
 +fn $0fun_name2() {
 +    let x = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_method_from_trait_impl() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Struct(i32);
 +trait Trait {
 +    fn bar(&self) -> i32;
 +}
 +
 +impl Trait for Struct {
 +    fn bar(&self) -> i32 {
 +        $0self.0 + 2$0
 +    }
 +}
 +"#,
 +            r#"
 +struct Struct(i32);
 +trait Trait {
 +    fn bar(&self) -> i32;
 +}
 +
 +impl Trait for Struct {
 +    fn bar(&self) -> i32 {
 +        self.fun_name()
 +    }
 +}
 +
 +impl Struct {
 +    fn $0fun_name(&self) -> i32 {
 +        self.0 + 2
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn closure_arguments() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn parent(factor: i32) {
 +    let v = &[1, 2, 3];
 +
 +    $0v.iter().map(|it| it * factor);$0
 +}
 +"#,
 +            r#"
 +fn parent(factor: i32) {
 +    let v = &[1, 2, 3];
 +
 +    fun_name(v, factor);
 +}
 +
 +fn $0fun_name(v: &[i32; 3], factor: i32) {
 +    v.iter().map(|it| it * factor);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn preserve_generics() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T: Debug>(i: T) {
 +    $0foo(i);$0
 +}
 +"#,
 +            r#"
 +fn func<T: Debug>(i: T) {
 +    fun_name(i);
 +}
 +
 +fn $0fun_name<T: Debug>(i: T) {
 +    foo(i);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn preserve_generics_from_body() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T: Default>() -> T {
 +    $0T::default()$0
 +}
 +"#,
 +            r#"
 +fn func<T: Default>() -> T {
 +    fun_name()
 +}
 +
 +fn $0fun_name<T: Default>() -> T {
 +    T::default()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn filter_unused_generics() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T: Debug, U: Copy>(i: T, u: U) {
 +    bar(u);
 +    $0foo(i);$0
 +}
 +"#,
 +            r#"
 +fn func<T: Debug, U: Copy>(i: T, u: U) {
 +    bar(u);
 +    fun_name(i);
 +}
 +
 +fn $0fun_name<T: Debug>(i: T) {
 +    foo(i);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn empty_generic_param_list() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T: Debug>(t: T, i: u32) {
 +    bar(t);
 +    $0foo(i);$0
 +}
 +"#,
 +            r#"
 +fn func<T: Debug>(t: T, i: u32) {
 +    bar(t);
 +    fun_name(i);
 +}
 +
 +fn $0fun_name(i: u32) {
 +    foo(i);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn preserve_where_clause() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T>(i: T) where T: Debug {
 +    $0foo(i);$0
 +}
 +"#,
 +            r#"
 +fn func<T>(i: T) where T: Debug {
 +    fun_name(i);
 +}
 +
 +fn $0fun_name<T>(i: T) where T: Debug {
 +    foo(i);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn filter_unused_where_clause() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
 +    bar(u);
 +    $0foo(i);$0
 +}
 +"#,
 +            r#"
 +fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
 +    bar(u);
 +    fun_name(i);
 +}
 +
 +fn $0fun_name<T>(i: T) where T: Debug {
 +    foo(i);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn nested_generics() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Struct<T: Into<i32>>(T);
 +impl <T: Into<i32> + Copy> Struct<T> {
 +    fn func<V: Into<i32>>(&self, v: V) -> i32 {
 +        let t = self.0;
 +        $0t.into() + v.into()$0
 +    }
 +}
 +"#,
 +            r#"
 +struct Struct<T: Into<i32>>(T);
 +impl <T: Into<i32> + Copy> Struct<T> {
 +    fn func<V: Into<i32>>(&self, v: V) -> i32 {
 +        let t = self.0;
 +        fun_name(t, v)
 +    }
 +}
 +
 +fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 {
 +    t.into() + v.into()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn filters_unused_nested_generics() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Struct<T: Into<i32>, U: Debug>(T, U);
 +impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
 +    fn func<V: Into<i32>>(&self, v: V) -> i32 {
 +        let t = self.0;
 +        $0t.into() + v.into()$0
 +    }
 +}
 +"#,
 +            r#"
 +struct Struct<T: Into<i32>, U: Debug>(T, U);
 +impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
 +    fn func<V: Into<i32>>(&self, v: V) -> i32 {
 +        let t = self.0;
 +        fun_name(t, v)
 +    }
 +}
 +
 +fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 {
 +    t.into() + v.into()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn nested_where_clauses() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Struct<T>(T) where T: Into<i32>;
 +impl <T> Struct<T> where T: Into<i32> + Copy {
 +    fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
 +        let t = self.0;
 +        $0t.into() + v.into()$0
 +    }
 +}
 +"#,
 +            r#"
 +struct Struct<T>(T) where T: Into<i32>;
 +impl <T> Struct<T> where T: Into<i32> + Copy {
 +    fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
 +        let t = self.0;
 +        fun_name(t, v)
 +    }
 +}
 +
 +fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
 +    t.into() + v.into()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn filters_unused_nested_where_clauses() {
 +        check_assist(
 +            extract_function,
 +            r#"
 +struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
 +impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
 +    fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
 +        let t = self.0;
 +        $0t.into() + v.into()$0
 +    }
 +}
 +"#,
 +            r#"
 +struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
 +impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
 +    fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
 +        let t = self.0;
 +        fun_name(t, v)
 +    }
 +}
 +
 +fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
 +    t.into() + v.into()
 +}
 +"#,
 +        );
 +    }
 +}
index ddc2052e7aa240f92f32c3122423138edea0f4da,0000000000000000000000000000000000000000..8d5cab283d0616d3297e864a782f61e4965975cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,1097 -1,0 +1,1098 @@@
 +use std::iter;
 +
 +use either::Either;
 +use hir::{Module, ModuleDef, Name, Variant};
 +use ide_db::{
 +    defs::Definition,
 +    helpers::mod_path_to_ast,
 +    imports::insert_use::{insert_use, ImportScope, InsertUseConfig},
 +    search::FileReference,
 +    FxHashSet, RootDatabase,
 +};
 +use itertools::{Itertools, Position};
 +use syntax::{
 +    ast::{
 +        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
 +        HasName, HasVisibility,
 +    },
 +    match_ast, ted, SyntaxElement,
 +    SyntaxKind::*,
 +    SyntaxNode, T,
 +};
 +
 +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: extract_struct_from_enum_variant
 +//
 +// Extracts a struct from enum variant.
 +//
 +// ```
 +// enum A { $0One(u32, u32) }
 +// ```
 +// ->
 +// ```
 +// struct One(u32, u32);
 +//
 +// enum A { One(One) }
 +// ```
 +pub(crate) fn extract_struct_from_enum_variant(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let field_list = extract_field_list_if_applicable(&variant)?;
 +
 +    let variant_name = variant.name()?;
 +    let variant_hir = ctx.sema.to_def(&variant)?;
 +    if existing_definition(ctx.db(), &variant_name, &variant_hir) {
 +        cov_mark::hit!(test_extract_enum_not_applicable_if_struct_exists);
 +        return None;
 +    }
 +
 +    let enum_ast = variant.parent_enum();
 +    let enum_hir = ctx.sema.to_def(&enum_ast)?;
 +    let target = variant.syntax().text_range();
 +    acc.add(
 +        AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
 +        "Extract struct from enum variant",
 +        target,
 +        |builder| {
 +            let variant_hir_name = variant_hir.name(ctx.db());
 +            let enum_module_def = ModuleDef::from(enum_hir);
 +            let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all();
 +
 +            let mut visited_modules_set = FxHashSet::default();
 +            let current_module = enum_hir.module(ctx.db());
 +            visited_modules_set.insert(current_module);
 +            // record file references of the file the def resides in, we only want to swap to the edited file in the builder once
 +            let mut def_file_references = None;
 +            for (file_id, references) in usages {
 +                if file_id == ctx.file_id() {
 +                    def_file_references = Some(references);
 +                    continue;
 +                }
 +                builder.edit_file(file_id);
 +                let processed = process_references(
 +                    ctx,
 +                    builder,
 +                    &mut visited_modules_set,
 +                    &enum_module_def,
 +                    &variant_hir_name,
 +                    references,
 +                );
 +                processed.into_iter().for_each(|(path, node, import)| {
 +                    apply_references(ctx.config.insert_use, path, node, import)
 +                });
 +            }
 +            builder.edit_file(ctx.file_id());
 +
 +            let variant = builder.make_mut(variant.clone());
 +            if let Some(references) = def_file_references {
 +                let processed = process_references(
 +                    ctx,
 +                    builder,
 +                    &mut visited_modules_set,
 +                    &enum_module_def,
 +                    &variant_hir_name,
 +                    references,
 +                );
 +                processed.into_iter().for_each(|(path, node, import)| {
 +                    apply_references(ctx.config.insert_use, path, node, import)
 +                });
 +            }
 +
 +            let generic_params = enum_ast
 +                .generic_param_list()
 +                .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
 +            let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
 +            let def =
 +                create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
 +
 +            let enum_ast = variant.parent_enum();
 +            let indent = enum_ast.indent_level();
 +            def.reindent_to(indent);
 +
 +            ted::insert_all(
 +                ted::Position::before(enum_ast.syntax()),
 +                vec![
 +                    def.syntax().clone().into(),
 +                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
 +                ],
 +            );
 +
 +            update_variant(&variant, generic_params.map(|g| g.clone_for_update()));
 +        },
 +    )
 +}
 +
 +fn extract_field_list_if_applicable(
 +    variant: &ast::Variant,
 +) -> Option<Either<ast::RecordFieldList, ast::TupleFieldList>> {
 +    match variant.kind() {
 +        ast::StructKind::Record(field_list) if field_list.fields().next().is_some() => {
 +            Some(Either::Left(field_list))
 +        }
 +        ast::StructKind::Tuple(field_list) if field_list.fields().count() > 1 => {
 +            Some(Either::Right(field_list))
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Variant) -> bool {
 +    variant
 +        .parent_enum(db)
 +        .module(db)
 +        .scope(db, None)
 +        .into_iter()
 +        .filter(|(_, def)| match def {
 +            // only check type-namespace
 +            hir::ScopeDef::ModuleDef(def) => matches!(
 +                def,
 +                ModuleDef::Module(_)
 +                    | ModuleDef::Adt(_)
 +                    | ModuleDef::Variant(_)
 +                    | ModuleDef::Trait(_)
 +                    | ModuleDef::TypeAlias(_)
 +                    | ModuleDef::BuiltinType(_)
 +            ),
 +            _ => false,
 +        })
 +        .any(|(name, _)| name.to_string() == variant_name.to_string())
 +}
 +
 +fn extract_generic_params(
 +    known_generics: &ast::GenericParamList,
 +    field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 +) -> Option<ast::GenericParamList> {
 +    let mut generics = known_generics.generic_params().map(|param| (param, false)).collect_vec();
 +
 +    let tagged_one = match field_list {
 +        Either::Left(field_list) => field_list
 +            .fields()
 +            .filter_map(|f| f.ty())
 +            .fold(false, |tagged, ty| tag_generics_in_variant(&ty, &mut generics) || tagged),
 +        Either::Right(field_list) => field_list
 +            .fields()
 +            .filter_map(|f| f.ty())
 +            .fold(false, |tagged, ty| tag_generics_in_variant(&ty, &mut generics) || tagged),
 +    };
 +
 +    let generics = generics.into_iter().filter_map(|(param, tag)| tag.then(|| param));
 +    tagged_one.then(|| make::generic_param_list(generics))
 +}
 +
 +fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, bool)]) -> bool {
 +    let mut tagged_one = false;
 +
 +    for token in ty.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token) {
 +        for (param, tag) in generics.iter_mut().filter(|(_, tag)| !tag) {
 +            match param {
 +                ast::GenericParam::LifetimeParam(lt)
 +                    if matches!(token.kind(), T![lifetime_ident]) =>
 +                {
 +                    if let Some(lt) = lt.lifetime() {
 +                        if lt.text().as_str() == token.text() {
 +                            *tag = true;
 +                            tagged_one = true;
 +                            break;
 +                        }
 +                    }
 +                }
 +                param if matches!(token.kind(), T![ident]) => {
 +                    if match param {
 +                        ast::GenericParam::ConstParam(konst) => konst
 +                            .name()
 +                            .map(|name| name.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                        ast::GenericParam::TypeParam(ty) => ty
 +                            .name()
 +                            .map(|name| name.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                        ast::GenericParam::LifetimeParam(lt) => lt
 +                            .lifetime()
 +                            .map(|lt| lt.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                    } {
 +                        *tag = true;
 +                        tagged_one = true;
 +                        break;
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    tagged_one
 +}
 +
 +fn create_struct_def(
 +    name: ast::Name,
 +    variant: &ast::Variant,
 +    field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 +    generics: Option<ast::GenericParamList>,
 +    enum_: &ast::Enum,
 +) -> ast::Struct {
 +    let enum_vis = enum_.visibility();
 +
 +    let insert_vis = |node: &'_ SyntaxNode, vis: &'_ SyntaxNode| {
 +        let vis = vis.clone_for_update();
 +        ted::insert(ted::Position::before(node), vis);
 +    };
 +
 +    // for fields without any existing visibility, use visibility of enum
 +    let field_list: ast::FieldList = match field_list {
 +        Either::Left(field_list) => {
 +            let field_list = field_list.clone_for_update();
 +
 +            if let Some(vis) = &enum_vis {
 +                field_list
 +                    .fields()
 +                    .filter(|field| field.visibility().is_none())
 +                    .filter_map(|field| field.name())
 +                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
 +            }
 +
 +            field_list.into()
 +        }
 +        Either::Right(field_list) => {
 +            let field_list = field_list.clone_for_update();
 +
 +            if let Some(vis) = &enum_vis {
 +                field_list
 +                    .fields()
 +                    .filter(|field| field.visibility().is_none())
 +                    .filter_map(|field| field.ty())
 +                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
 +            }
 +
 +            field_list.into()
 +        }
 +    };
 +    field_list.reindent_to(IndentLevel::single());
 +
 +    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
 +
 +    // take comments from variant
 +    ted::insert_all(
 +        ted::Position::first_child_of(strukt.syntax()),
 +        take_all_comments(variant.syntax()),
 +    );
 +
 +    // copy attributes from enum
 +    ted::insert_all(
 +        ted::Position::first_child_of(strukt.syntax()),
 +        enum_
 +            .attrs()
 +            .flat_map(|it| {
 +                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
 +            })
 +            .collect(),
 +    );
 +
 +    strukt
 +}
 +
 +fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
 +    let name = variant.name()?;
 +    let ty = generics
 +        .filter(|generics| generics.generic_params().count() > 0)
 +        .map(|generics| {
 +            let mut generic_str = String::with_capacity(8);
 +
 +            for (p, more) in generics.generic_params().with_position().map(|p| match p {
 +                Position::First(p) | Position::Middle(p) => (p, true),
 +                Position::Last(p) | Position::Only(p) => (p, false),
 +            }) {
 +                match p {
 +                    ast::GenericParam::ConstParam(konst) => {
 +                        if let Some(name) = konst.name() {
 +                            generic_str.push_str(name.text().as_str());
 +                        }
 +                    }
 +                    ast::GenericParam::LifetimeParam(lt) => {
 +                        if let Some(lt) = lt.lifetime() {
 +                            generic_str.push_str(lt.text().as_str());
 +                        }
 +                    }
 +                    ast::GenericParam::TypeParam(ty) => {
 +                        if let Some(name) = ty.name() {
 +                            generic_str.push_str(name.text().as_str());
 +                        }
 +                    }
 +                }
 +                if more {
 +                    generic_str.push_str(", ");
 +                }
 +            }
 +
 +            make::ty(&format!("{}<{}>", &name.text(), &generic_str))
 +        })
 +        .unwrap_or_else(|| make::ty(&name.text()));
 +
 +    // change from a record to a tuple field list
 +    let tuple_field = make::tuple_field(None, ty);
 +    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
 +    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
 +
 +    // remove any ws after the name
 +    if let Some(ws) = name
 +        .syntax()
 +        .siblings_with_tokens(syntax::Direction::Next)
 +        .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
 +    {
 +        ted::remove(SyntaxElement::Token(ws));
 +    }
 +
 +    Some(())
 +}
 +
 +// Note: this also detaches whitespace after comments,
 +// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
 +// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
 +fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
 +    let mut remove_next_ws = false;
 +    node.children_with_tokens()
 +        .filter_map(move |child| match child.kind() {
 +            COMMENT => {
 +                remove_next_ws = true;
 +                child.detach();
 +                Some(child)
 +            }
 +            WHITESPACE if remove_next_ws => {
 +                remove_next_ws = false;
 +                child.detach();
 +                Some(make::tokens::single_newline().into())
 +            }
 +            _ => {
 +                remove_next_ws = false;
 +                None
 +            }
 +        })
 +        .collect()
 +}
 +
 +fn apply_references(
 +    insert_use_cfg: InsertUseConfig,
 +    segment: ast::PathSegment,
 +    node: SyntaxNode,
 +    import: Option<(ImportScope, hir::ModPath)>,
 +) {
 +    if let Some((scope, path)) = import {
 +        insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg);
 +    }
 +    // deep clone to prevent cycle
 +    let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
 +    ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax());
 +    ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
 +    ted::insert_raw(ted::Position::after(&node), make::token(T![')']));
 +}
 +
 +fn process_references(
 +    ctx: &AssistContext<'_>,
 +    builder: &mut SourceChangeBuilder,
 +    visited_modules: &mut FxHashSet<Module>,
 +    enum_module_def: &ModuleDef,
 +    variant_hir_name: &Name,
 +    refs: Vec<FileReference>,
 +) -> Vec<(ast::PathSegment, SyntaxNode, Option<(ImportScope, hir::ModPath)>)> {
 +    // we have to recollect here eagerly as we are about to edit the tree we need to calculate the changes
 +    // and corresponding nodes up front
 +    refs.into_iter()
 +        .flat_map(|reference| {
 +            let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?;
 +            let segment = builder.make_mut(segment);
 +            let scope_node = builder.make_syntax_mut(scope_node);
 +            if !visited_modules.contains(&module) {
 +                let mod_path = module.find_use_path_prefixed(
 +                    ctx.sema.db,
 +                    *enum_module_def,
 +                    ctx.config.insert_use.prefix_kind,
++                    ctx.config.prefer_no_std,
 +                );
 +                if let Some(mut mod_path) = mod_path {
 +                    mod_path.pop_segment();
 +                    mod_path.push_segment(variant_hir_name.clone());
 +                    let scope = ImportScope::find_insert_use_container(&scope_node, &ctx.sema)?;
 +                    visited_modules.insert(module);
 +                    return Some((segment, scope_node, Some((scope, mod_path))));
 +                }
 +            }
 +            Some((segment, scope_node, None))
 +        })
 +        .collect()
 +}
 +
 +fn reference_to_node(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    reference: FileReference,
 +) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> {
 +    let segment =
 +        reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?;
 +    let parent = segment.parent_path().syntax().parent()?;
 +    let expr_or_pat = match_ast! {
 +        match parent {
 +            ast::PathExpr(_it) => parent.parent()?,
 +            ast::RecordExpr(_it) => parent,
 +            ast::TupleStructPat(_it) => parent,
 +            ast::RecordPat(_it) => parent,
 +            _ => return None,
 +        }
 +    };
 +    let module = sema.scope(&expr_or_pat)?.module();
 +    Some((segment, expr_or_pat, module))
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_extract_struct_several_fields_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, u32) }",
 +            r#"struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_several_fields_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One { foo: u32, bar: u32 } }",
 +            r#"struct One{ foo: u32, bar: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_one_field_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One { foo: u32 } }",
 +            r#"struct One{ foo: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_carries_over_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r"enum En<T> { Var { a: T$0 } }",
 +            r#"struct Var<T>{ a: T }
 +
 +enum En<T> { Var(Var<T>) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_carries_over_attributes() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +#[derive(Debug)]
 +#[derive(Clone)]
 +enum Enum { Variant{ field: u32$0 } }"#,
 +            r#"
 +#[derive(Debug)]
 +#[derive(Clone)]
 +struct Variant{ field: u32 }
 +
 +#[derive(Debug)]
 +#[derive(Clone)]
 +enum Enum { Variant(Variant) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_indent_to_parent_enum() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum Enum {
 +    Variant {
 +        field: u32$0
 +    }
 +}"#,
 +            r#"
 +struct Variant{
 +    field: u32
 +}
 +
 +enum Enum {
 +    Variant(Variant)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_indent_to_parent_enum_in_mod() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +mod indenting {
 +    enum Enum {
 +        Variant {
 +            field: u32$0
 +        }
 +    }
 +}"#,
 +            r#"
 +mod indenting {
 +    struct Variant{
 +        field: u32
 +    }
 +
 +    enum Enum {
 +        Variant(Variant)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_one_field_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    $0One {
 +        // leading comment
 +        /// doc comment
 +        #[an_attr]
 +        foo: u32
 +        // trailing comment
 +    }
 +}"#,
 +            r#"
 +struct One{
 +    // leading comment
 +    /// doc comment
 +    #[an_attr]
 +    foo: u32
 +    // trailing comment
 +}
 +
 +enum A {
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_several_fields_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    $0One {
 +        // comment
 +        /// doc
 +        #[attr]
 +        foo: u32,
 +        // comment
 +        #[attr]
 +        /// doc
 +        bar: u32
 +    }
 +}"#,
 +            r#"
 +struct One{
 +    // comment
 +    /// doc
 +    #[attr]
 +    foo: u32,
 +    // comment
 +    #[attr]
 +    /// doc
 +    bar: u32
 +}
 +
 +enum A {
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }",
 +            r#"
 +struct One(/* comment */ #[attr] u32, /* another */ u32 /* tail */);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_move_struct_variant_comments() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    /* comment */
 +    // other
 +    /// comment
 +    #[attr]
 +    $0One {
 +        a: u32
 +    }
 +}"#,
 +            r#"
 +/* comment */
 +// other
 +/// comment
 +struct One{
 +    a: u32
 +}
 +
 +enum A {
 +    #[attr]
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_move_tuple_variant_comments() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    /* comment */
 +    // other
 +    /// comment
 +    #[attr]
 +    $0One(u32, u32)
 +}"#,
 +            r#"
 +/* comment */
 +// other
 +/// comment
 +struct One(u32, u32);
 +
 +enum A {
 +    #[attr]
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_existing_visibility_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }",
 +            r#"
 +struct One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_existing_visibility_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, pub(crate) u32, pub(super) u32, u32) }",
 +            r#"
 +struct One(u32, pub(crate) u32, pub(super) u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_variant_name_value_namespace() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"const One: () = ();
 +enum A { $0One(u32, u32) }"#,
 +            r#"const One: () = ();
 +struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_no_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, u32) }",
 +            r#"
 +struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub enum A { $0One(u32, u32) }",
 +            r#"
 +pub struct One(pub u32, pub u32);
 +
 +pub enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_in_mod_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub(in something) enum A { $0One{ a: u32, b: u32 } }",
 +            r#"
 +pub(in something) struct One{ pub(in something) a: u32, pub(in something) b: u32 }
 +
 +pub(in something) enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_crate_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub(crate) enum A { $0One{ a: u32, b: u32, c: u32 } }",
 +            r#"
 +pub(crate) struct One{ pub(crate) a: u32, pub(crate) b: u32, pub(crate) c: u32 }
 +
 +pub(crate) enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_with_complex_imports() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"mod my_mod {
 +    fn another_fn() {
 +        let m = my_other_mod::MyEnum::MyField(1, 1);
 +    }
 +
 +    pub mod my_other_mod {
 +        fn another_fn() {
 +            let m = MyEnum::MyField(1, 1);
 +        }
 +
 +        pub enum MyEnum {
 +            $0MyField(u8, u8),
 +        }
 +    }
 +}
 +
 +fn another_fn() {
 +    let m = my_mod::my_other_mod::MyEnum::MyField(1, 1);
 +}"#,
 +            r#"use my_mod::my_other_mod::MyField;
 +
 +mod my_mod {
 +    use self::my_other_mod::MyField;
 +
 +    fn another_fn() {
 +        let m = my_other_mod::MyEnum::MyField(MyField(1, 1));
 +    }
 +
 +    pub mod my_other_mod {
 +        fn another_fn() {
 +            let m = MyEnum::MyField(MyField(1, 1));
 +        }
 +
 +        pub struct MyField(pub u8, pub u8);
 +
 +        pub enum MyEnum {
 +            MyField(MyField),
 +        }
 +    }
 +}
 +
 +fn another_fn() {
 +    let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1));
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_record_fix_references() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum E {
 +    $0V { i: i32, j: i32 }
 +}
 +
 +fn f() {
 +    let E::V { i, j } = E::V { i: 9, j: 2 };
 +}
 +"#,
 +            r#"
 +struct V{ i: i32, j: i32 }
 +
 +enum E {
 +    V(V)
 +}
 +
 +fn f() {
 +    let E::V(V { i, j }) = E::V(V { i: 9, j: 2 });
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn extract_record_fix_references2() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum E {
 +    $0V(i32, i32)
 +}
 +
 +fn f() {
 +    let E::V(i, j) = E::V(9, 2);
 +}
 +"#,
 +            r#"
 +struct V(i32, i32);
 +
 +enum E {
 +    V(V)
 +}
 +
 +fn f() {
 +    let E::V(V(i, j)) = E::V(V(9, 2));
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_several_files() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +//- /main.rs
 +enum E {
 +    $0V(i32, i32)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::E;
 +fn f() {
 +    let e = E::V(9, 2);
 +}
 +"#,
 +            r#"
 +//- /main.rs
 +struct V(i32, i32);
 +
 +enum E {
 +    V(V)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::{E, V};
 +fn f() {
 +    let e = E::V(V(9, 2));
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_several_files_record() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +//- /main.rs
 +enum E {
 +    $0V { i: i32, j: i32 }
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::E;
 +fn f() {
 +    let e = E::V { i: 9, j: 2 };
 +}
 +"#,
 +            r#"
 +//- /main.rs
 +struct V{ i: i32, j: i32 }
 +
 +enum E {
 +    V(V)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::{E, V};
 +fn f() {
 +    let e = E::V(V { i: 9, j: 2 });
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_record_nested_call_exp() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A { $0One { a: u32, b: u32 } }
 +
 +struct B(A);
 +
 +fn foo() {
 +    let _ = B(A::One { a: 1, b: 2 });
 +}
 +"#,
 +            r#"
 +struct One{ a: u32, b: u32 }
 +
 +enum A { One(One) }
 +
 +struct B(A);
 +
 +fn foo() {
 +    let _ = B(A::One(One { a: 1, b: 2 }));
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_not_applicable_for_element_with_no_fields() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r#"enum A { $0One }"#);
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_not_applicable_if_struct_exists() {
 +        cov_mark::check!(test_extract_enum_not_applicable_if_struct_exists);
 +        check_assist_not_applicable(
 +            extract_struct_from_enum_variant,
 +            r#"
 +struct One;
 +enum A { $0One(u8, u32) }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_one_field() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0One(u32) }");
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_no_field_tuple() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None() }");
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_no_field_named() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None {} }");
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_only_copies_needed_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'a, 'b, 'x> {
 +    $0A { a: &'a &'x mut () },
 +    B { b: &'b () },
 +    C { c: () },
 +}
 +"#,
 +            r#"
 +struct A<'a, 'x>{ a: &'a &'x mut () }
 +
 +enum X<'a, 'b, 'x> {
 +    A(A<'a, 'x>),
 +    B { b: &'b () },
 +    C { c: () },
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_with_liftime_type_const() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'b, T, V, const C: usize> {
 +    $0A { a: T, b: X<'b>, c: [u8; C] },
 +    D { d: V },
 +}
 +"#,
 +            r#"
 +struct A<'b, T, const C: usize>{ a: T, b: X<'b>, c: [u8; C] }
 +
 +enum X<'b, T, V, const C: usize> {
 +    A(A<'b, T, C>),
 +    D { d: V },
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_without_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'a, 'b> {
 +    A { a: &'a () },
 +    B { b: &'b () },
 +    $0C { c: () },
 +}
 +"#,
 +            r#"
 +struct C{ c: () }
 +
 +enum X<'a, 'b> {
 +    A { a: &'a () },
 +    B { b: &'b () },
 +    C(C),
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keeps_trait_bounds() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum En<T: TraitT, V: TraitV> {
 +    $0A { a: T },
 +    B { b: V },
 +}
 +"#,
 +            r#"
 +struct A<T: TraitT>{ a: T }
 +
 +enum En<T: TraitT, V: TraitV> {
 +    A(A<T>),
 +    B { b: V },
 +}
 +"#,
 +        );
 +    }
 +}
index b484635121eb230039fc12e8658d8f690170b0d9,0000000000000000000000000000000000000000..8f4405a8c869cf9273e481775f98bff95e63a24b
mode 100644,000000..100644
--- /dev/null
@@@ -1,343 -1,0 +1,345 @@@
-     let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
 +use std::fmt::Display;
 +
 +use hir::{ModPath, ModuleDef};
 +use ide_db::{famous_defs::FamousDefs, RootDatabase};
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SyntaxNode,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists, SourceChangeBuilder},
 +    utils::generate_trait_impl_text,
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: generate_deref
 +//
 +// Generate `Deref` impl using the given struct field.
 +//
 +// ```
 +// # //- minicore: deref, deref_mut
 +// struct A;
 +// struct B {
 +//    $0a: A
 +// }
 +// ```
 +// ->
 +// ```
 +// struct A;
 +// struct B {
 +//    a: A
 +// }
 +//
 +// impl core::ops::Deref for B {
 +//     type Target = A;
 +//
 +//     fn deref(&self) -> &Self::Target {
 +//         &self.a
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    generate_record_deref(acc, ctx).or_else(|| generate_tuple_deref(acc, ctx))
 +}
 +
 +fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let field = ctx.find_node_at_offset::<ast::RecordField>()?;
 +
 +    let deref_type_to_generate = match existing_deref_impl(&ctx.sema, &strukt) {
 +        None => DerefType::Deref,
 +        Some(DerefType::Deref) => DerefType::DerefMut,
 +        Some(DerefType::DerefMut) => {
 +            cov_mark::hit!(test_add_record_deref_impl_already_exists);
 +            return None;
 +        }
 +    };
 +
 +    let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
 +    let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
-     let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
++    let trait_path =
++        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
 +
 +    let field_type = field.ty()?;
 +    let field_name = field.name()?;
 +    let target = field.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_deref", AssistKind::Generate),
 +        format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field_name),
 +        target,
 +        |edit| {
 +            generate_edit(
 +                edit,
 +                strukt,
 +                field_type.syntax(),
 +                field_name.syntax(),
 +                deref_type_to_generate,
 +                trait_path,
 +            )
 +        },
 +    )
 +}
 +
 +fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let field = ctx.find_node_at_offset::<ast::TupleField>()?;
 +    let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
 +    let field_list_index =
 +        field_list.syntax().children().into_iter().position(|s| &s == field.syntax())?;
 +
 +    let deref_type_to_generate = match existing_deref_impl(&ctx.sema, &strukt) {
 +        None => DerefType::Deref,
 +        Some(DerefType::Deref) => DerefType::DerefMut,
 +        Some(DerefType::DerefMut) => {
 +            cov_mark::hit!(test_add_field_deref_impl_already_exists);
 +            return None;
 +        }
 +    };
 +
 +    let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
 +    let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
++    let trait_path =
++        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
 +
 +    let field_type = field.ty()?;
 +    let target = field.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_deref", AssistKind::Generate),
 +        format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field.syntax()),
 +        target,
 +        |edit| {
 +            generate_edit(
 +                edit,
 +                strukt,
 +                field_type.syntax(),
 +                field_list_index,
 +                deref_type_to_generate,
 +                trait_path,
 +            )
 +        },
 +    )
 +}
 +
 +fn generate_edit(
 +    edit: &mut SourceChangeBuilder,
 +    strukt: ast::Struct,
 +    field_type_syntax: &SyntaxNode,
 +    field_name: impl Display,
 +    deref_type: DerefType,
 +    trait_path: ModPath,
 +) {
 +    let start_offset = strukt.syntax().text_range().end();
 +    let impl_code = match deref_type {
 +        DerefType::Deref => format!(
 +            r#"    type Target = {0};
 +
 +    fn deref(&self) -> &Self::Target {{
 +        &self.{1}
 +    }}"#,
 +            field_type_syntax, field_name
 +        ),
 +        DerefType::DerefMut => format!(
 +            r#"    fn deref_mut(&mut self) -> &mut Self::Target {{
 +        &mut self.{}
 +    }}"#,
 +            field_name
 +        ),
 +    };
 +    let strukt_adt = ast::Adt::Struct(strukt);
 +    let deref_impl = generate_trait_impl_text(&strukt_adt, &trait_path.to_string(), &impl_code);
 +    edit.insert(start_offset, deref_impl);
 +}
 +
 +fn existing_deref_impl(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    strukt: &ast::Struct,
 +) -> Option<DerefType> {
 +    let strukt = sema.to_def(strukt)?;
 +    let krate = strukt.module(sema.db).krate();
 +
 +    let deref_trait = FamousDefs(sema, krate).core_ops_Deref()?;
 +    let deref_mut_trait = FamousDefs(sema, krate).core_ops_DerefMut()?;
 +    let strukt_type = strukt.ty(sema.db);
 +
 +    if strukt_type.impls_trait(sema.db, deref_trait, &[]) {
 +        if strukt_type.impls_trait(sema.db, deref_mut_trait, &[]) {
 +            Some(DerefType::DerefMut)
 +        } else {
 +            Some(DerefType::Deref)
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +#[derive(Debug)]
 +enum DerefType {
 +    Deref,
 +    DerefMut,
 +}
 +
 +impl DerefType {
 +    fn to_trait(
 +        &self,
 +        sema: &hir::Semantics<'_, RootDatabase>,
 +        krate: hir::Crate,
 +    ) -> Option<hir::Trait> {
 +        match self {
 +            DerefType::Deref => FamousDefs(sema, krate).core_ops_Deref(),
 +            DerefType::DerefMut => FamousDefs(sema, krate).core_ops_DerefMut(),
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_record_deref() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B { $0a: A }"#,
 +            r#"
 +struct A { }
 +struct B { a: A }
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.a
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_record_deref_short_path() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +struct A { }
 +struct B { $0a: A }"#,
 +            r#"
 +use core::ops::Deref;
 +struct A { }
 +struct B { a: A }
 +
 +impl Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.a
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_field_deref_idx_0() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B($0A);"#,
 +            r#"
 +struct A { }
 +struct B(A);
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}"#,
 +        );
 +    }
 +    #[test]
 +    fn test_generate_field_deref_idx_1() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B(u8, $0A);"#,
 +            r#"
 +struct A { }
 +struct B(u8, A);
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.1
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generates_derefmut_when_deref_present() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct B { $0a: u8 }
 +
 +impl core::ops::Deref for B {}
 +"#,
 +            r#"
 +struct B { a: u8 }
 +
 +impl core::ops::DerefMut for B {
 +    fn deref_mut(&mut self) -> &mut Self::Target {
 +        &mut self.a
 +    }
 +}
 +
 +impl core::ops::Deref for B {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_record_deref_not_applicable_if_already_impl() {
 +        cov_mark::check!(test_add_record_deref_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct A { }
 +struct B { $0a: A }
 +
 +impl core::ops::Deref for B {}
 +impl core::ops::DerefMut for B {}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_generate_field_deref_not_applicable_if_already_impl() {
 +        cov_mark::check!(test_add_field_deref_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct A { }
 +struct B($0A)
 +
 +impl core::ops::Deref for B {}
 +impl core::ops::DerefMut for B {}
 +"#,
 +        )
 +    }
 +}
index 6c93875e9eb62f2b0dd13e12068b19e1acedd543,0000000000000000000000000000000000000000..9cda74d9e0d31e4c41c65ed99b396d1cec982545
mode 100644,000000..100644
--- /dev/null
@@@ -1,495 -1,0 +1,498 @@@
-                 let type_path = current_module
-                     .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
 +use ide_db::{
 +    imports::import_assets::item_for_path_search, use_trivial_contructor::use_trivial_constructor,
 +};
 +use itertools::Itertools;
 +use stdx::format_to;
 +use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind};
 +
 +use crate::{
 +    utils::{find_impl_block_start, find_struct_impl, generate_impl_text},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_new
 +//
 +// Adds a `fn new` for a type.
 +//
 +// ```
 +// struct Ctx<T: Clone> {
 +//      data: T,$0
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Ctx<T: Clone> {
 +//      data: T,
 +// }
 +//
 +// impl<T: Clone> Ctx<T> {
 +//     fn $0new(data: T) -> Self { Self { data } }
 +// }
 +// ```
 +pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +
 +    // We want to only apply this to non-union structs with named fields
 +    let field_list = match strukt.kind() {
 +        StructKind::Record(named) => named,
 +        _ => return None,
 +    };
 +
 +    // Return early if we've found an existing new fn
 +    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), "new")?;
 +
 +    let current_module = ctx.sema.scope(strukt.syntax())?.module();
 +
 +    let target = strukt.syntax().text_range();
 +    acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
 +        let mut buf = String::with_capacity(512);
 +
 +        if impl_def.is_some() {
 +            buf.push('\n');
 +        }
 +
 +        let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
 +
 +        let trivial_constructors = field_list
 +            .fields()
 +            .map(|f| {
 +                let ty = ctx.sema.resolve_type(&f.ty()?)?;
 +
 +                let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
 +
++                let type_path = current_module.find_use_path(
++                    ctx.sema.db,
++                    item_for_path_search(ctx.sema.db, item_in_ns)?,
++                    ctx.config.prefer_no_std,
++                )?;
 +
 +                let expr = use_trivial_constructor(
 +                    &ctx.sema.db,
 +                    ide_db::helpers::mod_path_to_ast(&type_path),
 +                    &ty,
 +                )?;
 +
 +                Some(format!("{}: {}", f.name()?.syntax(), expr))
 +            })
 +            .collect::<Vec<_>>();
 +
 +        let params = field_list
 +            .fields()
 +            .enumerate()
 +            .filter_map(|(i, f)| {
 +                if trivial_constructors[i].is_none() {
 +                    Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))
 +                } else {
 +                    None
 +                }
 +            })
 +            .format(", ");
 +
 +        let fields = field_list
 +            .fields()
 +            .enumerate()
 +            .filter_map(|(i, f)| {
 +                let contructor = trivial_constructors[i].clone();
 +                if contructor.is_some() {
 +                    contructor
 +                } else {
 +                    Some(f.name()?.to_string())
 +                }
 +            })
 +            .format(", ");
 +
 +        format_to!(buf, "    {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
 +
 +        let start_offset = impl_def
 +            .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
 +            .unwrap_or_else(|| {
 +                buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
 +                strukt.syntax().text_range().end()
 +            });
 +
 +        match ctx.config.snippet_cap {
 +            None => builder.insert(start_offset, buf),
 +            Some(cap) => {
 +                buf = buf.replace("fn new", "fn $0new");
 +                builder.insert_snippet(cap, start_offset, buf);
 +            }
 +        }
 +    })
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_new_with_zst_fields() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty;
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty;
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new() -> Self { Self { empty: Empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty;
 +
 +struct Foo { baz: String, empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty;
 +
 +struct Foo { baz: String, empty: Empty }
 +
 +impl Foo {
 +    fn $0new(baz: String) -> Self { Self { baz, empty: Empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +enum Empty { Bar }
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +enum Empty { Bar }
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new() -> Self { Self { empty: Empty::Bar } }
 +}
 +"#,
 +        );
 +
 +        // make sure the assist only works on unit variants
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty {}
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty {}
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new(empty: Empty) -> Self { Self { empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +enum Empty { Bar {} }
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +enum Empty { Bar {} }
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new(empty: Empty) -> Self { Self { empty } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_new() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo<T: Clone> {$0}
 +"#,
 +            r#"
 +struct Foo<T: Clone> {}
 +
 +impl<T: Clone> Foo<T> {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo<'a, T: Foo<'a>> {$0}
 +"#,
 +            r#"
 +struct Foo<'a, T: Foo<'a>> {}
 +
 +impl<'a, T: Foo<'a>> Foo<'a, T> {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { baz: String $0}
 +"#,
 +            r#"
 +struct Foo { baz: String }
 +
 +impl Foo {
 +    fn $0new(baz: String) -> Self { Self { baz } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { baz: String, qux: Vec<i32> $0}
 +"#,
 +            r#"
 +struct Foo { baz: String, qux: Vec<i32> }
 +
 +impl Foo {
 +    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_that_visibility_modifiers_dont_get_brought_in() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { pub baz: String, pub qux: Vec<i32> $0}
 +"#,
 +            r#"
 +struct Foo { pub baz: String, pub qux: Vec<i32> }
 +
 +impl Foo {
 +    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_it_reuses_existing_impls() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn qux(&self) {}
 +}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +
 +    fn qux(&self) {}
 +}
 +"#,
 +        );
 +
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn qux(&self) {}
 +    fn baz() -> i32 {
 +        5
 +    }
 +}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +
 +    fn qux(&self) {}
 +    fn baz() -> i32 {
 +        5
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_visibility_of_new_fn_based_on_struct() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub struct Foo {$0}
 +"#,
 +            r#"
 +pub struct Foo {}
 +
 +impl Foo {
 +    pub fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub(crate) struct Foo {$0}
 +"#,
 +            r#"
 +pub(crate) struct Foo {}
 +
 +impl Foo {
 +    pub(crate) fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generate_new_not_applicable_if_fn_exists() {
 +        check_assist_not_applicable(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn new() -> Self {
 +        Self
 +    }
 +}
 +"#,
 +        );
 +
 +        check_assist_not_applicable(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn New() -> Self {
 +        Self
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generate_new_target() {
 +        check_assist_target(
 +            generate_new,
 +            r#"
 +struct SomeThingIrrelevant;
 +/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {$0}
 +struct EvenMoreIrrelevant;
 +"#,
 +            "/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {}",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_unrelated_new() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub struct AstId<N: AstNode> {
 +    file_id: HirFileId,
 +    file_ast_id: FileAstId<N>,
 +}
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
 +        AstId { file_id, file_ast_id }
 +    }
 +}
 +
 +pub struct Source<T> {
 +    pub file_id: HirFileId,$0
 +    pub ast: T,
 +}
 +
 +impl<T> Source<T> {
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
 +        Source { file_id: self.file_id, ast: f(self.ast) }
 +    }
 +}
 +"#,
 +            r#"
 +pub struct AstId<N: AstNode> {
 +    file_id: HirFileId,
 +    file_ast_id: FileAstId<N>,
 +}
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
 +        AstId { file_id, file_ast_id }
 +    }
 +}
 +
 +pub struct Source<T> {
 +    pub file_id: HirFileId,
 +    pub ast: T,
 +}
 +
 +impl<T> Source<T> {
 +    pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }
 +
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
 +        Source { file_id: self.file_id, ast: f(self.ast) }
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..92b2fa79d717bda9deeecb4811de419160c89b55
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,268 @@@
++use crate::{AssistContext, Assists};
++use ide_db::{
++    assists::{AssistId, AssistKind},
++    syntax_helpers::{
++        format_string::is_format_string,
++        format_string_exprs::{parse_format_exprs, Arg},
++    },
++};
++use itertools::Itertools;
++use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
++
++// Assist: move_format_string_arg
++//
++// Move an expression out of a format string.
++//
++// ```
++// macro_rules! format_args {
++//     ($lit:literal $(tt:tt)*) => { 0 },
++// }
++// macro_rules! print {
++//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
++// }
++//
++// fn main() {
++//     print!("{x + 1}$0");
++// }
++// ```
++// ->
++// ```
++// macro_rules! format_args {
++//     ($lit:literal $(tt:tt)*) => { 0 },
++// }
++// macro_rules! print {
++//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
++// }
++//
++// fn main() {
++//     print!("{}"$0, x + 1);
++// }
++// ```
++
++pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
++    let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
++    let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
++
++    let expanded_t = ast::String::cast(
++        ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone()),
++    )?;
++    if !is_format_string(&expanded_t) {
++        return None;
++    }
++
++    let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
++    if extracted_args.is_empty() {
++        return None;
++    }
++
++    acc.add(
++        AssistId(
++            "move_format_string_arg",
++            // if there aren't any expressions, then make the assist a RefactorExtract
++            if extracted_args.iter().filter(|f| matches!(f, Arg::Expr(_))).count() == 0 {
++                AssistKind::RefactorExtract
++            } else {
++                AssistKind::QuickFix
++            },
++        ),
++        "Extract format args",
++        tt.syntax().text_range(),
++        |edit| {
++            let fmt_range = fmt_string.syntax().text_range();
++
++            // Replace old format string with new format string whose arguments have been extracted
++            edit.replace(fmt_range, new_fmt);
++
++            // Insert cursor at end of format string
++            edit.insert(fmt_range.end(), "$0");
++
++            // Extract existing arguments in macro
++            let tokens =
++                tt.token_trees_and_tokens().filter_map(NodeOrToken::into_token).collect_vec();
++
++            let mut existing_args: Vec<String> = vec![];
++
++            let mut current_arg = String::new();
++            if let [_opening_bracket, format_string, _args_start_comma, tokens @ .., end_bracket] =
++                tokens.as_slice()
++            {
++                for t in tokens {
++                    if t.kind() == COMMA {
++                        existing_args.push(current_arg.trim().into());
++                        current_arg.clear();
++                    } else {
++                        current_arg.push_str(t.text());
++                    }
++                }
++                existing_args.push(current_arg.trim().into());
++
++                // delete everything after the format string till end bracket
++                // we're going to insert the new arguments later
++                edit.delete(TextRange::new(
++                    format_string.text_range().end(),
++                    end_bracket.text_range().start(),
++                ));
++            }
++
++            // Start building the new args
++            let mut existing_args = existing_args.into_iter();
++            let mut args = String::new();
++
++            let mut placeholder_idx = 1;
++
++            for extracted_args in extracted_args {
++                // remove expr from format string
++                args.push_str(", ");
++
++                match extracted_args {
++                    Arg::Ident(s) | Arg::Expr(s) => {
++                        // insert arg
++                        args.push_str(&s);
++                    }
++                    Arg::Placeholder => {
++                        // try matching with existing argument
++                        match existing_args.next() {
++                            Some(ea) => {
++                                args.push_str(&ea);
++                            }
++                            None => {
++                                // insert placeholder
++                                args.push_str(&format!("${placeholder_idx}"));
++                                placeholder_idx += 1;
++                            }
++                        }
++                    }
++                }
++            }
++
++            // Insert new args
++            edit.insert(fmt_range.end(), args);
++        },
++    );
++
++    Some(())
++}
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++    use crate::tests::check_assist;
++
++    const MACRO_DECL: &'static str = r#"
++macro_rules! format_args {
++    ($lit:literal $(tt:tt)*) => { 0 },
++}
++macro_rules! print {
++    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
++}
++"#;
++
++    fn add_macro_decl(s: &'static str) -> String {
++        MACRO_DECL.to_string() + s
++    }
++
++    #[test]
++    fn multiple_middle_arg() {
++        check_assist(
++            move_format_string_arg,
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {x + 1:b} {}$0", y + 2, 2);
++}
++"#,
++            ),
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {:b} {}"$0, y + 2, x + 1, 2);
++}
++"#,
++            ),
++        );
++    }
++
++    #[test]
++    fn single_arg() {
++        check_assist(
++            move_format_string_arg,
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{obj.value:b}$0",);
++}
++"#,
++            ),
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{:b}"$0, obj.value);
++}
++"#,
++            ),
++        );
++    }
++
++    #[test]
++    fn multiple_middle_placeholders_arg() {
++        check_assist(
++            move_format_string_arg,
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {x + 1:b} {} {}$0", y + 2, 2);
++}
++"#,
++            ),
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
++}
++"#,
++            ),
++        );
++    }
++
++    #[test]
++    fn multiple_trailing_args() {
++        check_assist(
++            move_format_string_arg,
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {x + 1:b} {Struct(1, 2)}$0", 1);
++}
++"#,
++            ),
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
++}
++"#,
++            ),
++        );
++    }
++
++    #[test]
++    fn improper_commas() {
++        check_assist(
++            move_format_string_arg,
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
++}
++"#,
++            ),
++            &add_macro_decl(
++                r#"
++fn main() {
++    print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
++}
++"#,
++            ),
++        );
++    }
++}
index 121f8b4a136839dfcf1a7f040cb9a7e317d3fb0d,0000000000000000000000000000000000000000..e57d1d065d6229361ca68604e8ace6c8b9331c1d
mode 100644,000000..100644
--- /dev/null
@@@ -1,548 -1,0 +1,551 @@@
-     let receiver_path = current_module
-         .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
 +use hir::{db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, ItemInNs, ModuleDef};
 +use ide_db::assists::{AssistId, AssistKind};
 +use syntax::{ast, AstNode};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    handlers::qualify_path::QualifyCandidate,
 +};
 +
 +// Assist: qualify_method_call
 +//
 +// Replaces the method call with a qualified function call.
 +//
 +// ```
 +// struct Foo;
 +// impl Foo {
 +//     fn foo(&self) {}
 +// }
 +// fn main() {
 +//     let foo = Foo;
 +//     foo.fo$0o();
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Foo;
 +// impl Foo {
 +//     fn foo(&self) {}
 +// }
 +// fn main() {
 +//     let foo = Foo;
 +//     Foo::foo(&foo);
 +// }
 +// ```
 +pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let name: ast::NameRef = ctx.find_node_at_offset()?;
 +    let call = name.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
 +
 +    let ident = name.ident_token()?;
 +
 +    let range = call.syntax().text_range();
 +    let resolved_call = ctx.sema.resolve_method_call(&call)?;
 +
 +    let current_module = ctx.sema.scope(call.syntax())?.module();
 +    let target_module_def = ModuleDef::from(resolved_call);
 +    let item_in_ns = ItemInNs::from(target_module_def);
++    let receiver_path = current_module.find_use_path(
++        ctx.sema.db,
++        item_for_path_search(ctx.sema.db, item_in_ns)?,
++        ctx.config.prefer_no_std,
++    )?;
 +
 +    let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
 +
 +    acc.add(
 +        AssistId("qualify_method_call", AssistKind::RefactorInline),
 +        format!("Qualify `{}` method call", ident.text()),
 +        range,
 +        |builder| {
 +            qualify_candidate.qualify(
 +                |replace_with: String| builder.replace(range, replace_with),
 +                &receiver_path,
 +                item_in_ns,
 +            )
 +        },
 +    );
 +    Some(())
 +}
 +
 +fn item_for_path_search(db: &dyn HirDatabase, item: ItemInNs) -> Option<ItemInNs> {
 +    Some(match item {
 +        ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
 +            Some(assoc_item) => match assoc_item.container(db) {
 +                AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
 +                AssocItemContainer::Impl(impl_) => match impl_.trait_(db) {
 +                    None => ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)),
 +                    Some(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
 +                },
 +            },
 +            None => item,
 +        },
 +        ItemInNs::Macros(_) => item,
 +    })
 +}
 +
 +fn item_as_assoc(db: &dyn HirDatabase, item: ItemInNs) -> Option<AssocItem> {
 +    item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    #[test]
 +    fn struct_method() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    foo.fo$0o()
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    Foo::foo(&foo)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_multi_params() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    foo.fo$0o(9, 9u)
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    Foo::foo(&foo, 9, 9u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_consume() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    foo.fo$0o(9, 9u)
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    Foo::foo(foo, 9, 9u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_exclusive() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&mut self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    foo.fo$0o(9, 9u)
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&mut self, p1: i32, p2: u32) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    Foo::foo(&mut foo, 9, 9u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_cross_crate() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let foo = dep::test_mod::Foo {};
 +    foo.fo$0o(9, 9u)
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub struct Foo;
 +    impl Foo {
 +        pub fn foo(&mut self, p1: i32, p2: u32) {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let foo = dep::test_mod::Foo {};
 +    dep::test_mod::Foo::foo(&mut foo, 9, 9u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_generic() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo<T>(&self) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    foo.fo$0o::<()>()
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo<T>(&self) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    Foo::foo::<()>(&foo)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od()
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    TestTrait::test_method(&test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_multi_params() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self, p1: i32, p2: u32) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od(12, 32u)
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self, p1: i32, p2: u32) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    TestTrait::test_method(&test_struct, 12, 32u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_consume() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(self, p1: i32, p2: u32) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od(12, 32u)
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(self, p1: i32, p2: u32) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    TestTrait::test_method(test_struct, 12, 32u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_exclusive() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&mut self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&mut self, p1: i32, p2: u32);
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od(12, 32u)
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&mut self, p1: i32, p2: u32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&mut self, p1: i32, p2: u32);
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    TestTrait::test_method(&mut test_struct, 12, 32u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_cross_crate() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let foo = dep::test_mod::Foo {};
 +    foo.fo$0o(9, 9u)
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub struct Foo;
 +    impl Foo {
 +        pub fn foo(&mut self, p1: i32, p2: u32) {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let foo = dep::test_mod::Foo {};
 +    dep::test_mod::Foo::foo(&mut foo, 9, 9u)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_generic() {
 +        check_assist(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method<T>(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method<T>(&self) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = TestStruct {};
 +    test_struct.test_meth$0od::<()>()
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method<T>(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method<T>(&self) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = TestStruct {};
 +    TestTrait::test_method::<()>(&test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_method_over_stuct_instance() {
 +        check_assist_not_applicable(
 +            qualify_method_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +
 +fn main() {
 +    let foo = Foo {};
 +    f$0oo.foo()
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_over_stuct_instance() {
 +        check_assist_not_applicable(
 +            qualify_method_call,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +use test_mod::*;
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    tes$0t_struct.test_method()
 +}
 +"#,
 +        );
 +    }
 +}
index 0c2e9da38639fbcf8844cace2d83bf71599724fa,0000000000000000000000000000000000000000..4b2af550bc5e4902c15bdf4a158ba6ee0bef6326
mode 100644,000000..100644
--- /dev/null
@@@ -1,1297 -1,0 +1,1298 @@@
-     let mut proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
 +use std::iter;
 +
 +use hir::AsAssocItem;
 +use ide_db::RootDatabase;
 +use ide_db::{
 +    helpers::mod_path_to_ast,
 +    imports::import_assets::{ImportCandidate, LocatedImport},
 +};
 +use syntax::{
 +    ast,
 +    ast::{make, HasArgList},
 +    AstNode, NodeOrToken,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    handlers::auto_import::find_importable_node,
 +    AssistId, AssistKind, GroupLabel,
 +};
 +
 +// Assist: qualify_path
 +//
 +// If the name is unresolved, provides all possible qualified paths for it.
 +//
 +// ```
 +// fn main() {
 +//     let map = HashMap$0::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +// ->
 +// ```
 +// fn main() {
 +//     let map = std::collections::HashMap::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
++    let mut proposed_imports =
++        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std);
 +    if proposed_imports.is_empty() {
 +        return None;
 +    }
 +
 +    let range = match &syntax_under_caret {
 +        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
 +        NodeOrToken::Token(token) => token.text_range(),
 +    };
 +    let candidate = import_assets.import_candidate();
 +    let qualify_candidate = match syntax_under_caret {
 +        NodeOrToken::Node(syntax_under_caret) => match candidate {
 +            ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
 +                cov_mark::hit!(qualify_path_qualifier_start);
 +                let path = ast::Path::cast(syntax_under_caret)?;
 +                let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
 +                QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
 +            }
 +            ImportCandidate::Path(_) => {
 +                cov_mark::hit!(qualify_path_unqualified_name);
 +                let path = ast::Path::cast(syntax_under_caret)?;
 +                let generics = path.segment()?.generic_arg_list();
 +                QualifyCandidate::UnqualifiedName(generics)
 +            }
 +            ImportCandidate::TraitAssocItem(_) => {
 +                cov_mark::hit!(qualify_path_trait_assoc_item);
 +                let path = ast::Path::cast(syntax_under_caret)?;
 +                let (qualifier, segment) = (path.qualifier()?, path.segment()?);
 +                QualifyCandidate::TraitAssocItem(qualifier, segment)
 +            }
 +            ImportCandidate::TraitMethod(_) => {
 +                cov_mark::hit!(qualify_path_trait_method);
 +                let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
 +                QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
 +            }
 +        },
 +        // derive attribute path
 +        NodeOrToken::Token(_) => QualifyCandidate::UnqualifiedName(None),
 +    };
 +
 +    // we aren't interested in different namespaces
 +    proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
 +
 +    let group_label = group_label(candidate);
 +    for import in proposed_imports {
 +        acc.add_group(
 +            &group_label,
 +            AssistId("qualify_path", AssistKind::QuickFix),
 +            label(candidate, &import),
 +            range,
 +            |builder| {
 +                qualify_candidate.qualify(
 +                    |replace_with: String| builder.replace(range, replace_with),
 +                    &import.import_path,
 +                    import.item_to_import,
 +                )
 +            },
 +        );
 +    }
 +    Some(())
 +}
 +pub(crate) enum QualifyCandidate<'db> {
 +    QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
 +    UnqualifiedName(Option<ast::GenericArgList>),
 +    TraitAssocItem(ast::Path, ast::PathSegment),
 +    TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
 +    ImplMethod(&'db RootDatabase, ast::MethodCallExpr, hir::Function),
 +}
 +
 +impl QualifyCandidate<'_> {
 +    pub(crate) fn qualify(
 +        &self,
 +        mut replacer: impl FnMut(String),
 +        import: &hir::ModPath,
 +        item: hir::ItemInNs,
 +    ) {
 +        let import = mod_path_to_ast(import);
 +        match self {
 +            QualifyCandidate::QualifierStart(segment, generics) => {
 +                let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
 +                replacer(format!("{}{}::{}", import, generics, segment));
 +            }
 +            QualifyCandidate::UnqualifiedName(generics) => {
 +                let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
 +                replacer(format!("{}{}", import, generics));
 +            }
 +            QualifyCandidate::TraitAssocItem(qualifier, segment) => {
 +                replacer(format!("<{} as {}>::{}", qualifier, import, segment));
 +            }
 +            QualifyCandidate::TraitMethod(db, mcall_expr) => {
 +                Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
 +            }
 +            QualifyCandidate::ImplMethod(db, mcall_expr, hir_fn) => {
 +                Self::qualify_fn_call(db, mcall_expr, replacer, import, hir_fn);
 +            }
 +        }
 +    }
 +
 +    fn qualify_fn_call(
 +        db: &RootDatabase,
 +        mcall_expr: &ast::MethodCallExpr,
 +        mut replacer: impl FnMut(String),
 +        import: ast::Path,
 +        hir_fn: &hir::Function,
 +    ) -> Option<()> {
 +        let receiver = mcall_expr.receiver()?;
 +        let method_name = mcall_expr.name_ref()?;
 +        let generics =
 +            mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
 +        let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
 +
 +        if let Some(self_access) = hir_fn.self_param(db).map(|sp| sp.access(db)) {
 +            let receiver = match self_access {
 +                hir::Access::Shared => make::expr_ref(receiver, false),
 +                hir::Access::Exclusive => make::expr_ref(receiver, true),
 +                hir::Access::Owned => receiver,
 +            };
 +            replacer(format!(
 +                "{}::{}{}{}",
 +                import,
 +                method_name,
 +                generics,
 +                match arg_list {
 +                    Some(args) => make::arg_list(iter::once(receiver).chain(args)),
 +                    None => make::arg_list(iter::once(receiver)),
 +                }
 +            ));
 +        }
 +        Some(())
 +    }
 +
 +    fn qualify_trait_method(
 +        db: &RootDatabase,
 +        mcall_expr: &ast::MethodCallExpr,
 +        replacer: impl FnMut(String),
 +        import: ast::Path,
 +        item: hir::ItemInNs,
 +    ) -> Option<()> {
 +        let trait_method_name = mcall_expr.name_ref()?;
 +        let trait_ = item_as_trait(db, item)?;
 +        let method = find_trait_method(db, trait_, &trait_method_name)?;
 +        Self::qualify_fn_call(db, mcall_expr, replacer, import, &method)
 +    }
 +}
 +
 +fn find_trait_method(
 +    db: &RootDatabase,
 +    trait_: hir::Trait,
 +    trait_method_name: &ast::NameRef,
 +) -> Option<hir::Function> {
 +    if let Some(hir::AssocItem::Function(method)) =
 +        trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
 +            item.name(db)
 +                .map(|name| name.to_string() == trait_method_name.to_string())
 +                .unwrap_or(false)
 +        })
 +    {
 +        Some(method)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
 +    let item_module_def = item.as_module_def()?;
 +
 +    match item_module_def {
 +        hir::ModuleDef::Trait(trait_) => Some(trait_),
 +        _ => item_module_def.as_assoc_item(db)?.containing_trait(db),
 +    }
 +}
 +
 +fn group_label(candidate: &ImportCandidate) -> GroupLabel {
 +    let name = match candidate {
 +        ImportCandidate::Path(it) => &it.name,
 +        ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
 +            &it.assoc_item_name
 +        }
 +    }
 +    .text();
 +    GroupLabel(format!("Qualify {}", name))
 +}
 +
 +fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
 +    match candidate {
 +        ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
 +            format!("Qualify as `{}`", import.import_path)
 +        }
 +        _ => format!("Qualify with `{}`", import.import_path),
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn applicable_when_found_an_import_partial() {
 +        cov_mark::check!(qualify_path_unqualified_name);
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod std {
 +    pub mod fmt {
 +        pub struct Formatter;
 +    }
 +}
 +
 +use std::fmt;
 +
 +$0Formatter
 +"#,
 +            r#"
 +mod std {
 +    pub mod fmt {
 +        pub struct Formatter;
 +    }
 +}
 +
 +use std::fmt;
 +
 +fmt::Formatter
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +$0PubStruct
 +
 +pub mod PubMod {
 +    pub struct PubStruct;
 +}
 +"#,
 +            r#"
 +PubMod::PubStruct
 +
 +pub mod PubMod {
 +    pub struct PubStruct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_in_macros() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +macro_rules! foo {
 +    ($i:ident) => { fn foo(a: $i) {} }
 +}
 +foo!(Pub$0Struct);
 +
 +pub mod PubMod {
 +    pub struct PubStruct;
 +}
 +"#,
 +            r#"
 +macro_rules! foo {
 +    ($i:ident) => { fn foo(a: $i) {} }
 +}
 +foo!(PubMod::PubStruct);
 +
 +pub mod PubMod {
 +    pub struct PubStruct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_multiple_imports() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +PubSt$0ruct
 +
 +pub mod PubMod1 {
 +    pub struct PubStruct;
 +}
 +pub mod PubMod2 {
 +    pub struct PubStruct;
 +}
 +pub mod PubMod3 {
 +    pub struct PubStruct;
 +}
 +"#,
 +            r#"
 +PubMod3::PubStruct
 +
 +pub mod PubMod1 {
 +    pub struct PubStruct;
 +}
 +pub mod PubMod2 {
 +    pub struct PubStruct;
 +}
 +pub mod PubMod3 {
 +    pub struct PubStruct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_already_imported_types() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +use PubMod::PubStruct;
 +
 +PubStruct$0
 +
 +pub mod PubMod {
 +    pub struct PubStruct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_types_with_private_paths() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +PrivateStruct$0
 +
 +pub mod PubMod {
 +    struct PrivateStruct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_no_imports_found() {
 +        check_assist_not_applicable(qualify_path, r#"PubStruct$0"#);
 +    }
 +
 +    #[test]
 +    fn qualify_function() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +test_function$0
 +
 +pub mod PubMod {
 +    pub fn test_function() {};
 +}
 +"#,
 +            r#"
 +PubMod::test_function
 +
 +pub mod PubMod {
 +    pub fn test_function() {};
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn qualify_macro() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- /lib.rs crate:crate_with_macro
 +#[macro_export]
 +macro_rules! foo {
 +    () => ()
 +}
 +
 +//- /main.rs crate:main deps:crate_with_macro
 +fn main() {
 +    foo$0
 +}
 +"#,
 +            r#"
 +fn main() {
 +    crate_with_macro::foo
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn qualify_path_target() {
 +        check_assist_target(
 +            qualify_path,
 +            r#"
 +struct AssistInfo {
 +    group_label: Option<$0GroupLabel>,
 +}
 +
 +mod m { pub struct GroupLabel; }
 +"#,
 +            "GroupLabel",
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_path_start_is_imported() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +pub mod mod1 {
 +    pub mod mod2 {
 +        pub mod mod3 {
 +            pub struct TestStruct;
 +        }
 +    }
 +}
 +
 +use mod1::mod2;
 +fn main() {
 +    mod2::mod3::TestStruct$0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_function() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +pub mod test_mod {
 +    pub fn test_function() {}
 +}
 +
 +use test_mod::test_function;
 +fn main() {
 +    test_function$0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_function() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct {}
 +    impl TestStruct {
 +        pub fn test_function() {}
 +    }
 +}
 +
 +fn main() {
 +    TestStruct::test_function$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct {}
 +    impl TestStruct {
 +        pub fn test_function() {}
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::test_function
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_const() {
 +        cov_mark::check!(qualify_path_qualifier_start);
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct {}
 +    impl TestStruct {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    TestStruct::TEST_CONST$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct {}
 +    impl TestStruct {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::TEST_CONST
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_const_unqualified() {
 +        // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct {}
 +    impl TestStruct {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    TEST_CONST$0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_trait_function() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_function();
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_function() {}
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::test_function$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_function();
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_function() {}
 +    }
 +}
 +
 +fn main() {
 +    <test_mod::TestStruct as test_mod::TestTrait>::test_function
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_function() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_function();
 +    }
 +    pub trait TestTrait2 {
 +        fn test_function();
 +    }
 +    pub enum TestEnum {
 +        One,
 +        Two,
 +    }
 +    impl TestTrait2 for TestEnum {
 +        fn test_function() {}
 +    }
 +    impl TestTrait for TestEnum {
 +        fn test_function() {}
 +    }
 +}
 +
 +use test_mod::TestTrait2;
 +fn main() {
 +    test_mod::TestEnum::test_function$0;
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn associated_trait_const() {
 +        cov_mark::check!(qualify_path_trait_assoc_item);
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        const TEST_CONST: u8;
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::TEST_CONST$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        const TEST_CONST: u8;
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_const() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        const TEST_CONST: u8;
 +    }
 +    pub trait TestTrait2 {
 +        const TEST_CONST: f64;
 +    }
 +    pub enum TestEnum {
 +        One,
 +        Two,
 +    }
 +    impl TestTrait2 for TestEnum {
 +        const TEST_CONST: f64 = 42.0;
 +    }
 +    impl TestTrait for TestEnum {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +use test_mod::TestTrait2;
 +fn main() {
 +    test_mod::TestEnum::TEST_CONST$0;
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn trait_method() {
 +        cov_mark::check!(qualify_path_trait_method);
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od()
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_mod::TestTrait::test_method(&test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_multi_params() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self, test: i32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self, test: i32) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od(42)
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self, test: i32);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self, test: i32) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_mod::TestTrait::test_method(&test_struct, 42)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_consume() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od()
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_mod::TestTrait::test_method(test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_cross_crate() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    test_struct.test_meth$0od()
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    dep::test_mod::TestTrait::test_method(&test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_cross_crate() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestStruct::test_func$0tion
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        fn test_function();
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_function() {}
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_const_cross_crate() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestStruct::CONST$0
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        const CONST: bool;
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const CONST: bool = true;
 +    }
 +}
 +"#,
 +            r#"
 +fn main() {
 +    <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_as_method_cross_crate() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    test_struct.test_func$0tion()
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        fn test_function();
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_function() {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn private_trait_cross_crate() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    test_struct.test_meth$0od()
 +}
 +//- /dep.rs crate:dep
 +pub mod test_mod {
 +    trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method(&self) {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_method() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method(&self);
 +    }
 +    pub trait TestTrait2 {
 +        fn test_method(&self);
 +    }
 +    pub enum TestEnum {
 +        One,
 +        Two,
 +    }
 +    impl TestTrait2 for TestEnum {
 +        fn test_method(&self) {}
 +    }
 +    impl TestTrait for TestEnum {
 +        fn test_method(&self) {}
 +    }
 +}
 +
 +use test_mod::TestTrait2;
 +fn main() {
 +    let one = test_mod::TestEnum::One;
 +    one.test$0_method();
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn dep_import() {
 +        check_assist(
 +            qualify_path,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct Struct;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Struct$0
 +}
 +",
 +            r"
 +fn main() {
 +    dep::Struct
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn whole_segment() {
 +        // Tests that only imports whose last segment matches the identifier get suggested.
 +        check_assist(
 +            qualify_path,
 +            r"
 +//- /lib.rs crate:dep
 +pub mod fmt {
 +    pub trait Display {}
 +}
 +
 +pub fn panic_fmt() {}
 +
 +//- /main.rs crate:main deps:dep
 +struct S;
 +
 +impl f$0mt::Display for S {}
 +",
 +            r"
 +struct S;
 +
 +impl dep::fmt::Display for S {}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_generated() {
 +        // Tests that macro-generated items are suggested from external crates.
 +        check_assist(
 +            qualify_path,
 +            r"
 +//- /lib.rs crate:dep
 +macro_rules! mac {
 +    () => {
 +        pub struct Cheese;
 +    };
 +}
 +
 +mac!();
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Cheese$0;
 +}
 +",
 +            r"
 +fn main() {
 +    dep::Cheese;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn casing() {
 +        // Tests that differently cased names don't interfere and we only suggest the matching one.
 +        check_assist(
 +            qualify_path,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct FMT;
 +pub struct fmt;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    FMT$0;
 +}
 +",
 +            r"
 +fn main() {
 +    dep::FMT;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn keep_generic_annotations() {
 +        check_assist(
 +            qualify_path,
 +            r"
 +//- /lib.rs crate:dep
 +pub mod generic { pub struct Thing<'a, T>(&'a T); }
 +
 +//- /main.rs crate:main deps:dep
 +fn foo() -> Thin$0g<'static, ()> {}
 +
 +fn main() {}
 +",
 +            r"
 +fn foo() -> dep::generic::Thing<'static, ()> {}
 +
 +fn main() {}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn keep_generic_annotations_leading_colon() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- /lib.rs crate:dep
 +pub mod generic { pub struct Thing<'a, T>(&'a T); }
 +
 +//- /main.rs crate:main deps:dep
 +fn foo() -> Thin$0g::<'static, ()> {}
 +
 +fn main() {}
 +"#,
 +            r"
 +fn foo() -> dep::generic::Thing::<'static, ()> {}
 +
 +fn main() {}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_const_generic() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct<T> {}
 +    impl<T> TestStruct<T> {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    TestStruct::<()>::TEST_CONST$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub struct TestStruct<T> {}
 +    impl<T> TestStruct<T> {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::<()>::TEST_CONST
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_trait_const_generic() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        const TEST_CONST: u8;
 +    }
 +    pub struct TestStruct<T> {}
 +    impl<T> TestTrait for TestStruct<T> {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    test_mod::TestStruct::<()>::TEST_CONST$0
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        const TEST_CONST: u8;
 +    }
 +    pub struct TestStruct<T> {}
 +    impl<T> TestTrait for TestStruct<T> {
 +        const TEST_CONST: u8 = 42;
 +    }
 +}
 +
 +fn main() {
 +    <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_generic() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method<T>(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method<T>(&self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_struct.test_meth$0od::<()>()
 +}
 +"#,
 +            r#"
 +mod test_mod {
 +    pub trait TestTrait {
 +        fn test_method<T>(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn test_method<T>(&self) {}
 +    }
 +}
 +
 +fn main() {
 +    let test_struct = test_mod::TestStruct {};
 +    test_mod::TestTrait::test_method::<()>(&test_struct)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_derives() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(Copy$0)]
 +struct Foo;
 +"#,
 +            r#"
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(foo::Copy)]
 +struct Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_use_start() {
 +        check_assist(
 +            qualify_path,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo$0::Foo;
 +"#,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use bar::foo::Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_in_non_start_use() {
 +        check_assist_not_applicable(
 +            qualify_path,
 +            r"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo::Foo$0;
 +",
 +        );
 +    }
 +}
index d139f78a6f36bc9ba5ab2b3941c7133e85b8e080,0000000000000000000000000000000000000000..9fd5e1886d206ef3dad043c6e29f2a4eb88b1219
mode 100644,000000..100644
--- /dev/null
@@@ -1,1250 -1,0 +1,1250 @@@
-             .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
 +use hir::{InFile, ModuleDef};
 +use ide_db::{
 +    helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator,
 +    syntax_helpers::insert_whitespace_into_node::insert_ws_into,
 +};
 +use itertools::Itertools;
 +use syntax::{
 +    ast::{self, AstNode, HasName},
 +    SyntaxKind::WHITESPACE,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists, SourceChangeBuilder},
 +    utils::{
 +        add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
 +        generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
 +    },
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: replace_derive_with_manual_impl
 +//
 +// Converts a `derive` impl into a manual one.
 +//
 +// ```
 +// # //- minicore: derive
 +// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +// #[derive(Deb$0ug, Display)]
 +// struct S;
 +// ```
 +// ->
 +// ```
 +// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +// #[derive(Display)]
 +// struct S;
 +//
 +// impl Debug for S {
 +//     $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
 +//         f.debug_struct("S").finish()
 +//     }
 +// }
 +// ```
 +pub(crate) fn replace_derive_with_manual_impl(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let attr = ctx.find_node_at_offset_with_descend::<ast::Attr>()?;
 +    let path = attr.path()?;
 +    let hir_file = ctx.sema.hir_file_for(attr.syntax());
 +    if !hir_file.is_derive_attr_pseudo_expansion(ctx.db()) {
 +        return None;
 +    }
 +
 +    let InFile { file_id, value } = hir_file.call_node(ctx.db())?;
 +    if file_id.is_macro() {
 +        // FIXME: make this work in macro files
 +        return None;
 +    }
 +    // collect the derive paths from the #[derive] expansion
 +    let current_derives = ctx
 +        .sema
 +        .parse_or_expand(hir_file)?
 +        .descendants()
 +        .filter_map(ast::Attr::cast)
 +        .filter_map(|attr| attr.path())
 +        .collect::<Vec<_>>();
 +
 +    let adt = value.parent().and_then(ast::Adt::cast)?;
 +    let attr = ast::Attr::cast(value)?;
 +    let args = attr.token_tree()?;
 +
 +    let current_module = ctx.sema.scope(adt.syntax())?.module();
 +    let current_crate = current_module.krate();
 +
 +    let found_traits = items_locator::items_with_name(
 +        &ctx.sema,
 +        current_crate,
 +        NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
 +        items_locator::AssocItemSearch::Exclude,
 +        Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +    )
 +    .filter_map(|item| match item.as_module_def()? {
 +        ModuleDef::Trait(trait_) => Some(trait_),
 +        _ => None,
 +    })
 +    .flat_map(|trait_| {
 +        current_module
++            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std)
 +            .as_ref()
 +            .map(mod_path_to_ast)
 +            .zip(Some(trait_))
 +    });
 +
 +    let mut no_traits_found = true;
 +    for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
 +        add_assist(
 +            acc,
 +            ctx,
 +            &attr,
 +            &current_derives,
 +            &args,
 +            &path,
 +            &replace_trait_path,
 +            Some(trait_),
 +            &adt,
 +        )?;
 +    }
 +    if no_traits_found {
 +        add_assist(acc, ctx, &attr, &current_derives, &args, &path, &path, None, &adt)?;
 +    }
 +    Some(())
 +}
 +
 +fn add_assist(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    attr: &ast::Attr,
 +    old_derives: &[ast::Path],
 +    old_tree: &ast::TokenTree,
 +    old_trait_path: &ast::Path,
 +    replace_trait_path: &ast::Path,
 +    trait_: Option<hir::Trait>,
 +    adt: &ast::Adt,
 +) -> Option<()> {
 +    let target = attr.syntax().text_range();
 +    let annotated_name = adt.name()?;
 +    let label = format!("Convert to manual `impl {} for {}`", replace_trait_path, annotated_name);
 +
 +    acc.add(
 +        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
 +        label,
 +        target,
 +        |builder| {
 +            let insert_pos = adt.syntax().text_range().end();
 +            let impl_def_with_items =
 +                impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
 +            update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
 +            let trait_path = replace_trait_path.to_string();
 +            match (ctx.config.snippet_cap, impl_def_with_items) {
 +                (None, _) => {
 +                    builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
 +                }
 +                (Some(cap), None) => builder.insert_snippet(
 +                    cap,
 +                    insert_pos,
 +                    generate_trait_impl_text(adt, &trait_path, "    $0"),
 +                ),
 +                (Some(cap), Some((impl_def, first_assoc_item))) => {
 +                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
 +                    let placeholder;
 +                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 +                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
 +                        {
 +                            if m.syntax().text() == "todo!()" {
 +                                placeholder = m;
 +                                cursor = Cursor::Replace(placeholder.syntax());
 +                            }
 +                        }
 +                    }
 +
 +                    builder.insert_snippet(
 +                        cap,
 +                        insert_pos,
 +                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
 +                    )
 +                }
 +            };
 +        },
 +    )
 +}
 +
 +fn impl_def_from_trait(
 +    sema: &hir::Semantics<'_, ide_db::RootDatabase>,
 +    adt: &ast::Adt,
 +    annotated_name: &ast::Name,
 +    trait_: Option<hir::Trait>,
 +    trait_path: &ast::Path,
 +) -> Option<(ast::Impl, ast::AssocItem)> {
 +    let trait_ = trait_?;
 +    let target_scope = sema.scope(annotated_name.syntax())?;
 +    let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
 +    if trait_items.is_empty() {
 +        return None;
 +    }
 +    let impl_def = {
 +        use syntax::ast::Impl;
 +        let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
 +        let parse = syntax::SourceFile::parse(&text);
 +        let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
 +            Some(it) => it,
 +            None => {
 +                panic!(
 +                    "Failed to make ast node `{}` from text {}",
 +                    std::any::type_name::<Impl>(),
 +                    text
 +                )
 +            }
 +        };
 +        let node = node.clone_subtree();
 +        assert_eq!(node.syntax().text_range().start(), 0.into());
 +        node
 +    };
 +
 +    let trait_items = trait_items
 +        .into_iter()
 +        .map(|it| {
 +            if sema.hir_file_for(it.syntax()).is_macro() {
 +                if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) {
 +                    return it;
 +                }
 +            }
 +            it.clone_for_update()
 +        })
 +        .collect();
 +    let (impl_def, first_assoc_item) =
 +        add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
 +
 +    // Generate a default `impl` function body for the derived trait.
 +    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 +        let _ = gen_trait_fn_body(func, trait_path, adt);
 +    };
 +
 +    Some((impl_def, first_assoc_item))
 +}
 +
 +fn update_attribute(
 +    builder: &mut SourceChangeBuilder,
 +    old_derives: &[ast::Path],
 +    old_tree: &ast::TokenTree,
 +    old_trait_path: &ast::Path,
 +    attr: &ast::Attr,
 +) {
 +    let new_derives = old_derives
 +        .iter()
 +        .filter(|t| t.to_string() != old_trait_path.to_string())
 +        .collect::<Vec<_>>();
 +    let has_more_derives = !new_derives.is_empty();
 +
 +    if has_more_derives {
 +        let new_derives = format!("({})", new_derives.iter().format(", "));
 +        builder.replace(old_tree.syntax().text_range(), new_derives);
 +    } else {
 +        let attr_range = attr.syntax().text_range();
 +        builder.delete(attr_range);
 +
 +        if let Some(line_break_range) = attr
 +            .syntax()
 +            .next_sibling_or_token()
 +            .filter(|t| t.kind() == WHITESPACE)
 +            .map(|t| t.text_range())
 +        {
 +            builder.delete(line_break_range);
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn add_custom_impl_debug_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +struct Foo {
 +    bar: String,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bar: String,
 +}
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        f.debug_struct("Foo").field("bar", &self.bar).finish()
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_debug_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +struct Foo(String, usize);
 +"#,
 +            r#"struct Foo(String, usize);
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        f.debug_tuple("Foo").field(&self.0).field(&self.1).finish()
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_debug_empty_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +struct Foo;
 +"#,
 +            r#"
 +struct Foo;
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        f.debug_struct("Foo").finish()
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_debug_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        match self {
 +            Self::Bar => write!(f, "Bar"),
 +            Self::Baz => write!(f, "Baz"),
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_debug_tuple_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +enum Foo {
 +    Bar(usize, usize),
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar(usize, usize),
 +    Baz,
 +}
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        match self {
 +            Self::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).finish(),
 +            Self::Baz => write!(f, "Baz"),
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_debug_record_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(Debu$0g)]
 +enum Foo {
 +    Bar {
 +        baz: usize,
 +        qux: usize,
 +    },
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar {
 +        baz: usize,
 +        qux: usize,
 +    },
 +    Baz,
 +}
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        match self {
 +            Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(),
 +            Self::Baz => write!(f, "Baz"),
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_default_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: default, derive
 +#[derive(Defau$0lt)]
 +struct Foo {
 +    foo: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    foo: usize,
 +}
 +
 +impl Default for Foo {
 +    $0fn default() -> Self {
 +        Self { foo: Default::default() }
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_default_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: default, derive
 +#[derive(Defau$0lt)]
 +struct Foo(usize);
 +"#,
 +            r#"
 +struct Foo(usize);
 +
 +impl Default for Foo {
 +    $0fn default() -> Self {
 +        Self(Default::default())
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_default_empty_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: default, derive
 +#[derive(Defau$0lt)]
 +struct Foo;
 +"#,
 +            r#"
 +struct Foo;
 +
 +impl Default for Foo {
 +    $0fn default() -> Self {
 +        Self {  }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_hash_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: hash, derive
 +#[derive(Has$0h)]
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +
 +impl core::hash::Hash for Foo {
 +    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
 +        self.bin.hash(state);
 +        self.bar.hash(state);
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_hash_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: hash, derive
 +#[derive(Has$0h)]
 +struct Foo(usize, usize);
 +"#,
 +            r#"
 +struct Foo(usize, usize);
 +
 +impl core::hash::Hash for Foo {
 +    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
 +        self.0.hash(state);
 +        self.1.hash(state);
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_hash_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: hash, derive
 +#[derive(Has$0h)]
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +
 +impl core::hash::Hash for Foo {
 +    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
 +        core::mem::discriminant(self).hash(state);
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        Self { bin: self.bin.clone(), bar: self.bar.clone() }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +struct Foo(usize, usize);
 +"#,
 +            r#"
 +struct Foo(usize, usize);
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        Self(self.0.clone(), self.1.clone())
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_empty_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +struct Foo;
 +"#,
 +            r#"
 +struct Foo;
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        Self {  }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        match self {
 +            Self::Bar => Self::Bar,
 +            Self::Baz => Self::Baz,
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_tuple_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +enum Foo {
 +    Bar(String),
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar(String),
 +    Baz,
 +}
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        match self {
 +            Self::Bar(arg0) => Self::Bar(arg0.clone()),
 +            Self::Baz => Self::Baz,
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_record_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +enum Foo {
 +    Bar {
 +        bin: String,
 +    },
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar {
 +        bin: String,
 +    },
 +    Baz,
 +}
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        match self {
 +            Self::Bar { bin } => Self::Bar { bin: bin.clone() },
 +            Self::Baz => Self::Baz,
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_ord_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: ord, derive
 +#[derive(Partial$0Ord)]
 +struct Foo {
 +    bin: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bin: usize,
 +}
 +
 +impl PartialOrd for Foo {
 +    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
 +        self.bin.partial_cmp(&other.bin)
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_ord_record_struct_multi_field() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: ord, derive
 +#[derive(Partial$0Ord)]
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +    baz: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +    baz: usize,
 +}
 +
 +impl PartialOrd for Foo {
 +    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
 +        match self.bin.partial_cmp(&other.bin) {
 +            Some(core::cmp::Ordering::Equal) => {}
 +            ord => return ord,
 +        }
 +        match self.bar.partial_cmp(&other.bar) {
 +            Some(core::cmp::Ordering::Equal) => {}
 +            ord => return ord,
 +        }
 +        self.baz.partial_cmp(&other.baz)
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_ord_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: ord, derive
 +#[derive(Partial$0Ord)]
 +struct Foo(usize, usize, usize);
 +"#,
 +            r#"
 +struct Foo(usize, usize, usize);
 +
 +impl PartialOrd for Foo {
 +    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
 +        match self.0.partial_cmp(&other.0) {
 +            Some(core::cmp::Ordering::Equal) => {}
 +            ord => return ord,
 +        }
 +        match self.1.partial_cmp(&other.1) {
 +            Some(core::cmp::Ordering::Equal) => {}
 +            ord => return ord,
 +        }
 +        self.2.partial_cmp(&other.2)
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    bin: usize,
 +    bar: usize,
 +}
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        self.bin == other.bin && self.bar == other.bar
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_tuple_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +struct Foo(usize, usize);
 +"#,
 +            r#"
 +struct Foo(usize, usize);
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        self.0 == other.0 && self.1 == other.1
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_empty_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +struct Foo;
 +"#,
 +            r#"
 +struct Foo;
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        true
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        core::mem::discriminant(self) == core::mem::discriminant(other)
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_tuple_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +enum Foo {
 +    Bar(String),
 +    Baz,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar(String),
 +    Baz,
 +}
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
 +            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_partial_eq_record_enum() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: eq, derive
 +#[derive(Partial$0Eq)]
 +enum Foo {
 +    Bar {
 +        bin: String,
 +    },
 +    Baz {
 +        qux: String,
 +        fez: String,
 +    },
 +    Qux {},
 +    Bin,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar {
 +        bin: String,
 +    },
 +    Baz {
 +        qux: String,
 +        fez: String,
 +    },
 +    Qux {},
 +    Bin,
 +}
 +
 +impl PartialEq for Foo {
 +    $0fn eq(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
 +            (Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => l_qux == r_qux && l_fez == r_fez,
 +            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
 +        }
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_all() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +mod foo {
 +    pub trait Bar {
 +        type Qux;
 +        const Baz: usize = 42;
 +        const Fez: usize;
 +        fn foo();
 +        fn bar() {}
 +    }
 +}
 +
 +#[derive($0Bar)]
 +struct Foo {
 +    bar: String,
 +}
 +"#,
 +            r#"
 +mod foo {
 +    pub trait Bar {
 +        type Qux;
 +        const Baz: usize = 42;
 +        const Fez: usize;
 +        fn foo();
 +        fn bar() {}
 +    }
 +}
 +
 +struct Foo {
 +    bar: String,
 +}
 +
 +impl foo::Bar for Foo {
 +    $0type Qux;
 +
 +    const Baz: usize = 42;
 +
 +    const Fez: usize;
 +
 +    fn foo() {
 +        todo!()
 +    }
 +}
 +"#,
 +        )
 +    }
 +    #[test]
 +    fn add_custom_impl_for_unique_input_unknown() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +#[derive(Debu$0g)]
 +struct Foo {
 +    bar: String,
 +}
 +            "#,
 +            r#"
 +struct Foo {
 +    bar: String,
 +}
 +
 +impl Debug for Foo {
 +    $0
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_for_with_visibility_modifier() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +#[derive(Debug$0)]
 +pub struct Foo {
 +    bar: String,
 +}
 +            "#,
 +            r#"
 +pub struct Foo {
 +    bar: String,
 +}
 +
 +impl Debug for Foo {
 +    $0
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_when_multiple_inputs() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +#[derive(Display, Debug$0, Serialize)]
 +struct Foo {}
 +            "#,
 +            r#"
 +#[derive(Display, Serialize)]
 +struct Foo {}
 +
 +impl Debug for Foo {
 +    $0
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_default_generic_record_struct() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: default, derive
 +#[derive(Defau$0lt)]
 +struct Foo<T, U> {
 +    foo: T,
 +    bar: U,
 +}
 +"#,
 +            r#"
 +struct Foo<T, U> {
 +    foo: T,
 +    bar: U,
 +}
 +
 +impl<T, U> Default for Foo<T, U> {
 +    $0fn default() -> Self {
 +        Self { foo: Default::default(), bar: Default::default() }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_clone_generic_tuple_struct_with_bounds() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(Clo$0ne)]
 +struct Foo<T: Clone>(T, usize);
 +"#,
 +            r#"
 +struct Foo<T: Clone>(T, usize);
 +
 +impl<T: Clone> Clone for Foo<T> {
 +    $0fn clone(&self) -> Self {
 +        Self(self.0.clone(), self.1.clone())
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_ignore_derive_macro_without_input() {
 +        check_assist_not_applicable(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +#[derive($0)]
 +struct Foo {}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_ignore_if_cursor_on_param() {
 +        check_assist_not_applicable(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive, fmt
 +#[derive$0(Debug)]
 +struct Foo {}
 +            "#,
 +        );
 +
 +        check_assist_not_applicable(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive, fmt
 +#[derive(Debug)$0]
 +struct Foo {}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_ignore_if_not_derive() {
 +        check_assist_not_applicable(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive
 +#[allow(non_camel_$0case_types)]
 +struct Foo {}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn works_at_start_of_file() {
 +        check_assist_not_applicable(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: derive, fmt
 +$0#[derive(Debug)]
 +struct S;
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_keep_path() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: clone, derive
 +#[derive(std::fmt::Debug, Clo$0ne)]
 +pub struct Foo;
 +"#,
 +            r#"
 +#[derive(std::fmt::Debug)]
 +pub struct Foo;
 +
 +impl Clone for Foo {
 +    $0fn clone(&self) -> Self {
 +        Self {  }
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_custom_impl_replace_path() {
 +        check_assist(
 +            replace_derive_with_manual_impl,
 +            r#"
 +//- minicore: fmt, derive
 +#[derive(core::fmt::Deb$0ug, Clone)]
 +pub struct Foo;
 +"#,
 +            r#"
 +#[derive(Clone)]
 +pub struct Foo;
 +
 +impl core::fmt::Debug for Foo {
 +    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 +        f.debug_struct("Foo").finish()
 +    }
 +}
 +"#,
 +        )
 +    }
 +}
index 2419fa11c155428b66899b88589c8c22833bb2f6,0000000000000000000000000000000000000000..dbbc56958f1e2ede4419e6887073c662bdc9f40e
mode 100644,000000..100644
--- /dev/null
@@@ -1,438 -1,0 +1,439 @@@
 +use hir::AsAssocItem;
 +use ide_db::{
 +    helpers::mod_path_to_ast,
 +    imports::insert_use::{insert_use, ImportScope},
 +};
 +use syntax::{
 +    ast::{self, make},
 +    match_ast, ted, AstNode, SyntaxNode,
 +};
 +
 +use crate::{AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: replace_qualified_name_with_use
 +//
 +// Adds a use statement for a given fully-qualified name.
 +//
 +// ```
 +// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +// fn process(map: std::collections::$0HashMap<String, String>) {}
 +// ```
 +// ->
 +// ```
 +// use std::collections::HashMap;
 +//
 +// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +// fn process(map: HashMap<String, String>) {}
 +// ```
 +pub(crate) fn replace_qualified_name_with_use(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let path: ast::Path = ctx.find_node_at_offset()?;
 +    // We don't want to mess with use statements
 +    if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
 +        cov_mark::hit!(not_applicable_in_use);
 +        return None;
 +    }
 +
 +    if path.qualifier().is_none() {
 +        cov_mark::hit!(dont_import_trivial_paths);
 +        return None;
 +    }
 +
 +    // only offer replacement for non assoc items
 +    match ctx.sema.resolve_path(&path)? {
 +        hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
 +        _ => return None,
 +    }
 +    // then search for an import for the first path segment of what we want to replace
 +    // that way it is less likely that we import the item from a different location due re-exports
 +    let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? {
 +        hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
 +        _ => return None,
 +    };
 +
 +    let starts_with_name_ref = !matches!(
 +        path.first_segment().and_then(|it| it.kind()),
 +        Some(
 +            ast::PathSegmentKind::CrateKw
 +                | ast::PathSegmentKind::SuperKw
 +                | ast::PathSegmentKind::SelfKw
 +        )
 +    );
 +    let path_to_qualifier = starts_with_name_ref
 +        .then(|| {
 +            ctx.sema.scope(path.syntax())?.module().find_use_path_prefixed(
 +                ctx.sema.db,
 +                module,
 +                ctx.config.insert_use.prefix_kind,
++                ctx.config.prefer_no_std,
 +            )
 +        })
 +        .flatten();
 +
 +    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
 +    let target = path.syntax().text_range();
 +    acc.add(
 +        AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
 +        "Replace qualified path with use",
 +        target,
 +        |builder| {
 +            // Now that we've brought the name into scope, re-qualify all paths that could be
 +            // affected (that is, all paths inside the node we added the `use` to).
 +            let scope = match scope {
 +                ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
 +                ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
 +                ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
 +            };
 +            shorten_paths(scope.as_syntax_node(), &path);
 +            let path = drop_generic_args(&path);
 +            // stick the found import in front of the to be replaced path
 +            let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) {
 +                Some(qualifier) => make::path_concat(qualifier, path),
 +                None => path,
 +            };
 +            insert_use(&scope, path, &ctx.config.insert_use);
 +        },
 +    )
 +}
 +
 +fn drop_generic_args(path: &ast::Path) -> ast::Path {
 +    let path = path.clone_for_update();
 +    if let Some(segment) = path.segment() {
 +        if let Some(generic_args) = segment.generic_arg_list() {
 +            ted::remove(generic_args.syntax());
 +        }
 +    }
 +    path
 +}
 +
 +/// Mutates `node` to shorten `path` in all descendants of `node`.
 +fn shorten_paths(node: &SyntaxNode, path: &ast::Path) {
 +    for child in node.children() {
 +        match_ast! {
 +            match child {
 +                // Don't modify `use` items, as this can break the `use` item when injecting a new
 +                // import into the use tree.
 +                ast::Use(_) => continue,
 +                // Don't descend into submodules, they don't have the same `use` items in scope.
 +                // FIXME: This isn't true due to `super::*` imports?
 +                ast::Module(_) => continue,
 +                ast::Path(p) => if maybe_replace_path(p.clone(), path.clone()).is_none() {
 +                    shorten_paths(p.syntax(), path);
 +                },
 +                _ => shorten_paths(&child, path),
 +            }
 +        }
 +    }
 +}
 +
 +fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
 +    if !path_eq_no_generics(path.clone(), target) {
 +        return None;
 +    }
 +
 +    // Shorten `path`, leaving only its last segment.
 +    if let Some(parent) = path.qualifier() {
 +        ted::remove(parent.syntax());
 +    }
 +    if let Some(double_colon) = path.coloncolon_token() {
 +        ted::remove(&double_colon);
 +    }
 +
 +    Some(())
 +}
 +
 +fn path_eq_no_generics(lhs: ast::Path, rhs: ast::Path) -> bool {
 +    let mut lhs_curr = lhs;
 +    let mut rhs_curr = rhs;
 +    loop {
 +        match lhs_curr.segment().zip(rhs_curr.segment()) {
 +            Some((lhs, rhs))
 +                if lhs.coloncolon_token().is_some() == rhs.coloncolon_token().is_some()
 +                    && lhs
 +                        .name_ref()
 +                        .zip(rhs.name_ref())
 +                        .map_or(false, |(lhs, rhs)| lhs.text() == rhs.text()) => {}
 +            _ => return false,
 +        }
 +
 +        match (lhs_curr.qualifier(), rhs_curr.qualifier()) {
 +            (Some(lhs), Some(rhs)) => {
 +                lhs_curr = lhs;
 +                rhs_curr = rhs;
 +            }
 +            (None, None) => return true,
 +            _ => return false,
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_replace_already_imported() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fs { pub struct Path; } }
 +use std::fs;
 +
 +fn main() {
 +    std::f$0s::Path
 +}",
 +            r"
 +mod std { pub mod fs { pub struct Path; } }
 +use std::fs;
 +
 +fn main() {
 +    fs::Path
 +}",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_replace_add_use_no_anchor() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fs { pub struct Path; } }
 +std::fs::Path$0
 +    ",
 +            r"
 +use std::fs::Path;
 +
 +mod std { pub mod fs { pub struct Path; } }
 +Path
 +    ",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_replace_add_use_no_anchor_middle_segment() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fs { pub struct Path; } }
 +std::fs$0::Path
 +    ",
 +            r"
 +use std::fs;
 +
 +mod std { pub mod fs { pub struct Path; } }
 +fs::Path
 +    ",
 +        );
 +    }
 +
 +    #[test]
 +    fn dont_import_trivial_paths() {
 +        cov_mark::check!(dont_import_trivial_paths);
 +        check_assist_not_applicable(replace_qualified_name_with_use, r"impl foo$0 for () {}");
 +    }
 +
 +    #[test]
 +    fn test_replace_not_applicable_in_use() {
 +        cov_mark::check!(not_applicable_in_use);
 +        check_assist_not_applicable(replace_qualified_name_with_use, r"use std::fmt$0;");
 +    }
 +
 +    #[test]
 +    fn replaces_all_affected_paths() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fmt { pub trait Debug {} } }
 +fn main() {
 +    std::fmt::Debug$0;
 +    let x: std::fmt::Debug = std::fmt::Debug;
 +}
 +    ",
 +            r"
 +use std::fmt::Debug;
 +
 +mod std { pub mod fmt { pub trait Debug {} } }
 +fn main() {
 +    Debug;
 +    let x: Debug = Debug;
 +}
 +    ",
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_replace_in_submodules() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fmt { pub trait Debug {} } }
 +fn main() {
 +    std::fmt::Debug$0;
 +}
 +
 +mod sub {
 +    fn f() {
 +        std::fmt::Debug;
 +    }
 +}
 +    ",
 +            r"
 +use std::fmt::Debug;
 +
 +mod std { pub mod fmt { pub trait Debug {} } }
 +fn main() {
 +    Debug;
 +}
 +
 +mod sub {
 +    fn f() {
 +        std::fmt::Debug;
 +    }
 +}
 +    ",
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_replace_in_use() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std { pub mod fmt { pub trait Display {} } }
 +use std::fmt::Display;
 +
 +fn main() {
 +    std::fmt$0;
 +}
 +    ",
 +            r"
 +mod std { pub mod fmt { pub trait Display {} } }
 +use std::fmt::{Display, self};
 +
 +fn main() {
 +    fmt;
 +}
 +    ",
 +        );
 +    }
 +
 +    #[test]
 +    fn does_not_replace_assoc_item_path() {
 +        check_assist_not_applicable(
 +            replace_qualified_name_with_use,
 +            r"
 +pub struct Foo;
 +impl Foo {
 +    pub fn foo() {}
 +}
 +
 +fn main() {
 +    Foo::foo$0();
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_reuses_path_qualifier() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +pub mod foo {
 +    pub struct Foo;
 +}
 +
 +mod bar {
 +    pub use super::foo::Foo as Bar;
 +}
 +
 +fn main() {
 +    foo::Foo$0;
 +}
 +",
 +            r"
 +use foo::Foo;
 +
 +pub mod foo {
 +    pub struct Foo;
 +}
 +
 +mod bar {
 +    pub use super::foo::Foo as Bar;
 +}
 +
 +fn main() {
 +    Foo;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_does_not_always_try_to_replace_by_full_item_path() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +use std::mem;
 +
 +mod std {
 +    pub mod mem {
 +        pub fn drop<T>(_: T) {}
 +    }
 +}
 +
 +fn main() {
 +    mem::drop$0(0);
 +}
 +",
 +            r"
 +use std::mem::{self, drop};
 +
 +mod std {
 +    pub mod mem {
 +        pub fn drop<T>(_: T) {}
 +    }
 +}
 +
 +fn main() {
 +    drop(0);
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_should_drop_generic_args_in_use() {
 +        check_assist(
 +            replace_qualified_name_with_use,
 +            r"
 +mod std {
 +    pub mod mem {
 +        pub fn drop<T>(_: T) {}
 +    }
 +}
 +
 +fn main() {
 +    std::mem::drop::<usize>$0(0);
 +}
 +",
 +            r"
 +use std::mem::drop;
 +
 +mod std {
 +    pub mod mem {
 +        pub fn drop<T>(_: T) {}
 +    }
 +}
 +
 +fn main() {
 +    drop::<usize>(0);
 +}
 +",
 +        );
 +    }
 +}
index e52544db5f530ff969735c4a25b305c64c5491ae,0000000000000000000000000000000000000000..812d22efbd797c42bc533d20c9a477207481aad6
mode 100644,000000..100644
--- /dev/null
@@@ -1,317 -1,0 +1,319 @@@
 +//! `assists` crate provides a bunch of code assists, also known as code actions
 +//! (in LSP) or intentions (in IntelliJ).
 +//!
 +//! An assist is a micro-refactoring, which is automatically activated in
 +//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
 +//! becomes available.
 +//!
 +//! ## Assists Guidelines
 +//!
 +//! Assists are the main mechanism to deliver advanced IDE features to the user,
 +//! so we should pay extra attention to the UX.
 +//!
 +//! The power of assists comes from their context-awareness. The main problem
 +//! with IDE features is that there are a lot of them, and it's hard to teach
 +//! the user what's available. Assists solve this problem nicely: 💡 signifies
 +//! that *something* is possible, and clicking on it reveals a *short* list of
 +//! actions. Contrast it with Emacs `M-x`, which just spits an infinite list of
 +//! all the features.
 +//!
 +//! Here are some considerations when creating a new assist:
 +//!
 +//! * It's good to preserve semantics, and it's good to keep the code compiling,
 +//!   but it isn't necessary. Example: "flip binary operation" might change
 +//!   semantics.
 +//! * Assist shouldn't necessary make the code "better". A lot of assist come in
 +//!   pairs: "if let <-> match".
 +//! * Assists should have as narrow scope as possible. Each new assists greatly
 +//!   improves UX for cases where the user actually invokes it, but it makes UX
 +//!   worse for every case where the user clicks 💡 to invoke some *other*
 +//!   assist. So, a rarely useful assist which is always applicable can be a net
 +//!   negative.
 +//! * Rarely useful actions are tricky. Sometimes there are features which are
 +//!   clearly useful to some users, but are just noise most of the time. We
 +//!   don't have a good solution here, our current approach is to make this
 +//!   functionality available only if assist is applicable to the whole
 +//!   selection. Example: `sort_items` sorts items alphabetically. Naively, it
 +//!   should be available more or less everywhere, which isn't useful. So
 +//!   instead we only show it if the user *selects* the items they want to sort.
 +//! * Consider grouping related assists together (see [`Assists::add_group`]).
 +//! * Make assists robust. If the assist depends on results of type-inference too
 +//!   much, it might only fire in fully-correct code. This makes assist less
 +//!   useful and (worse) less predictable. The user should have a clear
 +//!   intuition when each particular assist is available.
 +//! * Make small assists, which compose. Example: rather than auto-importing
 +//!   enums in `add_missing_match_arms`, we use fully-qualified names. There's a
 +//!   separate assist to shorten a fully-qualified name.
 +//! * Distinguish between assists and fixits for diagnostics. Internally, fixits
 +//!   and assists are equivalent. They have the same "show a list + invoke a
 +//!   single element" workflow, and both use [`Assist`] data structure. The main
 +//!   difference is in the UX: while 💡 looks only at the cursor position,
 +//!   diagnostics squigglies and fixits are calculated for the whole file and
 +//!   are presented to the user eagerly. So, diagnostics should be fixable
 +//!   errors, while assists can be just suggestions for an alternative way to do
 +//!   something. If something *could* be a diagnostic, it should be a
 +//!   diagnostic. Conversely, it might be valuable to turn a diagnostic with a
 +//!   lot of false errors into an assist.
 +//!
 +//! See also this post:
 +//! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod assist_config;
 +mod assist_context;
 +#[cfg(test)]
 +mod tests;
 +pub mod utils;
 +
 +use hir::Semantics;
 +use ide_db::{base_db::FileRange, RootDatabase};
 +use syntax::TextRange;
 +
 +pub(crate) use crate::assist_context::{AssistContext, Assists};
 +
 +pub use assist_config::AssistConfig;
 +pub use ide_db::assists::{
 +    Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
 +};
 +
 +/// Return all the assists applicable at the given position.
 +///
 +// NOTE: We don't have a `Feature: ` section for assists, they are special-cased
 +// in the manual.
 +pub fn assists(
 +    db: &RootDatabase,
 +    config: &AssistConfig,
 +    resolve: AssistResolveStrategy,
 +    range: FileRange,
 +) -> Vec<Assist> {
 +    let sema = Semantics::new(db);
 +    let ctx = AssistContext::new(sema, config, range);
 +    let mut acc = Assists::new(&ctx, resolve);
 +    handlers::all().iter().for_each(|handler| {
 +        handler(&mut acc, &ctx);
 +    });
 +    acc.finish()
 +}
 +
 +mod handlers {
 +    use crate::{AssistContext, Assists};
 +
 +    pub(crate) type Handler = fn(&mut Assists, &AssistContext<'_>) -> Option<()>;
 +
 +    mod add_explicit_type;
 +    mod add_label_to_loop;
 +    mod add_lifetime_to_type;
 +    mod add_missing_impl_members;
 +    mod add_turbo_fish;
 +    mod apply_demorgan;
 +    mod auto_import;
 +    mod change_visibility;
 +    mod convert_bool_then;
 +    mod convert_comment_block;
 +    mod convert_integer_literal;
 +    mod convert_into_to_from;
 +    mod convert_iter_for_each_to_for;
 +    mod convert_let_else_to_match;
 +    mod convert_tuple_struct_to_named_struct;
 +    mod convert_to_guarded_return;
 +    mod convert_two_arm_bool_match_to_matches_macro;
 +    mod convert_while_to_loop;
 +    mod destructure_tuple_binding;
 +    mod expand_glob_import;
 +    mod extract_function;
 +    mod extract_module;
 +    mod extract_struct_from_enum_variant;
 +    mod extract_type_alias;
 +    mod extract_variable;
 +    mod add_missing_match_arms;
 +    mod fix_visibility;
 +    mod flip_binexpr;
 +    mod flip_comma;
 +    mod flip_trait_bound;
++    mod move_format_string_arg;
 +    mod generate_constant;
 +    mod generate_default_from_enum_variant;
 +    mod generate_default_from_new;
 +    mod generate_deref;
 +    mod generate_derive;
 +    mod generate_documentation_template;
 +    mod generate_enum_is_method;
 +    mod generate_enum_projection_method;
 +    mod generate_enum_variant;
 +    mod generate_from_impl_for_enum;
 +    mod generate_function;
 +    mod generate_getter;
 +    mod generate_impl;
 +    mod generate_is_empty_from_len;
 +    mod generate_new;
 +    mod generate_setter;
 +    mod generate_delegate_methods;
 +    mod add_return_type;
 +    mod inline_call;
 +    mod inline_local_variable;
 +    mod inline_type_alias;
 +    mod introduce_named_lifetime;
 +    mod invert_if;
 +    mod merge_imports;
 +    mod merge_match_arms;
 +    mod move_bounds;
 +    mod move_guard;
 +    mod move_module_to_file;
 +    mod move_to_mod_rs;
 +    mod move_from_mod_rs;
 +    mod number_representation;
 +    mod promote_local_to_const;
 +    mod pull_assignment_up;
 +    mod qualify_path;
 +    mod qualify_method_call;
 +    mod raw_string;
 +    mod remove_dbg;
 +    mod remove_mut;
 +    mod remove_unused_param;
 +    mod reorder_fields;
 +    mod reorder_impl_items;
 +    mod replace_try_expr_with_match;
 +    mod replace_derive_with_manual_impl;
 +    mod replace_if_let_with_match;
 +    mod replace_or_with_or_else;
 +    mod introduce_named_generic;
 +    mod replace_let_with_if_let;
 +    mod replace_qualified_name_with_use;
 +    mod replace_string_with_char;
 +    mod replace_turbofish_with_explicit_type;
 +    mod split_import;
 +    mod unmerge_match_arm;
 +    mod sort_items;
 +    mod toggle_ignore;
 +    mod unmerge_use;
 +    mod unnecessary_async;
 +    mod unwrap_block;
 +    mod unwrap_result_return_type;
 +    mod wrap_return_type_in_result;
 +
 +    pub(crate) fn all() -> &'static [Handler] {
 +        &[
 +            // These are alphabetic for the foolish consistency
 +            add_explicit_type::add_explicit_type,
 +            add_label_to_loop::add_label_to_loop,
 +            add_missing_match_arms::add_missing_match_arms,
 +            add_lifetime_to_type::add_lifetime_to_type,
 +            add_return_type::add_return_type,
 +            add_turbo_fish::add_turbo_fish,
 +            apply_demorgan::apply_demorgan,
 +            auto_import::auto_import,
 +            change_visibility::change_visibility,
 +            convert_bool_then::convert_bool_then_to_if,
 +            convert_bool_then::convert_if_to_bool_then,
 +            convert_comment_block::convert_comment_block,
 +            convert_integer_literal::convert_integer_literal,
 +            convert_into_to_from::convert_into_to_from,
 +            convert_iter_for_each_to_for::convert_iter_for_each_to_for,
 +            convert_iter_for_each_to_for::convert_for_loop_with_for_each,
 +            convert_let_else_to_match::convert_let_else_to_match,
 +            convert_to_guarded_return::convert_to_guarded_return,
 +            convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
 +            convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
 +            convert_while_to_loop::convert_while_to_loop,
 +            destructure_tuple_binding::destructure_tuple_binding,
 +            expand_glob_import::expand_glob_import,
 +            extract_struct_from_enum_variant::extract_struct_from_enum_variant,
 +            extract_type_alias::extract_type_alias,
 +            fix_visibility::fix_visibility,
 +            flip_binexpr::flip_binexpr,
 +            flip_comma::flip_comma,
 +            flip_trait_bound::flip_trait_bound,
 +            generate_constant::generate_constant,
 +            generate_default_from_enum_variant::generate_default_from_enum_variant,
 +            generate_default_from_new::generate_default_from_new,
 +            generate_derive::generate_derive,
 +            generate_documentation_template::generate_documentation_template,
 +            generate_documentation_template::generate_doc_example,
 +            generate_enum_is_method::generate_enum_is_method,
 +            generate_enum_projection_method::generate_enum_as_method,
 +            generate_enum_projection_method::generate_enum_try_into_method,
 +            generate_enum_variant::generate_enum_variant,
 +            generate_from_impl_for_enum::generate_from_impl_for_enum,
 +            generate_function::generate_function,
 +            generate_impl::generate_impl,
 +            generate_is_empty_from_len::generate_is_empty_from_len,
 +            generate_new::generate_new,
 +            inline_call::inline_call,
 +            inline_call::inline_into_callers,
 +            inline_local_variable::inline_local_variable,
 +            inline_type_alias::inline_type_alias,
 +            inline_type_alias::inline_type_alias_uses,
 +            introduce_named_generic::introduce_named_generic,
 +            introduce_named_lifetime::introduce_named_lifetime,
 +            invert_if::invert_if,
 +            merge_imports::merge_imports,
 +            merge_match_arms::merge_match_arms,
 +            move_bounds::move_bounds_to_where_clause,
++            move_format_string_arg::move_format_string_arg,
 +            move_guard::move_arm_cond_to_match_guard,
 +            move_guard::move_guard_to_arm_body,
 +            move_module_to_file::move_module_to_file,
 +            move_to_mod_rs::move_to_mod_rs,
 +            move_from_mod_rs::move_from_mod_rs,
 +            number_representation::reformat_number_literal,
 +            pull_assignment_up::pull_assignment_up,
 +            promote_local_to_const::promote_local_to_const,
 +            qualify_path::qualify_path,
 +            qualify_method_call::qualify_method_call,
 +            raw_string::add_hash,
 +            raw_string::make_usual_string,
 +            raw_string::remove_hash,
 +            remove_dbg::remove_dbg,
 +            remove_mut::remove_mut,
 +            remove_unused_param::remove_unused_param,
 +            reorder_fields::reorder_fields,
 +            reorder_impl_items::reorder_impl_items,
 +            replace_try_expr_with_match::replace_try_expr_with_match,
 +            replace_derive_with_manual_impl::replace_derive_with_manual_impl,
 +            replace_if_let_with_match::replace_if_let_with_match,
 +            replace_if_let_with_match::replace_match_with_if_let,
 +            replace_let_with_if_let::replace_let_with_if_let,
 +            replace_or_with_or_else::replace_or_else_with_or,
 +            replace_or_with_or_else::replace_or_with_or_else,
 +            replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
 +            replace_qualified_name_with_use::replace_qualified_name_with_use,
 +            sort_items::sort_items,
 +            split_import::split_import,
 +            toggle_ignore::toggle_ignore,
 +            unmerge_match_arm::unmerge_match_arm,
 +            unmerge_use::unmerge_use,
 +            unnecessary_async::unnecessary_async,
 +            unwrap_block::unwrap_block,
 +            unwrap_result_return_type::unwrap_result_return_type,
 +            wrap_return_type_in_result::wrap_return_type_in_result,
 +            // These are manually sorted for better priorities. By default,
 +            // priority is determined by the size of the target range (smaller
 +            // target wins). If the ranges are equal, position in this list is
 +            // used as a tie-breaker.
 +            add_missing_impl_members::add_missing_impl_members,
 +            add_missing_impl_members::add_missing_default_members,
 +            //
 +            replace_string_with_char::replace_string_with_char,
 +            replace_string_with_char::replace_char_with_string,
 +            raw_string::make_raw_string,
 +            //
 +            extract_variable::extract_variable,
 +            extract_function::extract_function,
 +            extract_module::extract_module,
 +            //
 +            generate_getter::generate_getter,
 +            generate_getter::generate_getter_mut,
 +            generate_setter::generate_setter,
 +            generate_delegate_methods::generate_delegate_methods,
 +            generate_deref::generate_deref,
 +            // Are you sure you want to add new assist here, and not to the
 +            // sorted list above?
 +        ]
 +    }
 +}
index 9cd66c6b3b07bdb9c1cd8550dac2e58f3fd5cc43,0000000000000000000000000000000000000000..258144bae3d08dfad368fa824804d9c4f3128674
mode 100644,000000..100644
--- /dev/null
@@@ -1,558 -1,0 +1,559 @@@
 +mod generated;
 +#[cfg(not(feature = "in-rust-tree"))]
 +mod sourcegen;
 +
 +use expect_test::expect;
 +use hir::{db::DefDatabase, Semantics};
 +use ide_db::{
 +    base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
 +    imports::insert_use::{ImportGranularity, InsertUseConfig},
 +    source_change::FileSystemEdit,
 +    RootDatabase, SnippetCap,
 +};
 +use stdx::{format_to, trim_indent};
 +use syntax::TextRange;
 +use test_utils::{assert_eq_text, extract_offset};
 +
 +use crate::{
 +    assists, handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind,
 +    AssistResolveStrategy, Assists, SingleResolve,
 +};
 +
 +pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
 +    snippet_cap: SnippetCap::new(true),
 +    allowed: None,
 +    insert_use: InsertUseConfig {
 +        granularity: ImportGranularity::Crate,
 +        prefix_kind: hir::PrefixKind::Plain,
 +        enforce_granularity: true,
 +        group: true,
 +        skip_glob_imports: true,
 +    },
++    prefer_no_std: false,
 +};
 +
 +pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
 +    RootDatabase::with_single_file(text)
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
 +    let ra_fixture_after = trim_indent(ra_fixture_after);
 +    check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None);
 +}
 +
 +// There is no way to choose what assist within a group you want to test against,
 +// so this is here to allow you choose.
 +pub(crate) fn check_assist_by_label(
 +    assist: Handler,
 +    ra_fixture_before: &str,
 +    ra_fixture_after: &str,
 +    label: &str,
 +) {
 +    let ra_fixture_after = trim_indent(ra_fixture_after);
 +    check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), Some(label));
 +}
 +
 +// FIXME: instead of having a separate function here, maybe use
 +// `extract_ranges` and mark the target as `<target> </target>` in the
 +// fixture?
 +#[track_caller]
 +pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) {
 +    check(assist, ra_fixture, ExpectedResult::Target(target), None);
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) {
 +    check(assist, ra_fixture, ExpectedResult::NotApplicable, None);
 +}
 +
 +/// Check assist in unresolved state. Useful to check assists for lazy computation.
 +#[track_caller]
 +pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) {
 +    check(assist, ra_fixture, ExpectedResult::Unresolved, None);
 +}
 +
 +#[track_caller]
 +fn check_doc_test(assist_id: &str, before: &str, after: &str) {
 +    let after = trim_indent(after);
 +    let (db, file_id, selection) = RootDatabase::with_range_or_offset(before);
 +    let before = db.file_text(file_id).to_string();
 +    let frange = FileRange { file_id, range: selection.into() };
 +
 +    let assist = assists(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange)
 +        .into_iter()
 +        .find(|assist| assist.id.0 == assist_id)
 +        .unwrap_or_else(|| {
 +            panic!(
 +                "\n\nAssist is not applicable: {}\nAvailable assists: {}",
 +                assist_id,
 +                assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange)
 +                    .into_iter()
 +                    .map(|assist| assist.id.0)
 +                    .collect::<Vec<_>>()
 +                    .join(", ")
 +            )
 +        });
 +
 +    let actual = {
 +        let source_change =
 +            assist.source_change.expect("Assist did not contain any source changes");
 +        let mut actual = before;
 +        if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
 +            source_file_edit.apply(&mut actual);
 +        }
 +        actual
 +    };
 +    assert_eq_text!(&after, &actual);
 +}
 +
 +enum ExpectedResult<'a> {
 +    NotApplicable,
 +    Unresolved,
 +    After(&'a str),
 +    Target(&'a str),
 +}
 +
 +#[track_caller]
 +fn check(handler: Handler, before: &str, expected: ExpectedResult<'_>, assist_label: Option<&str>) {
 +    let (mut db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
 +    db.set_enable_proc_attr_macros(true);
 +    let text_without_caret = db.file_text(file_with_caret_id).to_string();
 +
 +    let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
 +
 +    let sema = Semantics::new(&db);
 +    let config = TEST_CONFIG;
 +    let ctx = AssistContext::new(sema, &config, frange);
 +    let resolve = match expected {
 +        ExpectedResult::Unresolved => AssistResolveStrategy::None,
 +        _ => AssistResolveStrategy::All,
 +    };
 +    let mut acc = Assists::new(&ctx, resolve);
 +    handler(&mut acc, &ctx);
 +    let mut res = acc.finish();
 +
 +    let assist = match assist_label {
 +        Some(label) => res.into_iter().find(|resolved| resolved.label == label),
 +        None => res.pop(),
 +    };
 +
 +    match (assist, expected) {
 +        (Some(assist), ExpectedResult::After(after)) => {
 +            let source_change =
 +                assist.source_change.expect("Assist did not contain any source changes");
 +            let skip_header = source_change.source_file_edits.len() == 1
 +                && source_change.file_system_edits.len() == 0;
 +
 +            let mut buf = String::new();
 +            for (file_id, edit) in source_change.source_file_edits {
 +                let mut text = db.file_text(file_id).as_ref().to_owned();
 +                edit.apply(&mut text);
 +                if !skip_header {
 +                    let sr = db.file_source_root(file_id);
 +                    let sr = db.source_root(sr);
 +                    let path = sr.path_for_file(&file_id).unwrap();
 +                    format_to!(buf, "//- {}\n", path)
 +                }
 +                buf.push_str(&text);
 +            }
 +
 +            for file_system_edit in source_change.file_system_edits {
 +                let (dst, contents) = match file_system_edit {
 +                    FileSystemEdit::CreateFile { dst, initial_contents } => (dst, initial_contents),
 +                    FileSystemEdit::MoveFile { src, dst } => {
 +                        (dst, db.file_text(src).as_ref().to_owned())
 +                    }
 +                    FileSystemEdit::MoveDir { src, src_id, dst } => {
 +                        // temporary placeholder for MoveDir since we are not using MoveDir in ide assists yet.
 +                        (dst, format!("{:?}\n{:?}", src_id, src))
 +                    }
 +                };
 +                let sr = db.file_source_root(dst.anchor);
 +                let sr = db.source_root(sr);
 +                let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
 +                base.pop();
 +                let created_file_path = base.join(&dst.path).unwrap();
 +                format_to!(buf, "//- {}\n", created_file_path);
 +                buf.push_str(&contents);
 +            }
 +
 +            assert_eq_text!(after, &buf);
 +        }
 +        (Some(assist), ExpectedResult::Target(target)) => {
 +            let range = assist.target;
 +            assert_eq_text!(&text_without_caret[range], target);
 +        }
 +        (Some(assist), ExpectedResult::Unresolved) => assert!(
 +            assist.source_change.is_none(),
 +            "unresolved assist should not contain source changes"
 +        ),
 +        (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
 +        (
 +            None,
 +            ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved,
 +        ) => {
 +            panic!("code action is not applicable")
 +        }
 +        (None, ExpectedResult::NotApplicable) => (),
 +    };
 +}
 +
 +fn labels(assists: &[Assist]) -> String {
 +    let mut labels = assists
 +        .iter()
 +        .map(|assist| {
 +            let mut label = match &assist.group {
 +                Some(g) => g.0.clone(),
 +                None => assist.label.to_string(),
 +            };
 +            label.push('\n');
 +            label
 +        })
 +        .collect::<Vec<_>>();
 +    labels.dedup();
 +    labels.into_iter().collect::<String>()
 +}
 +
 +#[test]
 +fn assist_order_field_struct() {
 +    let before = "struct Foo { $0bar: u32 }";
 +    let (before_cursor_pos, before) = extract_offset(before);
 +    let (db, file_id) = with_single_file(&before);
 +    let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
 +    let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
 +    let mut assists = assists.iter();
 +
 +    assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
 +    assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
 +}
 +
 +#[test]
 +fn assist_order_if_expr() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +
 +    let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
 +    let expected = labels(&assists);
 +
 +    expect![[r#"
 +        Convert integer base
 +        Extract into variable
 +        Extract into function
 +        Replace if let with match
 +    "#]]
 +    .assert_eq(&expected);
 +}
 +
 +#[test]
 +fn assist_filter_works() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::Refactor]);
 +
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#"
 +            Convert integer base
 +            Extract into variable
 +            Extract into function
 +            Replace if let with match
 +        "#]]
 +        .assert_eq(&expected);
 +    }
 +
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#"
 +            Extract into variable
 +            Extract into function
 +        "#]]
 +        .assert_eq(&expected);
 +    }
 +
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::QuickFix]);
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#""#]].assert_eq(&expected);
 +    }
 +}
 +
 +#[test]
 +fn various_resolve_strategies() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +
 +    let mut cfg = TEST_CONFIG;
 +    cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
 +
 +    {
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(
 +            &db,
 +            &cfg,
 +            AssistResolveStrategy::Single(SingleResolve {
 +                assist_id: "SOMETHING_MISMATCHING".to_string(),
 +                assist_kind: AssistKind::RefactorExtract,
 +            }),
 +            frange,
 +        );
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(
 +            &db,
 +            &cfg,
 +            AssistResolveStrategy::Single(SingleResolve {
 +                assist_id: "extract_variable".to_string(),
 +                assist_kind: AssistKind::RefactorExtract,
 +            }),
 +            frange,
 +        );
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "let $0var_name = 5;\n    ",
 +                                        delete: 45..45,
 +                                    },
 +                                    Indel {
 +                                        insert: "var_name",
 +                                        delete: 59..60,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::All, frange);
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "let $0var_name = 5;\n    ",
 +                                        delete: 45..45,
 +                                    },
 +                                    Indel {
 +                                        insert: "var_name",
 +                                        delete: 59..60,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "fun_name()",
 +                                        delete: 59..60,
 +                                    },
 +                                    Indel {
 +                                        insert: "\n\nfn $0fun_name() -> i32 {\n    5\n}",
 +                                        delete: 110..110,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +}
index 227e2300f92a0b258275512adca9fcadfc51f23a,0000000000000000000000000000000000000000..3a696635afd275c8830781e30259f5944f71f2d1
mode 100644,000000..100644
--- /dev/null
@@@ -1,2370 -1,0 +1,2401 @@@
 +//! Generated by `sourcegen_assists_docs`, do not edit by hand.
 +
 +use super::check_doc_test;
 +
 +#[test]
 +fn doctest_add_explicit_type() {
 +    check_doc_test(
 +        "add_explicit_type",
 +        r#####"
 +fn main() {
 +    let x$0 = 92;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x: i32 = 92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_hash() {
 +    check_doc_test(
 +        "add_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r##"Hello, World!"##;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_default_members() {
 +    check_doc_test(
 +        "add_impl_default_members",
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}$0
 +}
 +"#####,
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}
 +
 +    $0fn bar(&self) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_missing_members() {
 +    check_doc_test(
 +        "add_impl_missing_members",
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {$0
 +
 +}
 +"#####,
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {
 +    $0type X;
 +
 +    fn foo(&self) -> u32 {
 +        todo!()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_label_to_loop() {
 +    check_doc_test(
 +        "add_label_to_loop",
 +        r#####"
 +fn main() {
 +    loop$0 {
 +        break;
 +        continue;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    'l: loop {
 +        break 'l;
 +        continue 'l;
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_lifetime_to_type() {
 +    check_doc_test(
 +        "add_lifetime_to_type",
 +        r#####"
 +struct Point {
 +    x: &$0u32,
 +    y: u32,
 +}
 +"#####,
 +        r#####"
 +struct Point<'a> {
 +    x: &'a u32,
 +    y: u32,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_missing_match_arms() {
 +    check_doc_test(
 +        "add_missing_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move { distance } => todo!(),
 +        Action::Stop => todo!(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_return_type() {
 +    check_doc_test(
 +        "add_return_type",
 +        r#####"
 +fn foo() { 4$02i32 }
 +"#####,
 +        r#####"
 +fn foo() -> i32 { 42i32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_turbo_fish() {
 +    check_doc_test(
 +        "add_turbo_fish",
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make$0();
 +}
 +"#####,
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make::<${0:_}>();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_apply_demorgan() {
 +    check_doc_test(
 +        "apply_demorgan",
 +        r#####"
 +fn main() {
 +    if x != 4 ||$0 y < 3.14 {}
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !(x == 4 && y >= 3.14) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_auto_import() {
 +    check_doc_test(
 +        "auto_import",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +use std::collections::HashMap;
 +
 +fn main() {
 +    let map = HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_change_visibility() {
 +    check_doc_test(
 +        "change_visibility",
 +        r#####"
 +$0fn frobnicate() {}
 +"#####,
 +        r#####"
 +pub(crate) fn frobnicate() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_bool_then_to_if() {
 +    check_doc_test(
 +        "convert_bool_then_to_if",
 +        r#####"
 +//- minicore: bool_impl
 +fn main() {
 +    (0 == 0).then$0(|| val)
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if 0 == 0 {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_for_loop_with_for_each() {
 +    check_doc_test(
 +        "convert_for_loop_with_for_each",
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    for$0 v in x {
 +        let y = v * 2;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    x.into_iter().for_each(|v| {
 +        let y = v * 2;
 +    });
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_if_to_bool_then() {
 +    check_doc_test(
 +        "convert_if_to_bool_then",
 +        r#####"
 +//- minicore: option
 +fn main() {
 +    if$0 cond {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    cond.then(|| val)
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_integer_literal() {
 +    check_doc_test(
 +        "convert_integer_literal",
 +        r#####"
 +const _: i32 = 10$0;
 +"#####,
 +        r#####"
 +const _: i32 = 0b1010;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_into_to_from() {
 +    check_doc_test(
 +        "convert_into_to_from",
 +        r#####"
 +//- minicore: from
 +impl $0Into<Thing> for usize {
 +    fn into(self) -> Thing {
 +        Thing {
 +            b: self.to_string(),
 +            a: self
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl From<usize> for Thing {
 +    fn from(val: usize) -> Self {
 +        Thing {
 +            b: val.to_string(),
 +            a: val
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_iter_for_each_to_for() {
 +    check_doc_test(
 +        "convert_iter_for_each_to_for",
 +        r#####"
 +//- minicore: iterators
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    iter.for_each$0(|(x, y)| {
 +        println!("x: {}, y: {}", x, y);
 +    });
 +}
 +"#####,
 +        r#####"
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    for (x, y) in iter {
 +        println!("x: {}, y: {}", x, y);
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_let_else_to_match() {
 +    check_doc_test(
 +        "convert_let_else_to_match",
 +        r#####"
 +fn main() {
 +    let Ok(mut x) = f() else$0 { return };
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut x = match f() {
 +        Ok(x) => x,
 +        _ => return,
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_to_guarded_return() {
 +    check_doc_test(
 +        "convert_to_guarded_return",
 +        r#####"
 +fn main() {
 +    $0if cond {
 +        foo();
 +        bar();
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !cond {
 +        return;
 +    }
 +    foo();
 +    bar();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_tuple_struct_to_named_struct() {
 +    check_doc_test(
 +        "convert_tuple_struct_to_named_struct",
 +        r#####"
 +struct Point$0(f32, f32);
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point(x, y)
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.0
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.1
 +    }
 +}
 +"#####,
 +        r#####"
 +struct Point { field1: f32, field2: f32 }
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point { field1: x, field2: y }
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.field1
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.field2
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_two_arm_bool_match_to_matches_macro() {
 +    check_doc_test(
 +        "convert_two_arm_bool_match_to_matches_macro",
 +        r#####"
 +fn main() {
 +    match scrutinee$0 {
 +        Some(val) if val.cond() => true,
 +        _ => false,
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    matches!(scrutinee, Some(val) if val.cond())
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_while_to_loop() {
 +    check_doc_test(
 +        "convert_while_to_loop",
 +        r#####"
 +fn main() {
 +    $0while cond {
 +        foo();
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    loop {
 +        if !cond {
 +            break;
 +        }
 +        foo();
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_destructure_tuple_binding() {
 +    check_doc_test(
 +        "destructure_tuple_binding",
 +        r#####"
 +fn main() {
 +    let $0t = (1,2);
 +    let v = t.0;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let ($0_0, _1) = (1,2);
 +    let v = _0;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_expand_glob_import() {
 +    check_doc_test(
 +        "expand_glob_import",
 +        r#####"
 +mod foo {
 +    pub struct Bar;
 +    pub struct Baz;
 +}
 +
 +use foo::*$0;
 +
 +fn qux(bar: Bar, baz: Baz) {}
 +"#####,
 +        r#####"
 +mod foo {
 +    pub struct Bar;
 +    pub struct Baz;
 +}
 +
 +use foo::{Bar, Baz};
 +
 +fn qux(bar: Bar, baz: Baz) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_function() {
 +    check_doc_test(
 +        "extract_function",
 +        r#####"
 +fn main() {
 +    let n = 1;
 +    $0let m = n + 2;
 +    // calculate
 +    let k = m + n;$0
 +    let g = 3;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let n = 1;
 +    fun_name(n);
 +    let g = 3;
 +}
 +
 +fn $0fun_name(n: i32) {
 +    let m = n + 2;
 +    // calculate
 +    let k = m + n;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_module() {
 +    check_doc_test(
 +        "extract_module",
 +        r#####"
 +$0fn foo(name: i32) -> i32 {
 +    name + 1
 +}$0
 +
 +fn bar(name: i32) -> i32 {
 +    name + 2
 +}
 +"#####,
 +        r#####"
 +mod modname {
 +    pub(crate) fn foo(name: i32) -> i32 {
 +        name + 1
 +    }
 +}
 +
 +fn bar(name: i32) -> i32 {
 +    name + 2
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_struct_from_enum_variant() {
 +    check_doc_test(
 +        "extract_struct_from_enum_variant",
 +        r#####"
 +enum A { $0One(u32, u32) }
 +"#####,
 +        r#####"
 +struct One(u32, u32);
 +
 +enum A { One(One) }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_type_alias() {
 +    check_doc_test(
 +        "extract_type_alias",
 +        r#####"
 +struct S {
 +    field: $0(u8, u8, u8)$0,
 +}
 +"#####,
 +        r#####"
 +type $0Type = (u8, u8, u8);
 +
 +struct S {
 +    field: Type,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_variable() {
 +    check_doc_test(
 +        "extract_variable",
 +        r#####"
 +fn main() {
 +    $0(1 + 2)$0 * 4;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let $0var_name = (1 + 2);
 +    var_name * 4;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_fix_visibility() {
 +    check_doc_test(
 +        "fix_visibility",
 +        r#####"
 +mod m {
 +    fn frobnicate() {}
 +}
 +fn main() {
 +    m::frobnicate$0() {}
 +}
 +"#####,
 +        r#####"
 +mod m {
 +    $0pub(crate) fn frobnicate() {}
 +}
 +fn main() {
 +    m::frobnicate() {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_binexpr() {
 +    check_doc_test(
 +        "flip_binexpr",
 +        r#####"
 +fn main() {
 +    let _ = 90 +$0 2;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let _ = 2 + 90;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_comma() {
 +    check_doc_test(
 +        "flip_comma",
 +        r#####"
 +fn main() {
 +    ((1, 2),$0 (3, 4));
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    ((3, 4), (1, 2));
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_trait_bound() {
 +    check_doc_test(
 +        "flip_trait_bound",
 +        r#####"
 +fn foo<T: Clone +$0 Copy>() { }
 +"#####,
 +        r#####"
 +fn foo<T: Copy + Clone>() { }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_constant() {
 +    check_doc_test(
 +        "generate_constant",
 +        r#####"
 +struct S { i: usize }
 +impl S { pub fn new(n: usize) {} }
 +fn main() {
 +    let v = S::new(CAPA$0CITY);
 +}
 +"#####,
 +        r#####"
 +struct S { i: usize }
 +impl S { pub fn new(n: usize) {} }
 +fn main() {
 +    const CAPACITY: usize = $0;
 +    let v = S::new(CAPACITY);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_default_from_enum_variant() {
 +    check_doc_test(
 +        "generate_default_from_enum_variant",
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor$0,
 + Major,
 +}
 +"#####,
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor,
 + Major,
 +}
 +
 +impl Default for Version {
 +    fn default() -> Self {
 +        Self::Minor
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_default_from_new() {
 +    check_doc_test(
 +        "generate_default_from_new",
 +        r#####"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn n$0ew() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +"#####,
 +        r#####"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_delegate_methods() {
 +    check_doc_test(
 +        "generate_delegate_methods",
 +        r#####"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    ag$0e: Age,
 +}
 +"#####,
 +        r#####"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    age: Age,
 +}
 +
 +impl Person {
 +    $0fn age(&self) -> u8 {
 +        self.age.age()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_deref() {
 +    check_doc_test(
 +        "generate_deref",
 +        r#####"
 +//- minicore: deref, deref_mut
 +struct A;
 +struct B {
 +   $0a: A
 +}
 +"#####,
 +        r#####"
 +struct A;
 +struct B {
 +   a: A
 +}
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.a
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_derive() {
 +    check_doc_test(
 +        "generate_derive",
 +        r#####"
 +struct Point {
 +    x: u32,
 +    y: u32,$0
 +}
 +"#####,
 +        r#####"
 +#[derive($0)]
 +struct Point {
 +    x: u32,
 +    y: u32,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_doc_example() {
 +    check_doc_test(
 +        "generate_doc_example",
 +        r#####"
 +/// Adds two numbers.$0
 +pub fn add(a: i32, b: i32) -> i32 { a + b }
 +"#####,
 +        r#####"
 +/// Adds two numbers.
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::add;
 +///
 +/// assert_eq!(add(a, b), );
 +/// ```
 +pub fn add(a: i32, b: i32) -> i32 { a + b }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_documentation_template() {
 +    check_doc_test(
 +        "generate_documentation_template",
 +        r#####"
 +pub struct S;
 +impl S {
 +    pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
 +        /* ... */
 +    }
 +}
 +"#####,
 +        r#####"
 +pub struct S;
 +impl S {
 +    /// Sets the length of this [`S`].
 +    ///
 +    /// # Errors
 +    ///
 +    /// This function will return an error if .
 +    ///
 +    /// # Safety
 +    ///
 +    /// .
 +    pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
 +        /* ... */
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_as_method() {
 +    check_doc_test(
 +        "generate_enum_as_method",
 +        r#####"
 +enum Value {
 + Number(i32),
 + Text(String)$0,
 +}
 +"#####,
 +        r#####"
 +enum Value {
 + Number(i32),
 + Text(String),
 +}
 +
 +impl Value {
 +    fn as_text(&self) -> Option<&String> {
 +        if let Self::Text(v) = self {
 +            Some(v)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_is_method() {
 +    check_doc_test(
 +        "generate_enum_is_method",
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor$0,
 + Major,
 +}
 +"#####,
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor,
 + Major,
 +}
 +
 +impl Version {
 +    /// Returns `true` if the version is [`Minor`].
 +    ///
 +    /// [`Minor`]: Version::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_try_into_method() {
 +    check_doc_test(
 +        "generate_enum_try_into_method",
 +        r#####"
 +enum Value {
 + Number(i32),
 + Text(String)$0,
 +}
 +"#####,
 +        r#####"
 +enum Value {
 + Number(i32),
 + Text(String),
 +}
 +
 +impl Value {
 +    fn try_into_text(self) -> Result<String, Self> {
 +        if let Self::Text(v) = self {
 +            Ok(v)
 +        } else {
 +            Err(self)
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_variant() {
 +    check_doc_test(
 +        "generate_enum_variant",
 +        r#####"
 +enum Countries {
 +    Ghana,
 +}
 +
 +fn main() {
 +    let country = Countries::Lesotho$0;
 +}
 +"#####,
 +        r#####"
 +enum Countries {
 +    Ghana,
 +    Lesotho,
 +}
 +
 +fn main() {
 +    let country = Countries::Lesotho;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_from_impl_for_enum() {
 +    check_doc_test(
 +        "generate_from_impl_for_enum",
 +        r#####"
 +enum A { $0One(u32) }
 +"#####,
 +        r#####"
 +enum A { One(u32) }
 +
 +impl From<u32> for A {
 +    fn from(v: u32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_function() {
 +    check_doc_test(
 +        "generate_function",
 +        r#####"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar$0("", baz());
 +}
 +
 +"#####,
 +        r#####"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar("", baz());
 +}
 +
 +fn bar(arg: &str, baz: Baz) ${0:-> _} {
 +    todo!()
 +}
 +
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_getter() {
 +    check_doc_test(
 +        "generate_getter",
 +        r#####"
 +//- minicore: as_ref
 +pub struct String;
 +impl AsRef<str> for String {
 +    fn as_ref(&self) -> &str {
 +        ""
 +    }
 +}
 +
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +pub struct String;
 +impl AsRef<str> for String {
 +    fn as_ref(&self) -> &str {
 +        ""
 +    }
 +}
 +
 +struct Person {
 +    name: String,
 +}
 +
 +impl Person {
 +    fn $0name(&self) -> &str {
 +        self.name.as_ref()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_getter_mut() {
 +    check_doc_test(
 +        "generate_getter_mut",
 +        r#####"
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +struct Person {
 +    name: String,
 +}
 +
 +impl Person {
 +    fn $0name_mut(&mut self) -> &mut String {
 +        &mut self.name
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_impl() {
 +    check_doc_test(
 +        "generate_impl",
 +        r#####"
 +struct Ctx<T: Clone> {
 +    data: T,$0
 +}
 +"#####,
 +        r#####"
 +struct Ctx<T: Clone> {
 +    data: T,
 +}
 +
 +impl<T: Clone> Ctx<T> {
 +    $0
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_is_empty_from_len() {
 +    check_doc_test(
 +        "generate_is_empty_from_len",
 +        r#####"
 +struct MyStruct { data: Vec<String> }
 +
 +impl MyStruct {
 +    #[must_use]
 +    p$0ub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +}
 +"#####,
 +        r#####"
 +struct MyStruct { data: Vec<String> }
 +
 +impl MyStruct {
 +    #[must_use]
 +    pub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +
 +    #[must_use]
 +    pub fn is_empty(&self) -> bool {
 +        self.len() == 0
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_new() {
 +    check_doc_test(
 +        "generate_new",
 +        r#####"
 +struct Ctx<T: Clone> {
 +     data: T,$0
 +}
 +"#####,
 +        r#####"
 +struct Ctx<T: Clone> {
 +     data: T,
 +}
 +
 +impl<T: Clone> Ctx<T> {
 +    fn $0new(data: T) -> Self { Self { data } }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_setter() {
 +    check_doc_test(
 +        "generate_setter",
 +        r#####"
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +struct Person {
 +    name: String,
 +}
 +
 +impl Person {
 +    fn set_name(&mut self, name: String) {
 +        self.name = name;
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_call() {
 +    check_doc_test(
 +        "inline_call",
 +        r#####"
 +//- minicore: option
 +fn foo(name: Option<&str>) {
 +    let name = name.unwrap$0();
 +}
 +"#####,
 +        r#####"
 +fn foo(name: Option<&str>) {
 +    let name = match name {
 +            Some(val) => val,
 +            None => panic!("called `Option::unwrap()` on a `None` value"),
 +        };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_into_callers() {
 +    check_doc_test(
 +        "inline_into_callers",
 +        r#####"
 +fn print(_: &str) {}
 +fn foo$0(word: &str) {
 +    if !word.is_empty() {
 +        print(word);
 +    }
 +}
 +fn bar() {
 +    foo("안녕하세요");
 +    foo("여러분");
 +}
 +"#####,
 +        r#####"
 +fn print(_: &str) {}
 +
 +fn bar() {
 +    {
 +        let word = "안녕하세요";
 +        if !word.is_empty() {
 +            print(word);
 +        }
 +    };
 +    {
 +        let word = "여러분";
 +        if !word.is_empty() {
 +            print(word);
 +        }
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_local_variable() {
 +    check_doc_test(
 +        "inline_local_variable",
 +        r#####"
 +fn main() {
 +    let x$0 = 1 + 2;
 +    x * 4;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    (1 + 2) * 4;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_type_alias() {
 +    check_doc_test(
 +        "inline_type_alias",
 +        r#####"
 +type A<T = u32> = Vec<T>;
 +
 +fn main() {
 +    let a: $0A;
 +}
 +"#####,
 +        r#####"
 +type A<T = u32> = Vec<T>;
 +
 +fn main() {
 +    let a: Vec<u32>;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_type_alias_uses() {
 +    check_doc_test(
 +        "inline_type_alias_uses",
 +        r#####"
 +type $0A = i32;
 +fn id(x: A) -> A {
 +    x
 +};
 +fn foo() {
 +    let _: A = 3;
 +}
 +"#####,
 +        r#####"
 +
 +fn id(x: i32) -> i32 {
 +    x
 +};
 +fn foo() {
 +    let _: i32 = 3;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_introduce_named_generic() {
 +    check_doc_test(
 +        "introduce_named_generic",
 +        r#####"
 +fn foo(bar: $0impl Bar) {}
 +"#####,
 +        r#####"
 +fn foo<B: Bar>(bar: B) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_introduce_named_lifetime() {
 +    check_doc_test(
 +        "introduce_named_lifetime",
 +        r#####"
 +impl Cursor<'_$0> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl<'a> Cursor<'a> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_invert_if() {
 +    check_doc_test(
 +        "invert_if",
 +        r#####"
 +fn main() {
 +    if$0 !y { A } else { B }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if y { B } else { A }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_line_to_block() {
 +    check_doc_test(
 +        "line_to_block",
 +        r#####"
 +   // Multi-line$0
 +   // comment
 +"#####,
 +        r#####"
 +  /*
 +  Multi-line
 +  comment
 +  */
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_raw_string() {
 +    check_doc_test(
 +        "make_raw_string",
 +        r#####"
 +fn main() {
 +    "Hello,$0 World!";
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r#"Hello, World!"#;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_usual_string() {
 +    check_doc_test(
 +        "make_usual_string",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 "World!""#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    "Hello, \"World!\"";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_imports() {
 +    check_doc_test(
 +        "merge_imports",
 +        r#####"
 +use std::$0fmt::Formatter;
 +use std::io;
 +"#####,
 +        r#####"
 +use std::{fmt::Formatter, io};
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_match_arms() {
 +    check_doc_test(
 +        "merge_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move(..) => foo(),
 +        Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) | Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_arm_cond_to_match_guard() {
 +    check_doc_test(
 +        "move_arm_cond_to_match_guard",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => $0if distance > 10 { foo() },
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_bounds_to_where_clause() {
 +    check_doc_test(
 +        "move_bounds_to_where_clause",
 +        r#####"
 +fn apply<T, U, $0F: FnOnce(T) -> U>(f: F, x: T) -> U {
 +    f(x)
 +}
 +"#####,
 +        r#####"
 +fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
 +    f(x)
 +}
 +"#####,
 +    )
 +}
 +
++#[test]
++fn doctest_move_format_string_arg() {
++    check_doc_test(
++        "move_format_string_arg",
++        r#####"
++macro_rules! format_args {
++    ($lit:literal $(tt:tt)*) => { 0 },
++}
++macro_rules! print {
++    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
++}
++
++fn main() {
++    print!("{x + 1}$0");
++}
++"#####,
++        r#####"
++macro_rules! format_args {
++    ($lit:literal $(tt:tt)*) => { 0 },
++}
++macro_rules! print {
++    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
++}
++
++fn main() {
++    print!("{}"$0, x + 1);
++}
++"#####,
++    )
++}
++
 +#[test]
 +fn doctest_move_from_mod_rs() {
 +    check_doc_test(
 +        "move_from_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a/mod.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_guard_to_arm_body() {
 +    check_doc_test(
 +        "move_guard_to_arm_body",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } $0if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => if distance > 10 {
 +            foo()
 +        },
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_module_to_file() {
 +    check_doc_test(
 +        "move_module_to_file",
 +        r#####"
 +mod $0foo {
 +    fn t() {}
 +}
 +"#####,
 +        r#####"
 +mod foo;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_to_mod_rs() {
 +    check_doc_test(
 +        "move_to_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_promote_local_to_const() {
 +    check_doc_test(
 +        "promote_local_to_const",
 +        r#####"
 +fn main() {
 +    let foo$0 = true;
 +
 +    if foo {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    const $0FOO: bool = true;
 +
 +    if FOO {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_pull_assignment_up() {
 +    check_doc_test(
 +        "pull_assignment_up",
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    if true {
 +        $0foo = 5;
 +    } else {
 +        foo = 4;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    foo = if true {
 +        5
 +    } else {
 +        4
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_method_call() {
 +    check_doc_test(
 +        "qualify_method_call",
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    foo.fo$0o();
 +}
 +"#####,
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    Foo::foo(&foo);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_path() {
 +    check_doc_test(
 +        "qualify_path",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +fn main() {
 +    let map = std::collections::HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reformat_number_literal() {
 +    check_doc_test(
 +        "reformat_number_literal",
 +        r#####"
 +const _: i32 = 1012345$0;
 +"#####,
 +        r#####"
 +const _: i32 = 1_012_345;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_dbg() {
 +    check_doc_test(
 +        "remove_dbg",
 +        r#####"
 +fn main() {
 +    $0dbg!(92);
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_hash() {
 +    check_doc_test(
 +        "remove_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r"Hello, World!";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_mut() {
 +    check_doc_test(
 +        "remove_mut",
 +        r#####"
 +impl Walrus {
 +    fn feed(&mut$0 self, amount: u32) {}
 +}
 +"#####,
 +        r#####"
 +impl Walrus {
 +    fn feed(&self, amount: u32) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_unused_param() {
 +    check_doc_test(
 +        "remove_unused_param",
 +        r#####"
 +fn frobnicate(x: i32$0) {}
 +
 +fn main() {
 +    frobnicate(92);
 +}
 +"#####,
 +        r#####"
 +fn frobnicate() {}
 +
 +fn main() {
 +    frobnicate();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_fields() {
 +    check_doc_test(
 +        "reorder_fields",
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = $0Foo {bar: 0, foo: 1}
 +"#####,
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = Foo {foo: 1, bar: 0}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_impl_items() {
 +    check_doc_test(
 +        "reorder_impl_items",
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +$0impl Foo for Bar {
 +    const B: u8 = 17;
 +    fn c() {}
 +    type A = String;
 +}
 +"#####,
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +impl Foo for Bar {
 +    type A = String;
 +    const B: u8 = 17;
 +    fn c() {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_char_with_string() {
 +    check_doc_test(
 +        "replace_char_with_string",
 +        r#####"
 +fn main() {
 +    find('{$0');
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    find("{");
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_derive_with_manual_impl() {
 +    check_doc_test(
 +        "replace_derive_with_manual_impl",
 +        r#####"
 +//- minicore: derive
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Deb$0ug, Display)]
 +struct S;
 +"#####,
 +        r#####"
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Display)]
 +struct S;
 +
 +impl Debug for S {
 +    $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
 +        f.debug_struct("S").finish()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_if_let_with_match() {
 +    check_doc_test(
 +        "replace_if_let_with_match",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_let_with_if_let() {
 +    check_doc_test(
 +        "replace_let_with_if_let",
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    $0let x = compute();
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    if let Some(x) = compute() {
 +    }
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_match_with_if_let() {
 +    check_doc_test(
 +        "replace_match_with_if_let",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_or_else_with_or() {
 +    check_doc_test(
 +        "replace_or_else_with_or",
 +        r#####"
 +//- minicore:option
 +fn foo() {
 +    let a = Some(1);
 +    a.unwra$0p_or_else(|| 2);
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    let a = Some(1);
 +    a.unwrap_or(2);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_or_with_or_else() {
 +    check_doc_test(
 +        "replace_or_with_or_else",
 +        r#####"
 +//- minicore:option
 +fn foo() {
 +    let a = Some(1);
 +    a.unwra$0p_or(2);
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    let a = Some(1);
 +    a.unwrap_or_else(|| 2);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_qualified_name_with_use() {
 +    check_doc_test(
 +        "replace_qualified_name_with_use",
 +        r#####"
 +mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +fn process(map: std::collections::$0HashMap<String, String>) {}
 +"#####,
 +        r#####"
 +use std::collections::HashMap;
 +
 +mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +fn process(map: HashMap<String, String>) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_string_with_char() {
 +    check_doc_test(
 +        "replace_string_with_char",
 +        r#####"
 +fn main() {
 +    find("{$0");
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    find('{');
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_try_expr_with_match() {
 +    check_doc_test(
 +        "replace_try_expr_with_match",
 +        r#####"
 +//- minicore:option
 +fn handle() {
 +    let pat = Some(true)$0?;
 +}
 +"#####,
 +        r#####"
 +fn handle() {
 +    let pat = match Some(true) {
 +        Some(it) => it,
 +        None => return None,
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_turbofish_with_explicit_type() {
 +    check_doc_test(
 +        "replace_turbofish_with_explicit_type",
 +        r#####"
 +fn make<T>() -> T { ) }
 +fn main() {
 +    let a = make$0::<i32>();
 +}
 +"#####,
 +        r#####"
 +fn make<T>() -> T { ) }
 +fn main() {
 +    let a: i32 = make();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +struct $0Foo$0 { second: u32, first: String }
 +"#####,
 +        r#####"
 +struct Foo { first: String, second: u32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_1() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +trait $0Bar$0 {
 +    fn second(&self) -> u32;
 +    fn first(&self) -> String;
 +}
 +"#####,
 +        r#####"
 +trait Bar {
 +    fn first(&self) -> String;
 +    fn second(&self) -> u32;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_2() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +struct Baz;
 +impl $0Baz$0 {
 +    fn second(&self) -> u32;
 +    fn first(&self) -> String;
 +}
 +"#####,
 +        r#####"
 +struct Baz;
 +impl Baz {
 +    fn first(&self) -> String;
 +    fn second(&self) -> u32;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_3() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +enum $0Animal$0 {
 +  Dog(String, f64),
 +  Cat { weight: f64, name: String },
 +}
 +"#####,
 +        r#####"
 +enum Animal {
 +  Cat { weight: f64, name: String },
 +  Dog(String, f64),
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_4() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +enum Animal {
 +  Dog(String, f64),
 +  Cat $0{ weight: f64, name: String }$0,
 +}
 +"#####,
 +        r#####"
 +enum Animal {
 +  Dog(String, f64),
 +  Cat { name: String, weight: f64 },
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_split_import() {
 +    check_doc_test(
 +        "split_import",
 +        r#####"
 +use std::$0collections::HashMap;
 +"#####,
 +        r#####"
 +use std::{collections::HashMap};
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_toggle_ignore() {
 +    check_doc_test(
 +        "toggle_ignore",
 +        r#####"
 +$0#[test]
 +fn arithmetics {
 +    assert_eq!(2 + 2, 5);
 +}
 +"#####,
 +        r#####"
 +#[test]
 +#[ignore]
 +fn arithmetics {
 +    assert_eq!(2 + 2, 5);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unmerge_match_arm() {
 +    check_doc_test(
 +        "unmerge_match_arm",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) $0| Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) => foo(),
 +        Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unmerge_use() {
 +    check_doc_test(
 +        "unmerge_use",
 +        r#####"
 +use std::fmt::{Debug, Display$0};
 +"#####,
 +        r#####"
 +use std::fmt::{Debug};
 +use std::fmt::Display;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unnecessary_async() {
 +    check_doc_test(
 +        "unnecessary_async",
 +        r#####"
 +pub async f$0n foo() {}
 +pub async fn bar() { foo().await }
 +"#####,
 +        r#####"
 +pub fn foo() {}
 +pub async fn bar() { foo() }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unwrap_block() {
 +    check_doc_test(
 +        "unwrap_block",
 +        r#####"
 +fn foo() {
 +    if true {$0
 +        println!("foo");
 +    }
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    println!("foo");
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unwrap_result_return_type() {
 +    check_doc_test(
 +        "unwrap_result_return_type",
 +        r#####"
 +//- minicore: result
 +fn foo() -> Result<i32>$0 { Ok(42i32) }
 +"#####,
 +        r#####"
 +fn foo() -> i32 { 42i32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_wrap_return_type_in_result() {
 +    check_doc_test(
 +        "wrap_return_type_in_result",
 +        r#####"
 +//- minicore: result
 +fn foo() -> i32$0 { 42i32 }
 +"#####,
 +        r#####"
 +fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
 +"#####,
 +    )
 +}
index 55c3e28392a4d8c0bc8acbe182b8644d33ccce22,0000000000000000000000000000000000000000..97b90c62dd7775b1073181148bb6ae5ea27826c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,690 -1,0 +1,694 @@@
-         if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
 +//! This module defines an accumulator for completions which are going to be presented to user.
 +
 +pub(crate) mod attribute;
 +pub(crate) mod dot;
 +pub(crate) mod expr;
 +pub(crate) mod extern_abi;
 +pub(crate) mod field;
 +pub(crate) mod flyimport;
 +pub(crate) mod fn_param;
 +pub(crate) mod format_string;
 +pub(crate) mod item_list;
 +pub(crate) mod keyword;
 +pub(crate) mod lifetime;
 +pub(crate) mod mod_;
 +pub(crate) mod pattern;
 +pub(crate) mod postfix;
 +pub(crate) mod record;
 +pub(crate) mod snippet;
 +pub(crate) mod r#type;
 +pub(crate) mod use_;
 +pub(crate) mod vis;
 +
 +use std::iter;
 +
 +use hir::{known, ScopeDef};
 +use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
 +use syntax::ast;
 +
 +use crate::{
 +    context::{
 +        DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
 +        PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
 +    },
 +    item::Builder,
 +    render::{
 +        const_::render_const,
 +        function::{render_fn, render_method},
 +        literal::{render_struct_literal, render_variant_lit},
 +        macro_::render_macro,
 +        pattern::{render_struct_pat, render_variant_pat},
 +        render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
 +        type_alias::{render_type_alias, render_type_alias_with_eq},
 +        union_literal::render_union_literal,
 +        RenderContext,
 +    },
 +    CompletionContext, CompletionItem, CompletionItemKind,
 +};
 +
 +/// Represents an in-progress set of completions being built.
 +#[derive(Debug, Default)]
 +pub struct Completions {
 +    buf: Vec<CompletionItem>,
 +}
 +
 +impl From<Completions> for Vec<CompletionItem> {
 +    fn from(val: Completions) -> Self {
 +        val.buf
 +    }
 +}
 +
 +impl Builder {
 +    /// Convenience method, which allows to add a freshly created completion into accumulator
 +    /// without binding it to the variable.
 +    pub(crate) fn add_to(self, acc: &mut Completions) {
 +        acc.add(self.build())
 +    }
 +}
 +
 +impl Completions {
 +    fn add(&mut self, item: CompletionItem) {
 +        self.buf.push(item)
 +    }
 +
 +    fn add_opt(&mut self, item: Option<CompletionItem>) {
 +        if let Some(item) = item {
 +            self.buf.push(item)
 +        }
 +    }
 +
 +    pub(crate) fn add_all<I>(&mut self, items: I)
 +    where
 +        I: IntoIterator,
 +        I::Item: Into<CompletionItem>,
 +    {
 +        items.into_iter().for_each(|item| self.add(item.into()))
 +    }
 +
 +    pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) {
 +        let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword);
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) {
 +        ["self::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 +
 +        if ctx.depth_from_crate_root > 0 {
 +            self.add_keyword(ctx, "super::");
 +        }
 +    }
 +
 +    pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
 +        ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 +
 +        if ctx.depth_from_crate_root > 0 {
 +            self.add_keyword(ctx, "super");
 +        }
 +    }
 +
 +    pub(crate) fn add_super_keyword(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        super_chain_len: Option<usize>,
 +    ) {
 +        if let Some(len) = super_chain_len {
 +            if len > 0 && len < ctx.depth_from_crate_root {
 +                self.add_keyword(ctx, "super::");
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn add_keyword_snippet_expr(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        incomplete_let: bool,
 +        kw: &str,
 +        snippet: &str,
 +    ) {
 +        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 +
 +        match ctx.config.snippet_cap {
 +            Some(cap) => {
 +                if incomplete_let && snippet.ends_with('}') {
 +                    // complete block expression snippets with a trailing semicolon, if inside an incomplete let
 +                    cov_mark::hit!(let_semi);
 +                    item.insert_snippet(cap, format!("{};", snippet));
 +                } else {
 +                    item.insert_snippet(cap, snippet);
 +                }
 +            }
 +            None => {
 +                item.insert_text(if snippet.contains('$') { kw } else { snippet });
 +            }
 +        };
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_keyword_snippet(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        kw: &str,
 +        snippet: &str,
 +    ) {
 +        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 +
 +        match ctx.config.snippet_cap {
 +            Some(cap) => item.insert_snippet(cap, snippet),
 +            None => item.insert_text(if snippet.contains('$') { kw } else { snippet }),
 +        };
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_crate_roots(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +    ) {
 +        ctx.process_all_names(&mut |name, res| match res {
 +            ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
 +                self.add_module(ctx, path_ctx, m, name);
 +            }
 +            _ => (),
 +        });
 +    }
 +
 +    pub(crate) fn add_path_resolution(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        local_name: hir::Name,
 +        resolution: hir::ScopeDef,
 +    ) {
 +        let is_private_editable = match ctx.def_is_visible(&resolution) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_path_resolution(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                resolution,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_pattern_resolution(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        local_name: hir::Name,
 +        resolution: hir::ScopeDef,
 +    ) {
 +        let is_private_editable = match ctx.def_is_visible(&resolution) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_pattern_resolution(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                pattern_ctx,
 +                local_name,
 +                resolution,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_enum_variants(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        e: hir::Enum,
 +    ) {
 +        e.variants(ctx.db)
 +            .into_iter()
 +            .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
 +    }
 +
 +    pub(crate) fn add_module(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        module: hir::Module,
 +        local_name: hir::Name,
 +    ) {
 +        self.add_path_resolution(
 +            ctx,
 +            path_ctx,
 +            local_name,
 +            hir::ScopeDef::ModuleDef(module.into()),
 +        );
 +    }
 +
 +    pub(crate) fn add_macro(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        mac: hir::Macro,
 +        local_name: hir::Name,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&mac) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_macro(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                mac,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_function(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        func: hir::Function,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_fn(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_method(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        func: hir::Function,
 +        receiver: Option<hir::Name>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_method(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                dot_access,
 +                receiver,
 +                local_name,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_method_with_import(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        func: hir::Function,
 +        import: LocatedImport,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_method(
 +                RenderContext::new(ctx)
 +                    .private_editable(is_private_editable)
 +                    .import_to_add(Some(import)),
 +                dot_access,
 +                None,
 +                None,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
 +        let is_private_editable = match ctx.is_visible(&konst) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add_opt(render_const(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            konst,
 +        ));
 +    }
 +
 +    pub(crate) fn add_type_alias(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        type_alias: hir::TypeAlias,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&type_alias) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add_opt(render_type_alias(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            type_alias,
 +        ));
 +    }
 +
 +    pub(crate) fn add_type_alias_with_eq(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        type_alias: hir::TypeAlias,
 +    ) {
 +        self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
 +    }
 +
 +    pub(crate) fn add_qualified_enum_variant(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        variant: hir::Variant,
 +        path: hir::ModPath,
 +    ) {
 +        if let Some(builder) =
 +            render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_enum_variant(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        variant: hir::Variant,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
 +            cov_mark::hit!(enum_variant_pattern_path);
 +            self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
 +            return;
 +        }
 +
 +        if let Some(builder) =
 +            render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None)
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_field(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        receiver: Option<hir::Name>,
 +        field: hir::Field,
 +        ty: &hir::Type,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&field) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        let item = render_field(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            dot_access,
 +            receiver,
 +            field,
 +            ty,
 +        );
 +        self.add(item);
 +    }
 +
 +    pub(crate) fn add_struct_literal(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        strukt: hir::Struct,
 +        path: Option<hir::ModPath>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        if let Some(builder) =
 +            render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_union_literal(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        un: hir::Union,
 +        path: Option<hir::ModPath>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
 +        self.add_opt(item);
 +    }
 +
 +    pub(crate) fn add_tuple_field(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        receiver: Option<hir::Name>,
 +        field: usize,
 +        ty: &hir::Type,
 +    ) {
 +        let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
 +        self.add(item);
 +    }
 +
 +    pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
 +        CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str())
 +            .add_to(self)
 +    }
 +
 +    pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
 +        CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self)
 +    }
 +
 +    pub(crate) fn add_variant_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        path_ctx: Option<&PathCompletionCtx>,
 +        variant: hir::Variant,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        self.add_opt(render_variant_pat(
 +            RenderContext::new(ctx),
 +            pattern_ctx,
 +            path_ctx,
 +            variant,
 +            local_name.clone(),
 +            None,
 +        ));
 +    }
 +
 +    pub(crate) fn add_qualified_variant_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        variant: hir::Variant,
 +        path: hir::ModPath,
 +    ) {
 +        let path = Some(&path);
 +        self.add_opt(render_variant_pat(
 +            RenderContext::new(ctx),
 +            pattern_ctx,
 +            None,
 +            variant,
 +            None,
 +            path,
 +        ));
 +    }
 +
 +    pub(crate) fn add_struct_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        strukt: hir::Struct,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
 +    }
 +}
 +
 +/// Calls the callback for each variant of the provided enum with the path to the variant.
 +/// Skips variants that are visible with single segment paths.
 +fn enum_variants_with_paths(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    enum_: hir::Enum,
 +    impl_: &Option<ast::Impl>,
 +    cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
 +) {
 +    let variants = enum_.variants(ctx.db);
 +
 +    if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
 +        if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
 +            for &variant in &variants {
 +                let self_path = hir::ModPath::from_segments(
 +                    hir::PathKind::Plain,
 +                    iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
 +                );
 +                cb(acc, ctx, variant, self_path);
 +            }
 +        }
 +    }
 +
 +    for variant in variants {
++        if let Some(path) = ctx.module.find_use_path(
++            ctx.db,
++            hir::ModuleDef::from(variant),
++            ctx.config.prefer_no_std,
++        ) {
 +            // Variants with trivial paths are already added by the existing completion logic,
 +            // so we should avoid adding these twice
 +            if path.segments().len() > 1 {
 +                cb(acc, ctx, variant, path);
 +            }
 +        }
 +    }
 +}
 +
 +pub(super) fn complete_name(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    NameContext { name, kind }: &NameContext,
 +) {
 +    match kind {
 +        NameKind::Const => {
 +            item_list::trait_impl::complete_trait_impl_const(acc, ctx, name);
 +        }
 +        NameKind::Function => {
 +            item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name);
 +        }
 +        NameKind::IdentPat(pattern_ctx) => {
 +            if ctx.token.kind() != syntax::T![_] {
 +                complete_patterns(acc, ctx, pattern_ctx)
 +            }
 +        }
 +        NameKind::Module(mod_under_caret) => {
 +            mod_::complete_mod(acc, ctx, mod_under_caret);
 +        }
 +        NameKind::TypeAlias => {
 +            item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name);
 +        }
 +        NameKind::RecordField => {
 +            field::complete_field_list_record_variant(acc, ctx);
 +        }
 +        NameKind::ConstParam
 +        | NameKind::Enum
 +        | NameKind::MacroDef
 +        | NameKind::MacroRules
 +        | NameKind::Rename
 +        | NameKind::SelfParam
 +        | NameKind::Static
 +        | NameKind::Struct
 +        | NameKind::Trait
 +        | NameKind::TypeParam
 +        | NameKind::Union
 +        | NameKind::Variant => (),
 +    }
 +}
 +
 +pub(super) fn complete_name_ref(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    NameRefContext { nameref, kind }: &NameRefContext,
 +) {
 +    match kind {
 +        NameRefKind::Path(path_ctx) => {
 +            flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
 +
 +            match &path_ctx.kind {
 +                PathKind::Expr { expr_ctx } => {
 +                    expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx);
 +
 +                    dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx);
 +                    item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx);
 +                    snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx);
 +                }
 +                PathKind::Type { location } => {
 +                    r#type::complete_type_path(acc, ctx, path_ctx, location);
 +
 +                    match location {
 +                        TypeLocation::TupleField => {
 +                            field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
 +                        }
 +                        TypeLocation::TypeAscription(ascription) => {
 +                            r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
 +                        }
 +                        TypeLocation::GenericArgList(_)
 +                        | TypeLocation::TypeBound
 +                        | TypeLocation::ImplTarget
 +                        | TypeLocation::ImplTrait
 +                        | TypeLocation::Other => (),
 +                    }
 +                }
 +                PathKind::Attr { attr_ctx } => {
 +                    attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx);
 +                }
 +                PathKind::Derive { existing_derives } => {
 +                    attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives);
 +                }
 +                PathKind::Item { kind } => {
 +                    item_list::complete_item_list(acc, ctx, path_ctx, kind);
 +
 +                    snippet::complete_item_snippet(acc, ctx, path_ctx, kind);
 +                    if let ItemListKind::TraitImpl(impl_) = kind {
 +                        item_list::trait_impl::complete_trait_impl_item_by_name(
 +                            acc, ctx, path_ctx, nameref, impl_,
 +                        );
 +                    }
 +                }
 +                PathKind::Pat { .. } => {
 +                    pattern::complete_pattern_path(acc, ctx, path_ctx);
 +                }
 +                PathKind::Vis { has_in_token } => {
 +                    vis::complete_vis_path(acc, ctx, path_ctx, has_in_token);
 +                }
 +                PathKind::Use => {
 +                    use_::complete_use_path(acc, ctx, path_ctx, nameref);
 +                }
 +            }
 +        }
 +        NameRefKind::DotAccess(dot_access) => {
 +            flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
 +            dot::complete_dot(acc, ctx, dot_access);
 +            postfix::complete_postfix(acc, ctx, dot_access);
 +        }
 +        NameRefKind::Keyword(item) => {
 +            keyword::complete_for_and_where(acc, ctx, item);
 +        }
 +        NameRefKind::RecordExpr { dot_prefix, expr } => {
 +            record::complete_record_expr_fields(acc, ctx, expr, dot_prefix);
 +        }
 +        NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx),
 +    }
 +}
 +
 +fn complete_patterns(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +) {
 +    flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
 +    fn_param::complete_fn_param(acc, ctx, pattern_ctx);
 +    pattern::complete_pattern(acc, ctx, pattern_ctx);
 +    record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
 +}
index 588b52cc1ee3a72090d66899fdf89756ad6c48f3,0000000000000000000000000000000000000000..3192b21cfb2e2da3ae3bd49b5e560c561fa58fd1
mode 100644,000000..100644
--- /dev/null
@@@ -1,312 -1,0 +1,320 @@@
-                             .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
 +//! Completion of names from the current scope in expression position.
 +
 +use hir::ScopeDef;
 +use syntax::ast;
 +
 +use crate::{
 +    completions::record::add_default_update,
 +    context::{ExprCtx, PathCompletionCtx, Qualified},
 +    CompletionContext, Completions,
 +};
 +
 +pub(crate) fn complete_expr_path(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
 +    expr_ctx: &ExprCtx,
 +) {
 +    let _p = profile::span("complete_expr_path");
 +    if !ctx.qualifier_ctx.none() {
 +        return;
 +    }
 +
 +    let &ExprCtx {
 +        in_block_expr,
 +        in_loop_body,
 +        after_if_expr,
 +        in_condition,
 +        incomplete_let,
 +        ref ref_expr_parent,
 +        ref is_func_update,
 +        ref innermost_ret_ty,
 +        ref impl_,
 +        in_match_guard,
 +        ..
 +    } = expr_ctx;
 +
 +    let wants_mut_token =
 +        ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
 +
 +    let scope_def_applicable = |def| match def {
 +        ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
 +        ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
 +        _ => true,
 +    };
 +
 +    let add_assoc_item = |acc: &mut Completions, item| match item {
 +        hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
 +        hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
 +        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
 +    };
 +
 +    match qualified {
 +        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
 +            .traits_in_scope()
 +            .iter()
 +            .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
 +            .for_each(|item| add_assoc_item(acc, item)),
 +        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
 +            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
 +        }
 +        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
 +            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                cov_mark::hit!(completes_variant_through_alias);
 +                acc.add_enum_variants(ctx, path_ctx, e);
 +            }
 +
 +            ctx.iterate_path_candidates(&ty, |item| {
 +                add_assoc_item(acc, item);
 +            });
 +
 +            // Iterate assoc types separately
 +            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
 +                if let hir::AssocItem::TypeAlias(ty) = item {
 +                    acc.add_type_alias(ctx, ty)
 +                }
 +                None::<()>
 +            });
 +        }
 +        Qualified::With { resolution: None, .. } => {}
 +        Qualified::With { resolution: Some(resolution), .. } => {
 +            // Add associated types on type parameters and `Self`.
 +            ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
 +                acc.add_type_alias(ctx, alias);
 +                None::<()>
 +            });
 +            match resolution {
 +                hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
 +                    let module_scope = module.scope(ctx.db, Some(ctx.module));
 +                    for (name, def) in module_scope {
 +                        if scope_def_applicable(def) {
 +                            acc.add_path_resolution(ctx, path_ctx, name, def);
 +                        }
 +                    }
 +                }
 +                hir::PathResolution::Def(
 +                    def @ (hir::ModuleDef::Adt(_)
 +                    | hir::ModuleDef::TypeAlias(_)
 +                    | hir::ModuleDef::BuiltinType(_)),
 +                ) => {
 +                    let ty = match def {
 +                        hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
 +                        hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
 +                        hir::ModuleDef::BuiltinType(builtin) => {
 +                            cov_mark::hit!(completes_primitive_assoc_const);
 +                            builtin.ty(ctx.db)
 +                        }
 +                        _ => return,
 +                    };
 +
 +                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                        cov_mark::hit!(completes_variant_through_alias);
 +                        acc.add_enum_variants(ctx, path_ctx, e);
 +                    }
 +
 +                    // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
 +                    // (where AssocType is defined on a trait, not an inherent impl)
 +
 +                    ctx.iterate_path_candidates(&ty, |item| {
 +                        add_assoc_item(acc, item);
 +                    });
 +
 +                    // Iterate assoc types separately
 +                    ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
 +                        if let hir::AssocItem::TypeAlias(ty) = item {
 +                            acc.add_type_alias(ctx, ty)
 +                        }
 +                        None::<()>
 +                    });
 +                }
 +                hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
 +                    // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
 +                    for item in t.items(ctx.db) {
 +                        add_assoc_item(acc, item);
 +                    }
 +                }
 +                hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
 +                    let ty = match resolution {
 +                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
 +                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
 +                        _ => return,
 +                    };
 +
 +                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                        cov_mark::hit!(completes_variant_through_self);
 +                        acc.add_enum_variants(ctx, path_ctx, e);
 +                    }
 +
 +                    ctx.iterate_path_candidates(&ty, |item| {
 +                        add_assoc_item(acc, item);
 +                    });
 +                }
 +                _ => (),
 +            }
 +        }
 +        Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
 +        Qualified::No => {
 +            acc.add_nameref_keywords_with_colon(ctx);
 +            if let Some(adt) =
 +                ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
 +            {
 +                let self_ty = (|| ctx.sema.to_def(impl_.as_ref()?)?.self_ty(ctx.db).as_adt())();
 +                let complete_self = self_ty == Some(adt);
 +
 +                match adt {
 +                    hir::Adt::Struct(strukt) => {
 +                        let path = ctx
 +                            .module
-                             .find_use_path(ctx.db, hir::ModuleDef::from(un))
++                            .find_use_path(
++                                ctx.db,
++                                hir::ModuleDef::from(strukt),
++                                ctx.config.prefer_no_std,
++                            )
 +                            .filter(|it| it.len() > 1);
 +
 +                        acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
 +
 +                        if complete_self {
 +                            acc.add_struct_literal(
 +                                ctx,
 +                                path_ctx,
 +                                strukt,
 +                                None,
 +                                Some(hir::known::SELF_TYPE),
 +                            );
 +                        }
 +                    }
 +                    hir::Adt::Union(un) => {
 +                        let path = ctx
 +                            .module
++                            .find_use_path(
++                                ctx.db,
++                                hir::ModuleDef::from(un),
++                                ctx.config.prefer_no_std,
++                            )
 +                            .filter(|it| it.len() > 1);
 +
 +                        acc.add_union_literal(ctx, un, path, None);
 +                        if complete_self {
 +                            acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE));
 +                        }
 +                    }
 +                    hir::Adt::Enum(e) => {
 +                        super::enum_variants_with_paths(
 +                            acc,
 +                            ctx,
 +                            e,
 +                            impl_,
 +                            |acc, ctx, variant, path| {
 +                                acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
 +                            },
 +                        );
 +                    }
 +                }
 +            }
 +            ctx.process_all_names(&mut |name, def| match def {
 +                ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
 +                    let assocs = t.items_with_supertraits(ctx.db);
 +                    match &*assocs {
 +                        // traits with no assoc items are unusable as expressions since
 +                        // there is no associated item path that can be constructed with them
 +                        [] => (),
 +                        // FIXME: Render the assoc item with the trait qualified
 +                        &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                        // FIXME: Append `::` to the thing here, since a trait on its own won't work
 +                        [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                    }
 +                }
 +                _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                _ => (),
 +            });
 +
 +            match is_func_update {
 +                Some(record_expr) => {
 +                    let ty = ctx.sema.type_of_expr(&ast::Expr::RecordExpr(record_expr.clone()));
 +
 +                    match ty.as_ref().and_then(|t| t.original.as_adt()) {
 +                        Some(hir::Adt::Union(_)) => (),
 +                        _ => {
 +                            cov_mark::hit!(functional_update);
 +                            let missing_fields =
 +                                ctx.sema.record_literal_missing_fields(record_expr);
 +                            if !missing_fields.is_empty() {
 +                                add_default_update(acc, ctx, ty);
 +                            }
 +                        }
 +                    };
 +                }
 +                None => {
 +                    let mut add_keyword = |kw, snippet| {
 +                        acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet)
 +                    };
 +
 +                    if !in_block_expr {
 +                        add_keyword("unsafe", "unsafe {\n    $0\n}");
 +                    }
 +                    add_keyword("match", "match $1 {\n    $0\n}");
 +                    add_keyword("while", "while $1 {\n    $0\n}");
 +                    add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
 +                    add_keyword("loop", "loop {\n    $0\n}");
 +                    if in_match_guard {
 +                        add_keyword("if", "if $0");
 +                    } else {
 +                        add_keyword("if", "if $1 {\n    $0\n}");
 +                    }
 +                    add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
 +                    add_keyword("for", "for $1 in $2 {\n    $0\n}");
 +                    add_keyword("true", "true");
 +                    add_keyword("false", "false");
 +
 +                    if in_condition || in_block_expr {
 +                        add_keyword("let", "let");
 +                    }
 +
 +                    if after_if_expr {
 +                        add_keyword("else", "else {\n    $0\n}");
 +                        add_keyword("else if", "else if $1 {\n    $0\n}");
 +                    }
 +
 +                    if wants_mut_token {
 +                        add_keyword("mut", "mut ");
 +                    }
 +
 +                    if in_loop_body {
 +                        if in_block_expr {
 +                            add_keyword("continue", "continue;");
 +                            add_keyword("break", "break;");
 +                        } else {
 +                            add_keyword("continue", "continue");
 +                            add_keyword("break", "break");
 +                        }
 +                    }
 +
 +                    if let Some(ret_ty) = innermost_ret_ty {
 +                        add_keyword(
 +                            "return",
 +                            match (ret_ty.is_unit(), in_block_expr) {
 +                                (true, true) => {
 +                                    cov_mark::hit!(return_unit_block);
 +                                    "return;"
 +                                }
 +                                (true, false) => {
 +                                    cov_mark::hit!(return_unit_no_block);
 +                                    "return"
 +                                }
 +                                (false, true) => {
 +                                    cov_mark::hit!(return_value_block);
 +                                    "return $0;"
 +                                }
 +                                (false, false) => {
 +                                    cov_mark::hit!(return_value_no_block);
 +                                    "return $0"
 +                                }
 +                            },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
index f04cc15d7fabd844eff4d5e8900a89e5c03f5999,0000000000000000000000000000000000000000..364969af9c9abc8aa6721d9ccbdfa1f515915251
mode 100644,000000..100644
--- /dev/null
@@@ -1,407 -1,0 +1,415 @@@
-             .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
 +//! See [`import_on_the_fly`].
 +use hir::{ItemInNs, ModuleDef};
 +use ide_db::imports::{
 +    import_assets::{ImportAssets, LocatedImport},
 +    insert_use::ImportScope,
 +};
 +use itertools::Itertools;
 +use syntax::{
 +    ast::{self},
 +    AstNode, SyntaxNode, T,
 +};
 +
 +use crate::{
 +    context::{
 +        CompletionContext, DotAccess, PathCompletionCtx, PathKind, PatternContext, Qualified,
 +        TypeLocation,
 +    },
 +    render::{render_resolution_with_import, render_resolution_with_import_pat, RenderContext},
 +};
 +
 +use super::Completions;
 +
 +// Feature: Completion With Autoimport
 +//
 +// When completing names in the current scope, proposes additional imports from other modules or crates,
 +// if they can be qualified in the scope, and their name contains all symbols from the completion input.
 +//
 +// To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
 +// If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
 +//
 +// ```
 +// fn main() {
 +//     pda$0
 +// }
 +// # pub mod std { pub mod marker { pub struct PhantomData { } } }
 +// ```
 +// ->
 +// ```
 +// use std::marker::PhantomData;
 +//
 +// fn main() {
 +//     PhantomData
 +// }
 +// # pub mod std { pub mod marker { pub struct PhantomData { } } }
 +// ```
 +//
 +// Also completes associated items, that require trait imports.
 +// If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
 +// Currently, only the imports with their import path ending with the whole qualifier will be proposed
 +// (no fuzzy matching for qualifier).
 +//
 +// ```
 +// mod foo {
 +//     pub mod bar {
 +//         pub struct Item;
 +//
 +//         impl Item {
 +//             pub const TEST_ASSOC: usize = 3;
 +//         }
 +//     }
 +// }
 +//
 +// fn main() {
 +//     bar::Item::TEST_A$0
 +// }
 +// ```
 +// ->
 +// ```
 +// use foo::bar;
 +//
 +// mod foo {
 +//     pub mod bar {
 +//         pub struct Item;
 +//
 +//         impl Item {
 +//             pub const TEST_ASSOC: usize = 3;
 +//         }
 +//     }
 +// }
 +//
 +// fn main() {
 +//     bar::Item::TEST_ASSOC
 +// }
 +// ```
 +//
 +// NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
 +// no imports will be proposed.
 +//
 +// .Fuzzy search details
 +//
 +// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
 +// (i.e. in `HashMap` in the `std::collections::HashMap` path).
 +// For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
 +// (but shows all associated items for any input length).
 +//
 +// .Import configuration
 +//
 +// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
 +// Mimics the corresponding behavior of the `Auto Import` feature.
 +//
 +// .LSP and performance implications
 +//
 +// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
 +// (case-sensitive) resolve client capability in its client capabilities.
 +// This way the server is able to defer the costly computations, doing them for a selected completion item only.
 +// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
 +// which might be slow ergo the feature is automatically disabled.
 +//
 +// .Feature toggle
 +//
 +// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
 +// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
 +// capability enabled.
 +pub(crate) fn import_on_the_fly_path(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +) -> Option<()> {
 +    if !ctx.config.enable_imports_on_the_fly {
 +        return None;
 +    }
 +    let qualified = match path_ctx {
 +        PathCompletionCtx {
 +            kind:
 +                PathKind::Expr { .. }
 +                | PathKind::Type { .. }
 +                | PathKind::Attr { .. }
 +                | PathKind::Derive { .. }
 +                | PathKind::Item { .. }
 +                | PathKind::Pat { .. },
 +            qualified,
 +            ..
 +        } => qualified,
 +        _ => return None,
 +    };
 +    let potential_import_name = import_name(ctx);
 +    let qualifier = match qualified {
 +        Qualified::With { path, .. } => Some(path.clone()),
 +        _ => None,
 +    };
 +    let import_assets = import_assets_for_path(ctx, &potential_import_name, qualifier.clone())?;
 +
 +    import_on_the_fly(
 +        acc,
 +        ctx,
 +        path_ctx,
 +        import_assets,
 +        qualifier.map(|it| it.syntax().clone()).or_else(|| ctx.original_token.parent())?,
 +        potential_import_name,
 +    )
 +}
 +
 +pub(crate) fn import_on_the_fly_pat(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +) -> Option<()> {
 +    if !ctx.config.enable_imports_on_the_fly {
 +        return None;
 +    }
 +    if let PatternContext { record_pat: Some(_), .. } = pattern_ctx {
 +        return None;
 +    }
 +
 +    let potential_import_name = import_name(ctx);
 +    let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
 +
 +    import_on_the_fly_pat_(
 +        acc,
 +        ctx,
 +        pattern_ctx,
 +        import_assets,
 +        ctx.original_token.parent()?,
 +        potential_import_name,
 +    )
 +}
 +
 +pub(crate) fn import_on_the_fly_dot(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    dot_access: &DotAccess,
 +) -> Option<()> {
 +    if !ctx.config.enable_imports_on_the_fly {
 +        return None;
 +    }
 +    let receiver = dot_access.receiver.as_ref()?;
 +    let ty = dot_access.receiver_ty.as_ref()?;
 +    let potential_import_name = import_name(ctx);
 +    let import_assets = ImportAssets::for_fuzzy_method_call(
 +        ctx.module,
 +        ty.original.clone(),
 +        potential_import_name.clone(),
 +        receiver.syntax().clone(),
 +    )?;
 +
 +    import_on_the_fly_method(
 +        acc,
 +        ctx,
 +        dot_access,
 +        import_assets,
 +        receiver.syntax().clone(),
 +        potential_import_name,
 +    )
 +}
 +
 +fn import_on_the_fly(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx,
 +    import_assets: ImportAssets,
 +    position: SyntaxNode,
 +    potential_import_name: String,
 +) -> Option<()> {
 +    let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
 +
 +    if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
 +        return None;
 +    }
 +
 +    let ns_filter = |import: &LocatedImport| {
 +        match (kind, import.original_item) {
 +            // Aren't handled in flyimport
 +            (PathKind::Vis { .. } | PathKind::Use, _) => false,
 +            // modules are always fair game
 +            (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
 +            // and so are macros(except for attributes)
 +            (
 +                PathKind::Expr { .. }
 +                | PathKind::Type { .. }
 +                | PathKind::Item { .. }
 +                | PathKind::Pat { .. },
 +                ItemInNs::Macros(mac),
 +            ) => mac.is_fn_like(ctx.db),
 +            (PathKind::Item { .. }, ..) => false,
 +
 +            (PathKind::Expr { .. }, ItemInNs::Types(_) | ItemInNs::Values(_)) => true,
 +
 +            (PathKind::Pat { .. }, ItemInNs::Types(_)) => true,
 +            (PathKind::Pat { .. }, ItemInNs::Values(def)) => {
 +                matches!(def, hir::ModuleDef::Const(_))
 +            }
 +
 +            (PathKind::Type { location }, ItemInNs::Types(ty)) => {
 +                if matches!(location, TypeLocation::TypeBound) {
 +                    matches!(ty, ModuleDef::Trait(_))
 +                } else {
 +                    true
 +                }
 +            }
 +            (PathKind::Type { .. }, ItemInNs::Values(_)) => false,
 +
 +            (PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
 +            (PathKind::Attr { .. }, _) => false,
 +
 +            (PathKind::Derive { existing_derives }, ItemInNs::Macros(mac)) => {
 +                mac.is_derive(ctx.db) && !existing_derives.contains(&mac)
 +            }
 +            (PathKind::Derive { .. }, _) => false,
 +        }
 +    };
 +    let user_input_lowercased = potential_import_name.to_lowercase();
 +
 +    acc.add_all(
 +        import_assets
-             .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
++            .search_for_imports(
++                &ctx.sema,
++                ctx.config.insert_use.prefix_kind,
++                ctx.config.prefer_no_std,
++            )
 +            .into_iter()
 +            .filter(ns_filter)
 +            .filter(|import| {
 +                !ctx.is_item_hidden(&import.item_to_import)
 +                    && !ctx.is_item_hidden(&import.original_item)
 +            })
 +            .sorted_by_key(|located_import| {
 +                compute_fuzzy_completion_order_key(
 +                    &located_import.import_path,
 +                    &user_input_lowercased,
 +                )
 +            })
 +            .filter_map(|import| {
 +                render_resolution_with_import(RenderContext::new(ctx), path_ctx, import)
 +            })
 +            .map(|builder| builder.build()),
 +    );
 +    Some(())
 +}
 +
 +fn import_on_the_fly_pat_(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    import_assets: ImportAssets,
 +    position: SyntaxNode,
 +    potential_import_name: String,
 +) -> Option<()> {
 +    let _p = profile::span("import_on_the_fly_pat").detail(|| potential_import_name.clone());
 +
 +    if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
 +        return None;
 +    }
 +
 +    let ns_filter = |import: &LocatedImport| match import.original_item {
 +        ItemInNs::Macros(mac) => mac.is_fn_like(ctx.db),
 +        ItemInNs::Types(_) => true,
 +        ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
 +    };
 +    let user_input_lowercased = potential_import_name.to_lowercase();
 +
 +    acc.add_all(
 +        import_assets
-         .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
++            .search_for_imports(
++                &ctx.sema,
++                ctx.config.insert_use.prefix_kind,
++                ctx.config.prefer_no_std,
++            )
 +            .into_iter()
 +            .filter(ns_filter)
 +            .filter(|import| {
 +                !ctx.is_item_hidden(&import.item_to_import)
 +                    && !ctx.is_item_hidden(&import.original_item)
 +            })
 +            .sorted_by_key(|located_import| {
 +                compute_fuzzy_completion_order_key(
 +                    &located_import.import_path,
 +                    &user_input_lowercased,
 +                )
 +            })
 +            .filter_map(|import| {
 +                render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import)
 +            })
 +            .map(|builder| builder.build()),
 +    );
 +    Some(())
 +}
 +
 +fn import_on_the_fly_method(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    dot_access: &DotAccess,
 +    import_assets: ImportAssets,
 +    position: SyntaxNode,
 +    potential_import_name: String,
 +) -> Option<()> {
 +    let _p = profile::span("import_on_the_fly_method").detail(|| potential_import_name.clone());
 +
 +    if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
 +        return None;
 +    }
 +
 +    let user_input_lowercased = potential_import_name.to_lowercase();
 +
 +    import_assets
++        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std)
 +        .into_iter()
 +        .filter(|import| {
 +            !ctx.is_item_hidden(&import.item_to_import)
 +                && !ctx.is_item_hidden(&import.original_item)
 +        })
 +        .sorted_by_key(|located_import| {
 +            compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased)
 +        })
 +        .for_each(|import| match import.original_item {
 +            ItemInNs::Values(hir::ModuleDef::Function(f)) => {
 +                acc.add_method_with_import(ctx, dot_access, f, import);
 +            }
 +            _ => (),
 +        });
 +    Some(())
 +}
 +
 +fn import_name(ctx: &CompletionContext<'_>) -> String {
 +    let token_kind = ctx.token.kind();
 +    if matches!(token_kind, T![.] | T![::]) {
 +        String::new()
 +    } else {
 +        ctx.token.to_string()
 +    }
 +}
 +
 +fn import_assets_for_path(
 +    ctx: &CompletionContext<'_>,
 +    potential_import_name: &str,
 +    qualifier: Option<ast::Path>,
 +) -> Option<ImportAssets> {
 +    let fuzzy_name_length = potential_import_name.len();
 +    let mut assets_for_path = ImportAssets::for_fuzzy_path(
 +        ctx.module,
 +        qualifier,
 +        potential_import_name.to_owned(),
 +        &ctx.sema,
 +        ctx.token.parent()?,
 +    )?;
 +    if fuzzy_name_length < 3 {
 +        cov_mark::hit!(flyimport_exact_on_short_path);
 +        assets_for_path.path_fuzzy_name_to_exact(false);
 +    }
 +    Some(assets_for_path)
 +}
 +
 +fn compute_fuzzy_completion_order_key(
 +    proposed_mod_path: &hir::ModPath,
 +    user_input_lowercased: &str,
 +) -> usize {
 +    cov_mark::hit!(certain_fuzzy_order_test);
 +    let import_name = match proposed_mod_path.segments().last() {
 +        Some(name) => name.to_smol_str().to_lowercase(),
 +        None => return usize::MAX,
 +    };
 +    match import_name.match_indices(user_input_lowercased).next() {
 +        Some((first_matching_index, _)) => first_matching_index,
 +        None => usize::MAX,
 +    }
 +}
index 71d2d9d434b449f915dbad29a58c756ae591b651,0000000000000000000000000000000000000000..58d5bf114cca4abfbee7ae0f200c92e9c1780a0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,185 -1,0 +1,186 @@@
 +//! Completes constants and paths in unqualified patterns.
 +
 +use hir::{db::DefDatabase, AssocItem, ScopeDef};
 +use syntax::ast::Pat;
 +
 +use crate::{
 +    context::{PathCompletionCtx, PatternContext, PatternRefutability, Qualified},
 +    CompletionContext, Completions,
 +};
 +
 +/// Completes constants and paths in unqualified patterns.
 +pub(crate) fn complete_pattern(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +) {
 +    match pattern_ctx.parent_pat.as_ref() {
 +        Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
 +        Some(Pat::RefPat(r)) => {
 +            if r.mut_token().is_none() {
 +                acc.add_keyword(ctx, "mut");
 +            }
 +        }
 +        _ => {
 +            let tok = ctx.token.text_range().start();
 +            match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
 +                (None, None) => {
 +                    acc.add_keyword(ctx, "ref");
 +                    acc.add_keyword(ctx, "mut");
 +                }
 +                (None, Some(m)) if tok < m.text_range().start() => {
 +                    acc.add_keyword(ctx, "ref");
 +                }
 +                (Some(r), None) if tok > r.text_range().end() => {
 +                    acc.add_keyword(ctx, "mut");
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    if pattern_ctx.record_pat.is_some() {
 +        return;
 +    }
 +
 +    let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
 +    let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
 +
 +    if let Some(hir::Adt::Enum(e)) =
 +        ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
 +    {
 +        if refutable || single_variant_enum(e) {
 +            super::enum_variants_with_paths(
 +                acc,
 +                ctx,
 +                e,
 +                &pattern_ctx.impl_,
 +                |acc, ctx, variant, path| {
 +                    acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
 +                },
 +            );
 +        }
 +    }
 +
 +    // FIXME: ideally, we should look at the type we are matching against and
 +    // suggest variants + auto-imports
 +    ctx.process_all_names(&mut |name, res| {
 +        let add_simple_path = match res {
 +            hir::ScopeDef::ModuleDef(def) => match def {
 +                hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
 +                    acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
 +                    true
 +                }
 +                hir::ModuleDef::Variant(variant)
 +                    if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
 +                {
 +                    acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
 +                    true
 +                }
 +                hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
 +                hir::ModuleDef::Const(..) => refutable,
 +                hir::ModuleDef::Module(..) => true,
 +                hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
 +                _ => false,
 +            },
 +            hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
 +                Some(hir::Adt::Struct(strukt)) => {
 +                    acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
 +                    true
 +                }
 +                Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
 +                Some(hir::Adt::Union(_)) => true,
 +                _ => false,
 +            },
 +            ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => true,
 +            ScopeDef::GenericParam(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => false,
 +        };
 +        if add_simple_path {
 +            acc.add_pattern_resolution(ctx, pattern_ctx, name, res);
 +        }
 +    });
 +}
 +
 +pub(crate) fn complete_pattern_path(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
 +) {
 +    match qualified {
 +        Qualified::With { resolution: Some(resolution), super_chain_len, .. } => {
 +            acc.add_super_keyword(ctx, *super_chain_len);
 +
 +            match resolution {
 +                hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
 +                    let module_scope = module.scope(ctx.db, Some(ctx.module));
 +                    for (name, def) in module_scope {
 +                        let add_resolution = match def {
 +                            ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
 +                                mac.is_fn_like(ctx.db)
 +                            }
 +                            ScopeDef::ModuleDef(_) => true,
 +                            _ => false,
 +                        };
 +
 +                        if add_resolution {
 +                            acc.add_path_resolution(ctx, path_ctx, name, def);
 +                        }
 +                    }
 +                }
 +                res => {
 +                    let ty = match res {
 +                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
 +                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
 +                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(s))) => {
 +                            s.ty(ctx.db)
 +                        }
 +                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
 +                            e.ty(ctx.db)
 +                        }
 +                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
 +                            u.ty(ctx.db)
 +                        }
 +                        hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db),
++                        hir::PathResolution::Def(hir::ModuleDef::TypeAlias(ty)) => ty.ty(ctx.db),
 +                        _ => return,
 +                    };
 +
 +                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                        acc.add_enum_variants(ctx, path_ctx, e);
 +                    }
 +
 +                    ctx.iterate_path_candidates(&ty, |item| match item {
 +                        AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
 +                        AssocItem::Const(c) => acc.add_const(ctx, c),
 +                        _ => {}
 +                    });
 +                }
 +            }
 +        }
 +        Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
 +        Qualified::No => {
 +            // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern
 +            ctx.process_all_names(&mut |name, res| {
 +                // FIXME: we should check what kind of pattern we are in and filter accordingly
 +                let add_completion = match res {
 +                    ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
 +                    ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
 +                    ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
 +                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
 +                    ScopeDef::ImplSelfType(_) => true,
 +                    _ => false,
 +                };
 +                if add_completion {
 +                    acc.add_path_resolution(ctx, path_ctx, name, res);
 +                }
 +            });
 +
 +            acc.add_nameref_keywords_with_colon(ctx);
 +        }
 +        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
 +    }
 +}
index b273a4cb53ba1da2631b42798f5ecd86c11c1805,0000000000000000000000000000000000000000..b43bdb9ab9d1a5b861b148195bfdee890c56192e
mode 100644,000000..100644
--- /dev/null
@@@ -1,311 -1,0 +1,88 @@@
- use ide_db::SnippetCap;
- use syntax::ast::{self, AstToken};
 +// Feature: Format String Completion
 +//
 +// `"Result {result} is {2 + 2}"` is expanded to the `"Result {} is {}", result, 2 + 2`.
 +//
 +// The following postfix snippets are available:
 +//
 +// * `format` -> `format!(...)`
 +// * `panic` -> `panic!(...)`
 +// * `println` -> `println!(...)`
 +// * `log`:
 +// ** `logd` -> `log::debug!(...)`
 +// ** `logt` -> `log::trace!(...)`
 +// ** `logi` -> `log::info!(...)`
 +// ** `logw` -> `log::warn!(...)`
 +// ** `loge` -> `log::error!(...)`
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
 +
-     let input = match string_literal_contents(receiver_text) {
-         // It's not a string literal, do not parse input.
-         Some(input) => input,
-         None => return,
-     };
++use ide_db::{
++    syntax_helpers::format_string_exprs::{parse_format_exprs, with_placeholders},
++    SnippetCap,
++};
++use syntax::{ast, AstToken};
 +
 +use crate::{
 +    completions::postfix::build_postfix_snippet_builder, context::CompletionContext, Completions,
 +};
 +
 +/// Mapping ("postfix completion item" => "macro to use")
 +static KINDS: &[(&str, &str)] = &[
 +    ("format", "format!"),
 +    ("panic", "panic!"),
 +    ("println", "println!"),
 +    ("eprintln", "eprintln!"),
 +    ("logd", "log::debug!"),
 +    ("logt", "log::trace!"),
 +    ("logi", "log::info!"),
 +    ("logw", "log::warn!"),
 +    ("loge", "log::error!"),
 +];
 +
 +pub(crate) fn add_format_like_completions(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    dot_receiver: &ast::Expr,
 +    cap: SnippetCap,
 +    receiver_text: &ast::String,
 +) {
-     let mut parser = FormatStrParser::new(input);
 +    let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
 +        Some(it) => it,
 +        None => return,
 +    };
-     if parser.parse().is_ok() {
 +
-             let snippet = parser.to_suggestion(macro_name);
++    if let Ok((out, exprs)) = parse_format_exprs(receiver_text.text()) {
++        let exprs = with_placeholders(exprs);
 +        for (label, macro_name) in KINDS {
- /// Checks whether provided item is a string literal.
- fn string_literal_contents(item: &ast::String) -> Option<String> {
-     let item = item.text();
-     if item.len() >= 2 && item.starts_with('\"') && item.ends_with('\"') {
-         return Some(item[1..item.len() - 1].to_owned());
-     }
-     None
- }
- /// 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.
- #[derive(Debug)]
- pub(crate) struct FormatStrParser {
-     input: String,
-     output: String,
-     extracted_expressions: Vec<String>,
-     state: State,
-     parsed: bool,
- }
- #[derive(Debug, Clone, Copy, PartialEq)]
- enum State {
-     NotExpr,
-     MaybeExpr,
-     Expr,
-     MaybeIncorrect,
-     FormatOpts,
- }
- impl FormatStrParser {
-     pub(crate) fn new(input: String) -> Self {
-         Self {
-             input,
-             output: String::new(),
-             extracted_expressions: Vec::new(),
-             state: State::NotExpr,
-             parsed: false,
-         }
-     }
-     pub(crate) fn parse(&mut self) -> Result<(), ()> {
-         let mut current_expr = String::new();
-         let mut placeholder_id = 1;
-         // Count of open braces inside of an expression.
-         // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
-         // "{MyStruct { val_a: 0, val_b: 1 }}".
-         let mut inexpr_open_count = 0;
-         // We need to escape '\' and '$'. See the comments on `get_receiver_text()` for detail.
-         let mut chars = self.input.chars().peekable();
-         while let Some(chr) = chars.next() {
-             match (self.state, chr) {
-                 (State::NotExpr, '{') => {
-                     self.output.push(chr);
-                     self.state = State::MaybeExpr;
-                 }
-                 (State::NotExpr, '}') => {
-                     self.output.push(chr);
-                     self.state = State::MaybeIncorrect;
-                 }
-                 (State::NotExpr, _) => {
-                     if matches!(chr, '\\' | '$') {
-                         self.output.push('\\');
-                     }
-                     self.output.push(chr);
-                 }
-                 (State::MaybeIncorrect, '}') => {
-                     // It's okay, we met "}}".
-                     self.output.push(chr);
-                     self.state = State::NotExpr;
-                 }
-                 (State::MaybeIncorrect, _) => {
-                     // Error in the string.
-                     return Err(());
-                 }
-                 (State::MaybeExpr, '{') => {
-                     self.output.push(chr);
-                     self.state = State::NotExpr;
-                 }
-                 (State::MaybeExpr, '}') => {
-                     // This is an empty sequence '{}'. Replace it with placeholder.
-                     self.output.push(chr);
-                     self.extracted_expressions.push(format!("${}", placeholder_id));
-                     placeholder_id += 1;
-                     self.state = State::NotExpr;
-                 }
-                 (State::MaybeExpr, _) => {
-                     if matches!(chr, '\\' | '$') {
-                         current_expr.push('\\');
-                     }
-                     current_expr.push(chr);
-                     self.state = State::Expr;
-                 }
-                 (State::Expr, '}') => {
-                     if inexpr_open_count == 0 {
-                         self.output.push(chr);
-                         self.extracted_expressions.push(current_expr.trim().into());
-                         current_expr = String::new();
-                         self.state = State::NotExpr;
-                     } else {
-                         // We're closing one brace met before inside of the expression.
-                         current_expr.push(chr);
-                         inexpr_open_count -= 1;
-                     }
-                 }
-                 (State::Expr, ':') if chars.peek().copied() == Some(':') => {
-                     // path separator
-                     current_expr.push_str("::");
-                     chars.next();
-                 }
-                 (State::Expr, ':') => {
-                     if inexpr_open_count == 0 {
-                         // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
-                         self.output.push(chr);
-                         self.extracted_expressions.push(current_expr.trim().into());
-                         current_expr = String::new();
-                         self.state = State::FormatOpts;
-                     } else {
-                         // We're inside of braced expression, assume that it's a struct field name/value delimiter.
-                         current_expr.push(chr);
-                     }
-                 }
-                 (State::Expr, '{') => {
-                     current_expr.push(chr);
-                     inexpr_open_count += 1;
-                 }
-                 (State::Expr, _) => {
-                     if matches!(chr, '\\' | '$') {
-                         current_expr.push('\\');
-                     }
-                     current_expr.push(chr);
-                 }
-                 (State::FormatOpts, '}') => {
-                     self.output.push(chr);
-                     self.state = State::NotExpr;
-                 }
-                 (State::FormatOpts, _) => {
-                     if matches!(chr, '\\' | '$') {
-                         self.output.push('\\');
-                     }
-                     self.output.push(chr);
-                 }
-             }
-         }
-         if self.state != State::NotExpr {
-             return Err(());
-         }
-         self.parsed = true;
-         Ok(())
-     }
-     pub(crate) fn to_suggestion(&self, macro_name: &str) -> String {
-         assert!(self.parsed, "Attempt to get a suggestion from not parsed expression");
-         let expressions_as_string = self.extracted_expressions.join(", ");
-         format!(r#"{}("{}", {})"#, macro_name, self.output, expressions_as_string)
-     }
- }
++            let snippet = format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", "));
 +
 +            postfix_snippet(label, macro_name, &snippet).add_to(acc);
 +        }
 +    }
 +}
 +
-     use expect_test::{expect, Expect};
-     fn check(input: &str, expect: &Expect) {
-         let mut parser = FormatStrParser::new((*input).to_owned());
-         let outcome_repr = if parser.parse().is_ok() {
-             // Parsing should be OK, expected repr is "string; expr_1, expr_2".
-             if parser.extracted_expressions.is_empty() {
-                 parser.output
-             } else {
-                 format!("{}; {}", parser.output, parser.extracted_expressions.join(", "))
-             }
-         } else {
-             // Parsing should fail, expected repr is "-".
-             "-".to_owned()
-         };
-         expect.assert_eq(&outcome_repr);
-     }
-     #[test]
-     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"]),
-             ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
-             ("{expr:?}", expect![["{:?}; expr"]]),
-             ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
-             ("{$0}", expect![[r"{}; \$0"]]),
-             ("{malformed", expect![["-"]]),
-             ("malformed}", expect![["-"]]),
-             ("{{correct", expect![["{{correct"]]),
-             ("correct}}", expect![["correct}}"]]),
-             ("{correct}}}", expect![["{}}}; correct"]]),
-             ("{correct}}}}}", expect![["{}}}}}; correct"]]),
-             ("{incorrect}}", expect![["-"]]),
-             ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
-             ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
-             (
-                 "{SomeStruct { val_a: 0, val_b: 1 }}",
-                 expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
-             ),
-             ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
-             (
-                 "{SomeStruct { val_a: 0, val_b: 1 }:?}",
-                 expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
-             ),
-             ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
-             ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
-             ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
-             ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
-         ];
-         for (input, output) in test_vector {
-             check(input, output)
-         }
-     }
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
-             let mut parser = FormatStrParser::new((*input).to_owned());
-             parser.parse().expect("Parsing must succeed");
-             assert_eq!(&parser.to_suggestion(*kind), output);
 +
 +    #[test]
 +    fn test_into_suggestion() {
 +        let test_vector = &[
 +            ("println!", "{}", r#"println!("{}", $1)"#),
 +            ("eprintln!", "{}", r#"eprintln!("{}", $1)"#),
 +            (
 +                "log::info!",
 +                "{} {expr} {} {2 + 2}",
 +                r#"log::info!("{} {} {} {}", $1, expr, $2, 2 + 2)"#,
 +            ),
 +            ("format!", "{expr:?}", r#"format!("{:?}", expr)"#),
 +        ];
 +
 +        for (kind, input, output) in test_vector {
++            let (parsed_string, exprs) = parse_format_exprs(input).unwrap();
++            let exprs = with_placeholders(exprs);
++            let snippet = format!(r#"{}("{}", {})"#, kind, parsed_string, exprs.join(", "));
++            assert_eq!(&snippet, output);
 +        }
 +    }
 +}
index 80d6af28168f5c778b7fb117faabdcebf0e1154a,0000000000000000000000000000000000000000..a0f5e81b4fb6c3396efd9d1ec7093e6402f43e85
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,42 @@@
 +//! Settings for tweaking completion.
 +//!
 +//! The fun thing here is `SnippetCap` -- this type can only be created in this
 +//! module, and we use to statically check that we only produce snippet
 +//! completions if we are allowed to.
 +
 +use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
 +
 +use crate::snippet::Snippet;
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct CompletionConfig {
 +    pub enable_postfix_completions: bool,
 +    pub enable_imports_on_the_fly: bool,
 +    pub enable_self_on_the_fly: bool,
 +    pub enable_private_editable: bool,
 +    pub callable: Option<CallableSnippets>,
 +    pub snippet_cap: Option<SnippetCap>,
 +    pub insert_use: InsertUseConfig,
++    pub prefer_no_std: bool,
 +    pub snippets: Vec<Snippet>,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum CallableSnippets {
 +    FillArguments,
 +    AddParentheses,
 +}
 +
 +impl CompletionConfig {
 +    pub fn postfix_snippets(&self) -> impl Iterator<Item = (&str, &Snippet)> {
 +        self.snippets
 +            .iter()
 +            .flat_map(|snip| snip.postfix_triggers.iter().map(move |trigger| (&**trigger, snip)))
 +    }
 +
 +    pub fn prefix_snippets(&self) -> impl Iterator<Item = (&str, &Snippet)> {
 +        self.snippets
 +            .iter()
 +            .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
 +    }
 +}
index ae1a440d06da7cc9a40ab97d1af122c00a815d64,0000000000000000000000000000000000000000..8d21f4fce0a2b324a3fc112c23ac2faef9560afa
mode 100644,000000..100644
--- /dev/null
@@@ -1,247 -1,0 +1,252 @@@
-                 current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
 +//! `completions` crate provides utilities for generating completions of user input.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod completions;
 +mod config;
 +mod context;
 +mod item;
 +mod render;
 +
 +#[cfg(test)]
 +mod tests;
 +mod snippet;
 +
 +use ide_db::{
 +    base_db::FilePosition,
 +    helpers::mod_path_to_ast,
 +    imports::{
 +        import_assets::NameToImport,
 +        insert_use::{self, ImportScope},
 +    },
 +    items_locator, RootDatabase,
 +};
 +use syntax::algo;
 +use text_edit::TextEdit;
 +
 +use crate::{
 +    completions::Completions,
 +    context::{
 +        CompletionAnalysis, CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx,
 +        PathKind,
 +    },
 +};
 +
 +pub use crate::{
 +    config::{CallableSnippets, CompletionConfig},
 +    item::{
 +        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
 +    },
 +    snippet::{Snippet, SnippetScope},
 +};
 +
 +//FIXME: split the following feature into fine-grained features.
 +
 +// Feature: Magic Completions
 +//
 +// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
 +// completions as well:
 +//
 +// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
 +// is placed at the appropriate position. Even though `if` is easy to type, you
 +// still want to complete it, to get ` { }` for free! `return` is inserted with a
 +// space or `;` depending on the return type of the function.
 +//
 +// When completing a function call, `()` are automatically inserted. If a function
 +// takes arguments, the cursor is positioned inside the parenthesis.
 +//
 +// There are postfix completions, which can be triggered by typing something like
 +// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
 +//
 +// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
 +// - `expr.match` -> `match expr {}`
 +// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
 +// - `expr.ref` -> `&expr`
 +// - `expr.refm` -> `&mut expr`
 +// - `expr.let` -> `let $0 = expr;`
 +// - `expr.letm` -> `let mut $0 = expr;`
 +// - `expr.not` -> `!expr`
 +// - `expr.dbg` -> `dbg!(expr)`
 +// - `expr.dbgr` -> `dbg!(&expr)`
 +// - `expr.call` -> `(expr)`
 +//
 +// There also snippet completions:
 +//
 +// .Expressions
 +// - `pd` -> `eprintln!(" = {:?}", );`
 +// - `ppd` -> `eprintln!(" = {:#?}", );`
 +//
 +// .Items
 +// - `tfn` -> `#[test] fn feature(){}`
 +// - `tmod` ->
 +// ```rust
 +// #[cfg(test)]
 +// mod tests {
 +//     use super::*;
 +//
 +//     #[test]
 +//     fn test_name() {}
 +// }
 +// ```
 +//
 +// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
 +// Those are the additional completion options with automatic `use` import and options from all project importable items,
 +// fuzzy matched against the completion input.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]
 +
 +/// Main entry point for completion. We run completion as a two-phase process.
 +///
 +/// First, we look at the position and collect a so-called `CompletionContext.
 +/// This is a somewhat messy process, because, during completion, syntax tree is
 +/// incomplete and can look really weird.
 +///
 +/// Once the context is collected, we run a series of completion routines which
 +/// look at the context and produce completion items. One subtlety about this
 +/// phase is that completion engine should not filter by the substring which is
 +/// already present, it should give all possible variants for the identifier at
 +/// the caret. In other words, for
 +///
 +/// ```no_run
 +/// fn f() {
 +///     let foo = 92;
 +///     let _ = bar$0
 +/// }
 +/// ```
 +///
 +/// `foo` *should* be present among the completion variants. Filtering by
 +/// identifier prefix/fuzzy match should be done higher in the stack, together
 +/// with ordering of completions (currently this is done by the client).
 +///
 +/// # Speculative Completion Problem
 +///
 +/// There's a curious unsolved problem in the current implementation. Often, you
 +/// want to compute completions on a *slightly different* text document.
 +///
 +/// In the simplest case, when the code looks like `let x = `, you want to
 +/// insert a fake identifier to get a better syntax tree: `let x = complete_me`.
 +///
 +/// We do this in `CompletionContext`, and it works OK-enough for *syntax*
 +/// analysis. However, we might want to, eg, ask for the type of `complete_me`
 +/// variable, and that's where our current infrastructure breaks down. salsa
 +/// doesn't allow such "phantom" inputs.
 +///
 +/// Another case where this would be instrumental is macro expansion. We want to
 +/// insert a fake ident and re-expand code. There's `expand_speculative` as a
 +/// work-around for this.
 +///
 +/// A different use-case is completion of injection (examples and links in doc
 +/// comments). When computing completion for a path in a doc-comment, you want
 +/// to inject a fake path expression into the item being documented and complete
 +/// that.
 +///
 +/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a
 +/// temporary PSI node, and say that the context ("parent") of this node is some
 +/// existing node. Asking for, eg, type of this `CodeFragment` node works
 +/// correctly, as the underlying infrastructure makes use of contexts to do
 +/// analysis.
 +pub fn completions(
 +    db: &RootDatabase,
 +    config: &CompletionConfig,
 +    position: FilePosition,
 +    trigger_character: Option<char>,
 +) -> Option<Vec<CompletionItem>> {
 +    let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
 +    let mut completions = Completions::default();
 +
 +    // prevent `(` from triggering unwanted completion noise
 +    if trigger_character == Some('(') {
 +        if let CompletionAnalysis::NameRef(NameRefContext { kind, .. }) = &analysis {
 +            if let NameRefKind::Path(
 +                path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. },
 +            ) = kind
 +            {
 +                completions::vis::complete_vis_path(&mut completions, ctx, path_ctx, has_in_token);
 +            }
 +        }
 +        // prevent `(` from triggering unwanted completion noise
 +        return Some(completions.into());
 +    }
 +
 +    {
 +        let acc = &mut completions;
 +
 +        match &analysis {
 +            CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx),
 +            CompletionAnalysis::NameRef(name_ref_ctx) => {
 +                completions::complete_name_ref(acc, ctx, name_ref_ctx)
 +            }
 +            CompletionAnalysis::Lifetime(lifetime_ctx) => {
 +                completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
 +                completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx);
 +            }
 +            CompletionAnalysis::String { original, expanded: Some(expanded) } => {
 +                completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
 +                completions::format_string::format_string(acc, ctx, original, expanded);
 +            }
 +            CompletionAnalysis::UnexpandedAttrTT {
 +                colon_prefix,
 +                fake_attribute_under_caret: Some(attr),
 +            } => {
 +                completions::attribute::complete_known_attribute_input(
 +                    acc,
 +                    ctx,
 +                    colon_prefix,
 +                    attr,
 +                );
 +            }
 +            CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),
 +        }
 +    }
 +
 +    Some(completions.into())
 +}
 +
 +/// Resolves additional completion data at the position given.
 +/// This is used for import insertion done via completions like flyimport and custom user snippets.
 +pub fn resolve_completion_edits(
 +    db: &RootDatabase,
 +    config: &CompletionConfig,
 +    FilePosition { file_id, offset }: FilePosition,
 +    imports: impl IntoIterator<Item = (String, String)>,
 +) -> Option<Vec<TextEdit>> {
 +    let _p = profile::span("resolve_completion_edits");
 +    let sema = hir::Semantics::new(db);
 +
 +    let original_file = sema.parse(file_id);
 +    let original_token =
 +        syntax::AstNode::syntax(&original_file).token_at_offset(offset).left_biased()?;
 +    let position_for_import = &original_token.parent()?;
 +    let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?;
 +
 +    let current_module = sema.scope(position_for_import)?.module();
 +    let current_crate = current_module.krate();
 +    let new_ast = scope.clone_for_update();
 +    let mut import_insert = TextEdit::builder();
 +
 +    imports.into_iter().for_each(|(full_import_path, imported_name)| {
 +        let items_with_name = items_locator::items_with_name(
 +            &sema,
 +            current_crate,
 +            NameToImport::exact_case_sensitive(imported_name),
 +            items_locator::AssocItemSearch::Include,
 +            Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +        );
 +        let import = items_with_name
 +            .filter_map(|candidate| {
++                current_module.find_use_path_prefixed(
++                    db,
++                    candidate,
++                    config.insert_use.prefix_kind,
++                    config.prefer_no_std,
++                )
 +            })
 +            .find(|mod_path| mod_path.to_string() == full_import_path);
 +        if let Some(import_path) = import {
 +            insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use);
 +        }
 +    });
 +
 +    algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
 +    Some(vec![import_insert.finish()])
 +}
index dc1039fa623e85ad924f8c01e3d0d277a472d9d9,0000000000000000000000000000000000000000..f3b8eae4fe8cd8c25fff08afa889326e37da642e
mode 100644,000000..100644
--- /dev/null
@@@ -1,214 -1,0 +1,218 @@@
-         let path =
-             ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
 +//! User (postfix)-snippet definitions.
 +//!
 +//! Actual logic is implemented in [`crate::completions::postfix`] and [`crate::completions::snippet`] respectively.
 +
 +// Feature: User Snippet Completions
 +//
 +// rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable.
 +//
 +// A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets.custom` object respectively.
 +//
 +// [source,json]
 +// ----
 +// {
 +//   "rust-analyzer.completion.snippets.custom": {
 +//     "thread spawn": {
 +//       "prefix": ["spawn", "tspawn"],
 +//       "body": [
 +//         "thread::spawn(move || {",
 +//         "\t$0",
 +//         "});",
 +//       ],
 +//       "description": "Insert a thread::spawn call",
 +//       "requires": "std::thread",
 +//       "scope": "expr",
 +//     }
 +//   }
 +// }
 +// ----
 +//
 +// In the example above:
 +//
 +// * `"thread spawn"` is the name of the snippet.
 +//
 +// * `prefix` defines one or more trigger words that will trigger the snippets completion.
 +// Using `postfix` will instead create a postfix snippet.
 +//
 +// * `body` is one or more lines of content joined via newlines for the final output.
 +//
 +// * `description` is an optional description of the snippet, if unset the snippet name will be used.
 +//
 +// * `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered.
 +// On failure of resolution the snippet won't be applicable, otherwise the snippet will insert an import for the items on insertion if
 +// the items aren't yet in scope.
 +//
 +// * `scope` is an optional filter for when the snippet should be applicable. Possible values are:
 +// ** for Snippet-Scopes: `expr`, `item` (default: `item`)
 +// ** for Postfix-Snippet-Scopes: `expr`, `type` (default: `expr`)
 +//
 +// The `body` field also has access to placeholders as visible in the example as `$0`.
 +// These placeholders take the form of `$number` or `${number:placeholder_text}` which can be traversed as tabstop in ascending order starting from 1,
 +// with `$0` being a special case that always comes last.
 +//
 +// There is also a special placeholder, `${receiver}`, which will be replaced by the receiver expression for postfix snippets, or a `$0` tabstop in case of normal snippets.
 +// This replacement for normal snippets allows you to reuse a snippet for both post- and prefix in a single definition.
 +//
 +// For the VSCode editor, rust-analyzer also ships with a small set of defaults which can be removed
 +// by overwriting the settings object mentioned above, the defaults are:
 +// [source,json]
 +// ----
 +// {
 +//     "Arc::new": {
 +//         "postfix": "arc",
 +//         "body": "Arc::new(${receiver})",
 +//         "requires": "std::sync::Arc",
 +//         "description": "Put the expression into an `Arc`",
 +//         "scope": "expr"
 +//     },
 +//     "Rc::new": {
 +//         "postfix": "rc",
 +//         "body": "Rc::new(${receiver})",
 +//         "requires": "std::rc::Rc",
 +//         "description": "Put the expression into an `Rc`",
 +//         "scope": "expr"
 +//     },
 +//     "Box::pin": {
 +//         "postfix": "pinbox",
 +//         "body": "Box::pin(${receiver})",
 +//         "requires": "std::boxed::Box",
 +//         "description": "Put the expression into a pinned `Box`",
 +//         "scope": "expr"
 +//     },
 +//     "Ok": {
 +//         "postfix": "ok",
 +//         "body": "Ok(${receiver})",
 +//         "description": "Wrap the expression in a `Result::Ok`",
 +//         "scope": "expr"
 +//     },
 +//     "Err": {
 +//         "postfix": "err",
 +//         "body": "Err(${receiver})",
 +//         "description": "Wrap the expression in a `Result::Err`",
 +//         "scope": "expr"
 +//     },
 +//     "Some": {
 +//         "postfix": "some",
 +//         "body": "Some(${receiver})",
 +//         "description": "Wrap the expression in an `Option::Some`",
 +//         "scope": "expr"
 +//     }
 +// }
 +// ----
 +
 +use ide_db::imports::import_assets::LocatedImport;
 +use itertools::Itertools;
 +use syntax::{ast, AstNode, GreenNode, SyntaxNode};
 +
 +use crate::context::CompletionContext;
 +
 +/// A snippet scope describing where a snippet may apply to.
 +/// These may differ slightly in meaning depending on the snippet trigger.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum SnippetScope {
 +    Item,
 +    Expr,
 +    Type,
 +}
 +
 +/// A user supplied snippet.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct Snippet {
 +    pub postfix_triggers: Box<[Box<str>]>,
 +    pub prefix_triggers: Box<[Box<str>]>,
 +    pub scope: SnippetScope,
 +    pub description: Option<Box<str>>,
 +    snippet: String,
 +    // These are `ast::Path`'s but due to SyntaxNodes not being Send we store these
 +    // and reconstruct them on demand instead. This is cheaper than reparsing them
 +    // from strings
 +    requires: Box<[GreenNode]>,
 +}
 +
 +impl Snippet {
 +    pub fn new(
 +        prefix_triggers: &[String],
 +        postfix_triggers: &[String],
 +        snippet: &[String],
 +        description: &str,
 +        requires: &[String],
 +        scope: SnippetScope,
 +    ) -> Option<Self> {
 +        if prefix_triggers.is_empty() && postfix_triggers.is_empty() {
 +            return None;
 +        }
 +        let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
 +        Some(Snippet {
 +            // Box::into doesn't work as that has a Copy bound 😒
 +            postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
 +            prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
 +            scope,
 +            snippet,
 +            description,
 +            requires,
 +        })
 +    }
 +
 +    /// Returns [`None`] if the required items do not resolve.
 +    pub(crate) fn imports(&self, ctx: &CompletionContext<'_>) -> Option<Vec<LocatedImport>> {
 +        import_edits(ctx, &self.requires)
 +    }
 +
 +    pub fn snippet(&self) -> String {
 +        self.snippet.replace("${receiver}", "$0")
 +    }
 +
 +    pub fn postfix_snippet(&self, receiver: &str) -> String {
 +        self.snippet.replace("${receiver}", receiver)
 +    }
 +}
 +
 +fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
 +    let resolve = |import: &GreenNode| {
 +        let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
 +        let item = match ctx.scope.speculative_resolve(&path)? {
 +            hir::PathResolution::Def(def) => def.into(),
 +            _ => return None,
 +        };
++        let path = ctx.module.find_use_path_prefixed(
++            ctx.db,
++            item,
++            ctx.config.insert_use.prefix_kind,
++            ctx.config.prefer_no_std,
++        )?;
 +        Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
 +    };
 +    let mut res = Vec::with_capacity(requires.len());
 +    for import in requires {
 +        match resolve(import) {
 +            Some(first) => res.extend(first),
 +            None => return None,
 +        }
 +    }
 +    Some(res)
 +}
 +
 +fn validate_snippet(
 +    snippet: &[String],
 +    description: &str,
 +    requires: &[String],
 +) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
 +    let mut imports = Vec::with_capacity(requires.len());
 +    for path in requires.iter() {
 +        let use_path = ast::SourceFile::parse(&format!("use {};", path))
 +            .syntax_node()
 +            .descendants()
 +            .find_map(ast::Path::cast)?;
 +        if use_path.syntax().text() != path.as_str() {
 +            return None;
 +        }
 +        let green = use_path.syntax().green().into_owned();
 +        imports.push(green);
 +    }
 +    let snippet = snippet.iter().join("\n");
 +    let description = (!description.is_empty())
 +        .then(|| description.split_once('\n').map_or(description, |(it, _)| it))
 +        .map(ToOwned::to_owned)
 +        .map(Into::into);
 +    Some((imports.into_boxed_slice(), snippet, description))
 +}
index cf826648dcf7b92426d162055248a2f7248a91c3,0000000000000000000000000000000000000000..9e2beb9ee328862289fd507f504a4e79767ec903
mode 100644,000000..100644
--- /dev/null
@@@ -1,305 -1,0 +1,306 @@@
 +//! Tests and test utilities for completions.
 +//!
 +//! Most tests live in this module or its submodules. The tests in these submodules are "location"
 +//! oriented, that is they try to check completions for something like type position, param position
 +//! etc.
 +//! Tests that are more orientated towards specific completion types like visibility checks of path
 +//! completions or `check_edit` tests usually live in their respective completion modules instead.
 +//! This gives this test module and its submodules here the main purpose of giving the developer an
 +//! overview of whats being completed where, not how.
 +
 +mod attribute;
 +mod expression;
 +mod flyimport;
 +mod fn_param;
 +mod item_list;
 +mod item;
 +mod pattern;
 +mod predicate;
 +mod proc_macros;
 +mod record;
 +mod special;
 +mod type_pos;
 +mod use_tree;
 +mod visibility;
 +
 +use hir::{db::DefDatabase, PrefixKind, Semantics};
 +use ide_db::{
 +    base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
 +    imports::insert_use::{ImportGranularity, InsertUseConfig},
 +    RootDatabase, SnippetCap,
 +};
 +use itertools::Itertools;
 +use stdx::{format_to, trim_indent};
 +use syntax::{AstNode, NodeOrToken, SyntaxElement};
 +use test_utils::assert_eq_text;
 +
 +use crate::{
 +    resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem,
 +    CompletionItemKind,
 +};
 +
 +/// Lots of basic item definitions
 +const BASE_ITEMS_FIXTURE: &str = r#"
 +enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
 +use self::Enum::TupleV;
 +mod module {}
 +
 +trait Trait {}
 +static STATIC: Unit = Unit;
 +const CONST: Unit = Unit;
 +struct Record { field: u32 }
 +struct Tuple(u32);
 +struct Unit;
 +#[macro_export]
 +macro_rules! makro {}
 +#[rustc_builtin_macro]
 +pub macro Clone {}
 +fn function() {}
 +union Union { field: i32 }
 +"#;
 +
 +pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
 +    enable_postfix_completions: true,
 +    enable_imports_on_the_fly: true,
 +    enable_self_on_the_fly: true,
 +    enable_private_editable: false,
 +    callable: Some(CallableSnippets::FillArguments),
 +    snippet_cap: SnippetCap::new(true),
++    prefer_no_std: false,
 +    insert_use: InsertUseConfig {
 +        granularity: ImportGranularity::Crate,
 +        prefix_kind: PrefixKind::Plain,
 +        enforce_granularity: true,
 +        group: true,
 +        skip_glob_imports: true,
 +    },
 +    snippets: Vec::new(),
 +};
 +
 +pub(crate) fn completion_list(ra_fixture: &str) -> String {
 +    completion_list_with_config(TEST_CONFIG, ra_fixture, true, None)
 +}
 +
 +pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
 +    completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
 +}
 +
 +pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
 +    let mut config = TEST_CONFIG.clone();
 +    config.enable_private_editable = true;
 +    completion_list_with_config(config, ra_fixture, false, None)
 +}
 +
 +pub(crate) fn completion_list_with_trigger_character(
 +    ra_fixture: &str,
 +    trigger_character: Option<char>,
 +) -> String {
 +    completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
 +}
 +
 +fn completion_list_with_config(
 +    config: CompletionConfig,
 +    ra_fixture: &str,
 +    include_keywords: bool,
 +    trigger_character: Option<char>,
 +) -> String {
 +    // filter out all but one builtintype completion for smaller test outputs
 +    let items = get_all_items(config, ra_fixture, trigger_character);
 +    let items = items
 +        .into_iter()
 +        .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
 +        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
 +        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
 +        .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
 +        .collect();
 +    render_completion_list(items)
 +}
 +
 +/// Creates analysis from a multi-file fixture, returns positions marked with $0.
 +pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
 +    let change_fixture = ChangeFixture::parse(ra_fixture);
 +    let mut database = RootDatabase::default();
 +    database.set_enable_proc_attr_macros(true);
 +    database.apply_change(change_fixture.change);
 +    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
 +    let offset = range_or_offset.expect_offset();
 +    (database, FilePosition { file_id, offset })
 +}
 +
 +pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec<CompletionItem> {
 +    do_completion_with_config(TEST_CONFIG, code, kind)
 +}
 +
 +pub(crate) fn do_completion_with_config(
 +    config: CompletionConfig,
 +    code: &str,
 +    kind: CompletionItemKind,
 +) -> Vec<CompletionItem> {
 +    get_all_items(config, code, None)
 +        .into_iter()
 +        .filter(|c| c.kind() == kind)
 +        .sorted_by(|l, r| l.label().cmp(r.label()))
 +        .collect()
 +}
 +
 +fn render_completion_list(completions: Vec<CompletionItem>) -> String {
 +    fn monospace_width(s: &str) -> usize {
 +        s.chars().count()
 +    }
 +    let label_width =
 +        completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(22);
 +    completions
 +        .into_iter()
 +        .map(|it| {
 +            let tag = it.kind().tag();
 +            let var_name = format!("{} {}", tag, it.label());
 +            let mut buf = var_name;
 +            if let Some(detail) = it.detail() {
 +                let width = label_width.saturating_sub(monospace_width(it.label()));
 +                format_to!(buf, "{:width$} {}", "", detail, width = width);
 +            }
 +            if it.deprecated() {
 +                format_to!(buf, " DEPRECATED");
 +            }
 +            format_to!(buf, "\n");
 +            buf
 +        })
 +        .collect()
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
 +    check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_edit_with_config(
 +    config: CompletionConfig,
 +    what: &str,
 +    ra_fixture_before: &str,
 +    ra_fixture_after: &str,
 +) {
 +    let ra_fixture_after = trim_indent(ra_fixture_after);
 +    let (db, position) = position(ra_fixture_before);
 +    let completions: Vec<CompletionItem> =
 +        crate::completions(&db, &config, position, None).unwrap().into();
 +    let (completion,) = completions
 +        .iter()
 +        .filter(|it| it.lookup() == what)
 +        .collect_tuple()
 +        .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
 +    let mut actual = db.file_text(position.file_id).to_string();
 +
 +    let mut combined_edit = completion.text_edit().to_owned();
 +
 +    resolve_completion_edits(
 +        &db,
 +        &config,
 +        position,
 +        completion.imports_to_add().iter().filter_map(|import_edit| {
 +            let import_path = &import_edit.import_path;
 +            let import_name = import_path.segments().last()?;
 +            Some((import_path.to_string(), import_name.to_string()))
 +        }),
 +    )
 +    .into_iter()
 +    .flatten()
 +    .for_each(|text_edit| {
 +        combined_edit.union(text_edit).expect(
 +            "Failed to apply completion resolve changes: change ranges overlap, but should not",
 +        )
 +    });
 +
 +    combined_edit.apply(&mut actual);
 +    assert_eq_text!(&ra_fixture_after, &actual)
 +}
 +
 +pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) {
 +    let (db, pos) = position(code);
 +
 +    let sema = Semantics::new(&db);
 +    let original_file = sema.parse(pos.file_id);
 +    let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
 +    assert!(check(NodeOrToken::Token(token)));
 +}
 +
 +pub(crate) fn get_all_items(
 +    config: CompletionConfig,
 +    code: &str,
 +    trigger_character: Option<char>,
 +) -> Vec<CompletionItem> {
 +    let (db, position) = position(code);
 +    let res = crate::completions(&db, &config, position, trigger_character)
 +        .map_or_else(Vec::default, Into::into);
 +    // validate
 +    res.iter().for_each(|it| {
 +        let sr = it.source_range();
 +        assert!(
 +            sr.contains_inclusive(position.offset),
 +            "source range {sr:?} does not contain the offset {:?} of the completion request: {it:?}",
 +            position.offset
 +        );
 +    });
 +    res
 +}
 +
 +#[test]
 +fn test_no_completions_required() {
 +    assert_eq!(completion_list(r#"fn foo() { for i i$0 }"#), String::new());
 +}
 +
 +#[test]
 +fn regression_10042() {
 +    completion_list(
 +        r#"
 +macro_rules! preset {
 +    ($($x:ident)&&*) => {
 +        {
 +            let mut v = Vec::new();
 +            $(
 +                v.push($x.into());
 +            )*
 +            v
 +        }
 +    };
 +}
 +
 +fn foo() {
 +    preset!(foo$0);
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn no_completions_in_comments() {
 +    assert_eq!(
 +        completion_list(
 +            r#"
 +fn test() {
 +let x = 2; // A comment$0
 +}
 +"#,
 +        ),
 +        String::new(),
 +    );
 +    assert_eq!(
 +        completion_list(
 +            r#"
 +/*
 +Some multi-line comment$0
 +*/
 +"#,
 +        ),
 +        String::new(),
 +    );
 +    assert_eq!(
 +        completion_list(
 +            r#"
 +/// Some doc comment
 +/// let test$0 = 1
 +"#,
 +        ),
 +        String::new(),
 +    );
 +}
index 85c4dbd6625dfcfc891a073c885eab6eec98780b,0000000000000000000000000000000000000000..db8bef66405efb3e55e564c55385edfe9dc7b823
mode 100644,000000..100644
--- /dev/null
@@@ -1,716 -1,0 +1,743 @@@
 +//! Completion tests for pattern position.
 +use expect_test::{expect, Expect};
 +
 +use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
 +
 +fn check_empty(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(ra_fixture);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture));
 +    expect.assert_eq(&actual)
 +}
 +
 +#[test]
 +fn wildcard() {
 +    check(
 +        r#"
 +fn quux() {
 +    let _$0
 +}
 +"#,
 +        expect![""],
 +    );
 +}
 +
 +#[test]
 +fn ident_rebind_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let en$0 @ x
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn ident_ref_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref en$0
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref en$0 @ x
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn ident_ref_mut_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref mut en$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref mut en$0 @ x
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn ref_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let &en$0
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let &mut en$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +    check_empty(
 +        r#"
 +fn foo() {
 +    for &$0 in () {}
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn refutable() {
 +    check(
 +        r#"
 +fn foo() {
 +    if let a$0
 +}
 +"#,
 +        expect![[r#"
 +            ct CONST
 +            en Enum
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            ev TupleV
 +            bn Record {…} Record { field$1 }$0
 +            bn Tuple(…)   Tuple($1)$0
 +            bn TupleV(…)  TupleV($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn irrefutable() {
 +    check(
 +        r#"
 +enum SingleVariantEnum {
 +    Variant
 +}
 +use SingleVariantEnum::Variant;
 +fn foo() {
 +   let a$0
 +}
 +"#,
 +        expect![[r#"
 +            en SingleVariantEnum
 +            ma makro!(…)         macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            ev Variant
 +            bn Record {…}        Record { field$1 }$0
 +            bn Tuple(…)          Tuple($1)$0
 +            bn Variant           Variant$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_param() {
 +    check(
 +        r#"
 +fn foo(a$0) {
 +}
 +"#,
 +        expect![[r#"
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            bn Record {…} Record { field$1 }: Record$0
 +            bn Tuple(…)   Tuple($1): Tuple$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check(
 +        r#"
 +fn foo(a$0: Tuple) {
 +}
 +"#,
 +        expect![[r#"
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            bn Record {…} Record { field$1 }$0
 +            bn Tuple(…)   Tuple($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn only_fn_like_macros() {
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +
 +#[rustc_builtin_macro]
 +macro Clone {}
 +
 +fn foo() {
 +    let x$0
 +}
 +"#,
 +        expect![[r#"
 +            ma m!(…) macro_rules! m
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_simple_macro_call() {
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +enum E { X }
 +
 +fn foo() {
 +   m!(match E::X { a$0 })
 +}
 +"#,
 +        expect![[r#"
 +            en E
 +            ma m!(…) macro_rules! m
 +            bn E::X  E::X$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn omits_private_fields_pat() {
 +    check_empty(
 +        r#"
 +mod foo {
 +    pub struct Record { pub field: i32, _field: i32 }
 +    pub struct Tuple(pub u32, u32);
 +    pub struct Invisible(u32, u32);
 +}
 +use foo::*;
 +
 +fn outer() {
 +    if let a$0
 +}
 +"#,
 +        expect![[r#"
 +            md foo
 +            st Invisible
 +            st Record
 +            st Tuple
 +            bn Record {…} Record { field$1, .. }$0
 +            bn Tuple(…)   Tuple($1, ..)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_self_pats() {
 +    check_empty(
 +        r#"
 +struct Foo(i32);
 +impl Foo {
 +    fn foo() {
 +        match Foo(0) {
 +            a$0
 +        }
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            sp Self
 +            st Foo
 +            bn Foo(…)  Foo($1)$0
 +            bn Self(…) Self($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn enum_qualified() {
 +    check(
 +        r#"
 +impl Enum {
 +    type AssocType = ();
 +    const ASSOC_CONST: () = ();
 +    fn assoc_fn() {}
 +}
 +fn func() {
 +    if let Enum::$0 = unknown {}
 +}
 +"#,
 +        expect![[r#"
 +            ct ASSOC_CONST const ASSOC_CONST: ()
 +            bn RecordV {…} RecordV { field$1 }$0
 +            bn TupleV(…)   TupleV($1)$0
 +            bn UnitV       UnitV$0
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_in_record_field_pat() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn outer(Foo { bar: $0 }: Foo) {}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1)$0
 +            bn Foo {…} Foo { bar$1 }$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn skips_in_record_field_pat_name() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn outer(Foo { bar$0 }: Foo) {}
 +"#,
 +        expect![[r#"
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_in_fn_param() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn foo($0) {}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1): Bar$0
 +            bn Foo {…} Foo { bar$1 }: Foo$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_in_closure_param() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn foo() {
 +    |$0| {};
 +}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1)$0
 +            bn Foo {…} Foo { bar$1 }$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_no_delims_if_existing() {
 +    check_empty(
 +        r#"
 +struct Bar(u32);
 +fn foo() {
 +    match Bar(0) {
 +        B$0(b) => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            kw crate::
 +            kw self::
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Foo { bar: u32 }
 +fn foo() {
 +    match (Foo { bar: 0 }) {
 +        F$0 { bar } => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            st Foo
 +            kw crate::
 +            kw self::
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +enum Enum {
 +    TupleVariant(u32)
 +}
 +fn foo() {
 +    match Enum::TupleVariant(0) {
 +        Enum::T$0(b) => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn TupleVariant TupleVariant
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordV$0 { field } => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn RecordVariant RecordVariant
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_enum_variant_pat() {
 +    cov_mark::check!(enum_variant_pattern_path);
 +    check_edit(
 +        "RecordVariant{}",
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordV$0
 +    }
 +}
 +"#,
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordVariant { field$1 }$0
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn completes_enum_variant_pat_escape() {
 +    cov_mark::check!(enum_variant_pattern_path);
 +    check_empty(
 +        r#"
 +enum Enum {
 +    A,
 +    B { r#type: i32 },
 +    r#type,
 +    r#struct { r#type: i32 },
 +}
 +fn foo() {
 +    match (Enum::A) {
 +        $0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            en Enum
 +            bn Enum::A          Enum::A$0
 +            bn Enum::B {…}      Enum::B { r#type$1 }$0
 +            bn Enum::struct {…} Enum::r#struct { r#type$1 }$0
 +            bn Enum::type       Enum::r#type$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +enum Enum {
 +    A,
 +    B { r#type: i32 },
 +    r#type,
 +    r#struct { r#type: i32 },
 +}
 +fn foo() {
 +    match (Enum::A) {
 +        Enum::$0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn A          A$0
 +            bn B {…}      B { r#type$1 }$0
 +            bn struct {…} r#struct { r#type$1 }$0
 +            bn type       r#type$0
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_associated_const() {
 +    check_empty(
 +        r#"
 +#[derive(PartialEq, Eq)]
 +struct Ty(u8);
 +
 +impl Ty {
 +    const ABC: Self = Self(0);
 +}
 +
 +fn f(t: Ty) {
 +    match t {
 +        Ty::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct ABC const ABC: Self
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +enum MyEnum {}
 +
 +impl MyEnum {
 +    pub const A: i32 = 123;
 +    pub const B: i32 = 456;
 +}
 +
 +fn f(e: MyEnum) {
 +    match e {
 +        MyEnum::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct A pub const A: i32
 +            ct B pub const B: i32
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +union U {
 +    i: i32,
 +    f: f32,
 +}
 +
 +impl U {
 +    pub const C: i32 = 123;
 +    pub const D: i32 = 456;
 +}
 +
 +fn f(u: U) {
 +    match u {
 +        U::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct C pub const C: i32
 +            ct D pub const D: i32
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +#[lang = "u32"]
 +impl u32 {
 +    pub const MIN: Self = 0;
 +}
 +
 +fn f(v: u32) {
 +    match v {
 +        u32::$0
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            ct MIN pub const MIN: Self
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_method_param() {
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo($0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(s$0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(s$0, foo: u8)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(foo: u8, b$0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn Self(…) Self($1): Self$0
 +            bn Ty(…)   Ty($1): Ty$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
++
++#[test]
++fn through_alias() {
++    check_empty(
++        r#"
++enum Enum<T> {
++    Unit,
++    Tuple(T),
++}
++
++type EnumAlias<T> = Enum<T>;
++
++fn f(x: EnumAlias<u8>) {
++    match x {
++        EnumAlias::$0 => (),
++        _ => (),
++    }
++
++}
++
++"#,
++        expect![[r#"
++            bn Tuple(…) Tuple($1)$0
++            bn Unit     Unit$0
++        "#]],
++    );
++}
index a1b0bd6cb304422f6b3110686f2059cddafa2693,0000000000000000000000000000000000000000..30272bc16f636754489c6838c64448ac48f8283a
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,40 @@@
 +[package]
 +name = "ide-db"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +cov-mark = "2.0.0-pre.1"
 +tracing = "0.1.35"
 +rayon = "1.5.3"
 +fst = { version = "0.4.7", default-features = false }
 +rustc-hash = "1.1.0"
 +once_cell = "1.12.0"
 +either = "1.7.0"
 +itertools = "0.10.3"
 +arrayvec = "0.7.2"
 +indexmap = "1.9.1"
++memchr = "2.5.0"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +parser = { path = "../parser", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +# ide should depend only on the top-level `hir` package. if you need
 +# something from some `hir-xxx` subpackage, reexport the API via `hir`.
 +hir = { path = "../hir", version = "0.0.0" }
 +limit = { path = "../limit", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +xshell = "0.2.2"
 +expect-test = "1.4.0"
index 26ef86155e5343b750a3d993f8a004c8aa0abecb,0000000000000000000000000000000000000000..40a6a3e8970fb770428c092b901ad23bc1bf7536
mode 100644,000000..100644
--- /dev/null
@@@ -1,674 -1,0 +1,679 @@@
-         self.search_for(sema, Some(prefix_kind))
 +//! Look up accessible paths for items.
 +use hir::{
 +    AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, ModPath, Module, ModuleDef,
 +    PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type,
 +};
 +use itertools::Itertools;
 +use rustc_hash::FxHashSet;
 +use syntax::{
 +    ast::{self, HasName},
 +    utils::path_to_string_stripping_turbo_fish,
 +    AstNode, SyntaxNode,
 +};
 +
 +use crate::{
 +    helpers::item_name,
 +    items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
 +    RootDatabase,
 +};
 +
 +/// A candidate for import, derived during various IDE activities:
 +/// * completion with imports on the fly proposals
 +/// * completion edit resolve requests
 +/// * assists
 +/// * etc.
 +#[derive(Debug)]
 +pub enum ImportCandidate {
 +    /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
 +    Path(PathImportCandidate),
 +    /// A trait associated function (with no self parameter) or an associated constant.
 +    /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type
 +    /// and `name` is the `test_function`
 +    TraitAssocItem(TraitImportCandidate),
 +    /// A trait method with self parameter.
 +    /// For 'test_enum.test_method()', `ty` is the `test_enum` expression type
 +    /// and `name` is the `test_method`
 +    TraitMethod(TraitImportCandidate),
 +}
 +
 +/// A trait import needed for a given associated item access.
 +/// For `some::path::SomeStruct::ASSOC_`, contains the
 +/// type of `some::path::SomeStruct` and `ASSOC_` as the item name.
 +#[derive(Debug)]
 +pub struct TraitImportCandidate {
 +    /// A type of the item that has the associated item accessed at.
 +    pub receiver_ty: Type,
 +    /// The associated item name that the trait to import should contain.
 +    pub assoc_item_name: NameToImport,
 +}
 +
 +/// Path import for a given name, qualified or not.
 +#[derive(Debug)]
 +pub struct PathImportCandidate {
 +    /// Optional qualifier before name.
 +    pub qualifier: Option<FirstSegmentUnresolved>,
 +    /// The name the item (struct, trait, enum, etc.) should have.
 +    pub name: NameToImport,
 +}
 +
 +/// A qualifier that has a first segment and it's unresolved.
 +#[derive(Debug)]
 +pub struct FirstSegmentUnresolved {
 +    fist_segment: ast::NameRef,
 +    full_qualifier: ast::Path,
 +}
 +
 +/// A name that will be used during item lookups.
 +#[derive(Debug, Clone)]
 +pub enum NameToImport {
 +    /// Requires items with names that exactly match the given string, bool indicates case-sensitivity.
 +    Exact(String, bool),
 +    /// Requires items with names that case-insensitively contain all letters from the string,
 +    /// in the same order, but not necessary adjacent.
 +    Fuzzy(String),
 +}
 +
 +impl NameToImport {
 +    pub fn exact_case_sensitive(s: String) -> NameToImport {
 +        NameToImport::Exact(s, true)
 +    }
 +}
 +
 +impl NameToImport {
 +    pub fn text(&self) -> &str {
 +        match self {
 +            NameToImport::Exact(text, _) => text.as_str(),
 +            NameToImport::Fuzzy(text) => text.as_str(),
 +        }
 +    }
 +}
 +
 +/// A struct to find imports in the project, given a certain name (or its part) and the context.
 +#[derive(Debug)]
 +pub struct ImportAssets {
 +    import_candidate: ImportCandidate,
 +    candidate_node: SyntaxNode,
 +    module_with_candidate: Module,
 +}
 +
 +impl ImportAssets {
 +    pub fn for_method_call(
 +        method_call: &ast::MethodCallExpr,
 +        sema: &Semantics<'_, RootDatabase>,
 +    ) -> Option<Self> {
 +        let candidate_node = method_call.syntax().clone();
 +        Some(Self {
 +            import_candidate: ImportCandidate::for_method_call(sema, method_call)?,
 +            module_with_candidate: sema.scope(&candidate_node)?.module(),
 +            candidate_node,
 +        })
 +    }
 +
 +    pub fn for_exact_path(
 +        fully_qualified_path: &ast::Path,
 +        sema: &Semantics<'_, RootDatabase>,
 +    ) -> Option<Self> {
 +        let candidate_node = fully_qualified_path.syntax().clone();
 +        if let Some(use_tree) = candidate_node.ancestors().find_map(ast::UseTree::cast) {
 +            // Path is inside a use tree, then only continue if it is the first segment of a use statement.
 +            if use_tree.syntax().parent().and_then(ast::Use::cast).is_none()
 +                || fully_qualified_path.qualifier().is_some()
 +            {
 +                return None;
 +            }
 +        }
 +        Some(Self {
 +            import_candidate: ImportCandidate::for_regular_path(sema, fully_qualified_path)?,
 +            module_with_candidate: sema.scope(&candidate_node)?.module(),
 +            candidate_node,
 +        })
 +    }
 +
 +    pub fn for_ident_pat(sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
 +        if !pat.is_simple_ident() {
 +            return None;
 +        }
 +        let name = pat.name()?;
 +        let candidate_node = pat.syntax().clone();
 +        Some(Self {
 +            import_candidate: ImportCandidate::for_name(sema, &name)?,
 +            module_with_candidate: sema.scope(&candidate_node)?.module(),
 +            candidate_node,
 +        })
 +    }
 +
 +    pub fn for_fuzzy_path(
 +        module_with_candidate: Module,
 +        qualifier: Option<ast::Path>,
 +        fuzzy_name: String,
 +        sema: &Semantics<'_, RootDatabase>,
 +        candidate_node: SyntaxNode,
 +    ) -> Option<Self> {
 +        Some(Self {
 +            import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?,
 +            module_with_candidate,
 +            candidate_node,
 +        })
 +    }
 +
 +    pub fn for_fuzzy_method_call(
 +        module_with_method_call: Module,
 +        receiver_ty: Type,
 +        fuzzy_method_name: String,
 +        candidate_node: SyntaxNode,
 +    ) -> Option<Self> {
 +        Some(Self {
 +            import_candidate: ImportCandidate::TraitMethod(TraitImportCandidate {
 +                receiver_ty,
 +                assoc_item_name: NameToImport::Fuzzy(fuzzy_method_name),
 +            }),
 +            module_with_candidate: module_with_method_call,
 +            candidate_node,
 +        })
 +    }
 +}
 +
 +/// An import (not necessary the only one) that corresponds a certain given [`PathImportCandidate`].
 +/// (the structure is not entirely correct, since there can be situations requiring two imports, see FIXME below for the details)
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LocatedImport {
 +    /// The path to use in the `use` statement for a given candidate to be imported.
 +    pub import_path: ModPath,
 +    /// An item that will be imported with the import path given.
 +    pub item_to_import: ItemInNs,
 +    /// The path import candidate, resolved.
 +    ///
 +    /// Not necessary matches the import:
 +    /// For any associated constant from the trait, we try to access as `some::path::SomeStruct::ASSOC_`
 +    /// the original item is the associated constant, but the import has to be a trait that
 +    /// defines this constant.
 +    pub original_item: ItemInNs,
 +    /// A path of the original item.
 +    pub original_path: Option<ModPath>,
 +}
 +
 +impl LocatedImport {
 +    pub fn new(
 +        import_path: ModPath,
 +        item_to_import: ItemInNs,
 +        original_item: ItemInNs,
 +        original_path: Option<ModPath>,
 +    ) -> Self {
 +        Self { import_path, item_to_import, original_item, original_path }
 +    }
 +}
 +
 +impl ImportAssets {
 +    pub fn import_candidate(&self) -> &ImportCandidate {
 +        &self.import_candidate
 +    }
 +
 +    pub fn search_for_imports(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
 +        prefix_kind: PrefixKind,
++        prefer_no_std: bool,
 +    ) -> Vec<LocatedImport> {
 +        let _p = profile::span("import_assets::search_for_imports");
-         self.search_for(sema, None)
++        self.search_for(sema, Some(prefix_kind), prefer_no_std)
 +    }
 +
 +    /// This may return non-absolute paths if a part of the returned path is already imported into scope.
 +    pub fn search_for_relative_paths(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
++        prefer_no_std: bool,
 +    ) -> Vec<LocatedImport> {
 +        let _p = profile::span("import_assets::search_for_relative_paths");
-         module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind)
++        self.search_for(sema, None, prefer_no_std)
 +    }
 +
 +    pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
 +        if let ImportCandidate::Path(PathImportCandidate { name: to_import, .. }) =
 +            &mut self.import_candidate
 +        {
 +            let name = match to_import {
 +                NameToImport::Fuzzy(name) => std::mem::take(name),
 +                _ => return,
 +            };
 +            *to_import = NameToImport::Exact(name, case_sensitive);
 +        }
 +    }
 +
 +    fn search_for(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
 +        prefixed: Option<PrefixKind>,
++        prefer_no_std: bool,
 +    ) -> Vec<LocatedImport> {
 +        let _p = profile::span("import_assets::search_for");
 +
 +        let scope_definitions = self.scope_definitions(sema);
 +        let mod_path = |item| {
 +            get_mod_path(
 +                sema.db,
 +                item_for_path_search(sema.db, item)?,
 +                &self.module_with_candidate,
 +                prefixed,
++                prefer_no_std,
 +            )
 +        };
 +
 +        let krate = self.module_with_candidate.krate();
 +        let scope = match sema.scope(&self.candidate_node) {
 +            Some(it) => it,
 +            None => return Vec::new(),
 +        };
 +
 +        match &self.import_candidate {
 +            ImportCandidate::Path(path_candidate) => {
 +                path_applicable_imports(sema, krate, path_candidate, mod_path)
 +            }
 +            ImportCandidate::TraitAssocItem(trait_candidate) => {
 +                trait_applicable_items(sema, krate, &scope, trait_candidate, true, mod_path)
 +            }
 +            ImportCandidate::TraitMethod(trait_candidate) => {
 +                trait_applicable_items(sema, krate, &scope, trait_candidate, false, mod_path)
 +            }
 +        }
 +        .into_iter()
 +        .filter(|import| import.import_path.len() > 1)
 +        .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import)))
 +        .sorted_by(|a, b| a.import_path.cmp(&b.import_path))
 +        .collect()
 +    }
 +
 +    fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
 +        let _p = profile::span("import_assets::scope_definitions");
 +        let mut scope_definitions = FxHashSet::default();
 +        if let Some(scope) = sema.scope(&self.candidate_node) {
 +            scope.process_all_names(&mut |_, scope_def| {
 +                scope_definitions.insert(scope_def);
 +            });
 +        }
 +        scope_definitions
 +    }
 +}
 +
 +fn path_applicable_imports(
 +    sema: &Semantics<'_, RootDatabase>,
 +    current_crate: Crate,
 +    path_candidate: &PathImportCandidate,
 +    mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
 +) -> FxHashSet<LocatedImport> {
 +    let _p = profile::span("import_assets::path_applicable_imports");
 +
 +    match &path_candidate.qualifier {
 +        None => {
 +            items_locator::items_with_name(
 +                sema,
 +                current_crate,
 +                path_candidate.name.clone(),
 +                // FIXME: we could look up assoc items by the input and propose those in completion,
 +                // but that requires more preparation first:
 +                // * store non-trait assoc items in import_map to fully enable this lookup
 +                // * ensure that does not degrade the performance (benchmark it)
 +                // * write more logic to check for corresponding trait presence requirement (we're unable to flyimport multiple item right now)
 +                // * improve the associated completion item matching and/or scoring to ensure no noisy completions appear
 +                //
 +                // see also an ignored test under FIXME comment in the qualify_path.rs module
 +                AssocItemSearch::Exclude,
 +                Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +            )
 +            .filter_map(|item| {
 +                let mod_path = mod_path(item)?;
 +                Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
 +            })
 +            .collect()
 +        }
 +        Some(first_segment_unresolved) => {
 +            let unresolved_qualifier =
 +                path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier);
 +            let unresolved_first_segment = first_segment_unresolved.fist_segment.text();
 +            items_locator::items_with_name(
 +                sema,
 +                current_crate,
 +                path_candidate.name.clone(),
 +                AssocItemSearch::Include,
 +                Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +            )
 +            .filter_map(|item| {
 +                import_for_item(
 +                    sema.db,
 +                    mod_path,
 +                    &unresolved_first_segment,
 +                    &unresolved_qualifier,
 +                    item,
 +                )
 +            })
 +            .collect()
 +        }
 +    }
 +}
 +
 +fn import_for_item(
 +    db: &RootDatabase,
 +    mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
 +    unresolved_first_segment: &str,
 +    unresolved_qualifier: &str,
 +    original_item: ItemInNs,
 +) -> Option<LocatedImport> {
 +    let _p = profile::span("import_assets::import_for_item");
 +
 +    let original_item_candidate = item_for_path_search(db, original_item)?;
 +    let import_path_candidate = mod_path(original_item_candidate)?;
 +    let import_path_string = import_path_candidate.to_string();
 +
 +    let expected_import_end = if item_as_assoc(db, original_item).is_some() {
 +        unresolved_qualifier.to_string()
 +    } else {
 +        format!("{}::{}", unresolved_qualifier, item_name(db, original_item)?)
 +    };
 +    if !import_path_string.contains(unresolved_first_segment)
 +        || !import_path_string.ends_with(&expected_import_end)
 +    {
 +        return None;
 +    }
 +
 +    let segment_import =
 +        find_import_for_segment(db, original_item_candidate, unresolved_first_segment)?;
 +    let trait_item_to_import = item_as_assoc(db, original_item)
 +        .and_then(|assoc| assoc.containing_trait(db))
 +        .map(|trait_| ItemInNs::from(ModuleDef::from(trait_)));
 +    Some(match (segment_import == original_item_candidate, trait_item_to_import) {
 +        (true, Some(_)) => {
 +            // FIXME we should be able to import both the trait and the segment,
 +            // but it's unclear what to do with overlapping edits (merge imports?)
 +            // especially in case of lazy completion edit resolutions.
 +            return None;
 +        }
 +        (false, Some(trait_to_import)) => LocatedImport::new(
 +            mod_path(trait_to_import)?,
 +            trait_to_import,
 +            original_item,
 +            mod_path(original_item),
 +        ),
 +        (true, None) => LocatedImport::new(
 +            import_path_candidate,
 +            original_item_candidate,
 +            original_item,
 +            mod_path(original_item),
 +        ),
 +        (false, None) => LocatedImport::new(
 +            mod_path(segment_import)?,
 +            segment_import,
 +            original_item,
 +            mod_path(original_item),
 +        ),
 +    })
 +}
 +
 +pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
 +    Some(match item {
 +        ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
 +            Some(assoc_item) => match assoc_item.container(db) {
 +                AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
 +                AssocItemContainer::Impl(impl_) => {
 +                    ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?))
 +                }
 +            },
 +            None => item,
 +        },
 +        ItemInNs::Macros(_) => item,
 +    })
 +}
 +
 +fn find_import_for_segment(
 +    db: &RootDatabase,
 +    original_item: ItemInNs,
 +    unresolved_first_segment: &str,
 +) -> Option<ItemInNs> {
 +    let segment_is_name = item_name(db, original_item)
 +        .map(|name| name.to_smol_str() == unresolved_first_segment)
 +        .unwrap_or(false);
 +
 +    Some(if segment_is_name {
 +        original_item
 +    } else {
 +        let matching_module =
 +            module_with_segment_name(db, unresolved_first_segment, original_item)?;
 +        ItemInNs::from(ModuleDef::from(matching_module))
 +    })
 +}
 +
 +fn module_with_segment_name(
 +    db: &RootDatabase,
 +    segment_name: &str,
 +    candidate: ItemInNs,
 +) -> Option<Module> {
 +    let mut current_module = match candidate {
 +        ItemInNs::Types(module_def_id) => module_def_id.module(db),
 +        ItemInNs::Values(module_def_id) => module_def_id.module(db),
 +        ItemInNs::Macros(macro_def_id) => ModuleDef::from(macro_def_id).module(db),
 +    };
 +    while let Some(module) = current_module {
 +        if let Some(module_name) = module.name(db) {
 +            if module_name.to_smol_str() == segment_name {
 +                return Some(module);
 +            }
 +        }
 +        current_module = module.parent(db);
 +    }
 +    None
 +}
 +
 +fn trait_applicable_items(
 +    sema: &Semantics<'_, RootDatabase>,
 +    current_crate: Crate,
 +    scope: &SemanticsScope<'_>,
 +    trait_candidate: &TraitImportCandidate,
 +    trait_assoc_item: bool,
 +    mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
 +) -> FxHashSet<LocatedImport> {
 +    let _p = profile::span("import_assets::trait_applicable_items");
 +
 +    let db = sema.db;
 +
 +    let inherent_traits = trait_candidate.receiver_ty.applicable_inherent_traits(db);
 +    let env_traits = trait_candidate.receiver_ty.env_traits(db);
 +    let related_traits = inherent_traits.chain(env_traits).collect::<FxHashSet<_>>();
 +
 +    let mut required_assoc_items = FxHashSet::default();
 +    let trait_candidates = items_locator::items_with_name(
 +        sema,
 +        current_crate,
 +        trait_candidate.assoc_item_name.clone(),
 +        AssocItemSearch::AssocItemsOnly,
 +        Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +    )
 +    .filter_map(|input| item_as_assoc(db, input))
 +    .filter_map(|assoc| {
 +        let assoc_item_trait = assoc.containing_trait(db)?;
 +        if related_traits.contains(&assoc_item_trait) {
 +            None
 +        } else {
 +            required_assoc_items.insert(assoc);
 +            Some(assoc_item_trait.into())
 +        }
 +    })
 +    .collect();
 +
 +    let mut located_imports = FxHashSet::default();
 +
 +    if trait_assoc_item {
 +        trait_candidate.receiver_ty.iterate_path_candidates(
 +            db,
 +            scope,
 +            &trait_candidates,
 +            None,
 +            None,
 +            |assoc| {
 +                if required_assoc_items.contains(&assoc) {
 +                    if let AssocItem::Function(f) = assoc {
 +                        if f.self_param(db).is_some() {
 +                            return None;
 +                        }
 +                    }
 +                    let located_trait = assoc.containing_trait(db)?;
 +                    let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
 +                    let original_item = assoc_to_item(assoc);
 +                    located_imports.insert(LocatedImport::new(
 +                        mod_path(trait_item)?,
 +                        trait_item,
 +                        original_item,
 +                        mod_path(original_item),
 +                    ));
 +                }
 +                None::<()>
 +            },
 +        )
 +    } else {
 +        trait_candidate.receiver_ty.iterate_method_candidates(
 +            db,
 +            scope,
 +            &trait_candidates,
 +            None,
 +            None,
 +            |function| {
 +                let assoc = function.as_assoc_item(db)?;
 +                if required_assoc_items.contains(&assoc) {
 +                    let located_trait = assoc.containing_trait(db)?;
 +                    let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
 +                    let original_item = assoc_to_item(assoc);
 +                    located_imports.insert(LocatedImport::new(
 +                        mod_path(trait_item)?,
 +                        trait_item,
 +                        original_item,
 +                        mod_path(original_item),
 +                    ));
 +                }
 +                None::<()>
 +            },
 +        )
 +    };
 +
 +    located_imports
 +}
 +
 +fn assoc_to_item(assoc: AssocItem) -> ItemInNs {
 +    match assoc {
 +        AssocItem::Function(f) => ItemInNs::from(ModuleDef::from(f)),
 +        AssocItem::Const(c) => ItemInNs::from(ModuleDef::from(c)),
 +        AssocItem::TypeAlias(t) => ItemInNs::from(ModuleDef::from(t)),
 +    }
 +}
 +
 +fn get_mod_path(
 +    db: &RootDatabase,
 +    item_to_search: ItemInNs,
 +    module_with_candidate: &Module,
 +    prefixed: Option<PrefixKind>,
++    prefer_no_std: bool,
 +) -> Option<ModPath> {
 +    if let Some(prefix_kind) = prefixed {
-         module_with_candidate.find_use_path(db, item_to_search)
++        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_no_std)
 +    } else {
++        module_with_candidate.find_use_path(db, item_to_search, prefer_no_std)
 +    }
 +}
 +
 +impl ImportCandidate {
 +    fn for_method_call(
 +        sema: &Semantics<'_, RootDatabase>,
 +        method_call: &ast::MethodCallExpr,
 +    ) -> Option<Self> {
 +        match sema.resolve_method_call(method_call) {
 +            Some(_) => None,
 +            None => Some(Self::TraitMethod(TraitImportCandidate {
 +                receiver_ty: sema.type_of_expr(&method_call.receiver()?)?.adjusted(),
 +                assoc_item_name: NameToImport::exact_case_sensitive(
 +                    method_call.name_ref()?.to_string(),
 +                ),
 +            })),
 +        }
 +    }
 +
 +    fn for_regular_path(sema: &Semantics<'_, RootDatabase>, path: &ast::Path) -> Option<Self> {
 +        if sema.resolve_path(path).is_some() {
 +            return None;
 +        }
 +        path_import_candidate(
 +            sema,
 +            path.qualifier(),
 +            NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()),
 +        )
 +    }
 +
 +    fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<Self> {
 +        if sema
 +            .scope(name.syntax())?
 +            .speculative_resolve(&ast::make::ext::ident_path(&name.text()))
 +            .is_some()
 +        {
 +            return None;
 +        }
 +        Some(ImportCandidate::Path(PathImportCandidate {
 +            qualifier: None,
 +            name: NameToImport::exact_case_sensitive(name.to_string()),
 +        }))
 +    }
 +
 +    fn for_fuzzy_path(
 +        qualifier: Option<ast::Path>,
 +        fuzzy_name: String,
 +        sema: &Semantics<'_, RootDatabase>,
 +    ) -> Option<Self> {
 +        path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name))
 +    }
 +}
 +
 +fn path_import_candidate(
 +    sema: &Semantics<'_, RootDatabase>,
 +    qualifier: Option<ast::Path>,
 +    name: NameToImport,
 +) -> Option<ImportCandidate> {
 +    Some(match qualifier {
 +        Some(qualifier) => match sema.resolve_path(&qualifier) {
 +            None => {
 +                let qualifier_start =
 +                    qualifier.syntax().descendants().find_map(ast::NameRef::cast)?;
 +                let qualifier_start_path =
 +                    qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?;
 +                if sema.resolve_path(&qualifier_start_path).is_none() {
 +                    ImportCandidate::Path(PathImportCandidate {
 +                        qualifier: Some(FirstSegmentUnresolved {
 +                            fist_segment: qualifier_start,
 +                            full_qualifier: qualifier,
 +                        }),
 +                        name,
 +                    })
 +                } else {
 +                    return None;
 +                }
 +            }
 +            Some(PathResolution::Def(ModuleDef::Adt(assoc_item_path))) => {
 +                ImportCandidate::TraitAssocItem(TraitImportCandidate {
 +                    receiver_ty: assoc_item_path.ty(sema.db),
 +                    assoc_item_name: name,
 +                })
 +            }
 +            Some(PathResolution::Def(ModuleDef::TypeAlias(alias))) => {
 +                let ty = alias.ty(sema.db);
 +                if ty.as_adt().is_some() {
 +                    ImportCandidate::TraitAssocItem(TraitImportCandidate {
 +                        receiver_ty: ty,
 +                        assoc_item_name: name,
 +                    })
 +                } else {
 +                    return None;
 +                }
 +            }
 +            Some(_) => return None,
 +        },
 +        None => ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
 +    })
 +}
 +
 +fn item_as_assoc(db: &RootDatabase, item: ItemInNs) -> Option<AssocItem> {
 +    item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
 +}
index 1ec62a8425a39b3fcb5f1fb6287047e7cf1b4002,0000000000000000000000000000000000000000..e0bc0f89f0a1d14bdd54d384802ae8587311e41d
mode 100644,000000..100644
--- /dev/null
@@@ -1,247 -1,0 +1,248 @@@
 +//! This crate defines the core datastructure representing IDE state -- `RootDatabase`.
 +//!
 +//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod apply_change;
 +
 +pub mod active_parameter;
 +pub mod assists;
 +pub mod defs;
 +pub mod famous_defs;
 +pub mod helpers;
 +pub mod items_locator;
 +pub mod label;
 +pub mod line_index;
 +pub mod path_transform;
 +pub mod rename;
 +pub mod rust_doc;
 +pub mod search;
 +pub mod source_change;
 +pub mod symbol_index;
 +pub mod traits;
 +pub mod ty_filter;
 +pub mod use_trivial_contructor;
 +
 +pub mod imports {
 +    pub mod import_assets;
 +    pub mod insert_use;
 +    pub mod merge_imports;
 +}
 +
 +pub mod generated {
 +    pub mod lints;
 +}
 +
 +pub mod syntax_helpers {
 +    pub mod node_ext;
 +    pub mod insert_whitespace_into_node;
 +    pub mod format_string;
++    pub mod format_string_exprs;
 +
 +    pub use parser::LexedStr;
 +}
 +
 +use std::{fmt, mem::ManuallyDrop, sync::Arc};
 +
 +use base_db::{
 +    salsa::{self, Durability},
 +    AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
 +};
 +use hir::{
 +    db::{AstDatabase, DefDatabase, HirDatabase},
 +    symbols::FileSymbolKind,
 +};
 +use stdx::hash::NoHashHashSet;
 +
 +use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 +pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
 +
 +/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
 +pub use base_db;
 +
 +pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
 +pub type FxIndexMap<K, V> =
 +    indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
 +
 +#[salsa::database(
 +    base_db::SourceDatabaseExtStorage,
 +    base_db::SourceDatabaseStorage,
 +    hir::db::AstDatabaseStorage,
 +    hir::db::DefDatabaseStorage,
 +    hir::db::HirDatabaseStorage,
 +    hir::db::InternDatabaseStorage,
 +    LineIndexDatabaseStorage,
 +    symbol_index::SymbolsDatabaseStorage
 +)]
 +pub struct RootDatabase {
 +    // We use `ManuallyDrop` here because every codegen unit that contains a
 +    // `&RootDatabase -> &dyn OtherDatabase` cast will instantiate its drop glue in the vtable,
 +    // which duplicates `Weak::drop` and `Arc::drop` tens of thousands of times, which makes
 +    // compile times of all `ide_*` and downstream crates suffer greatly.
 +    storage: ManuallyDrop<salsa::Storage<RootDatabase>>,
 +}
 +
 +impl Drop for RootDatabase {
 +    fn drop(&mut self) {
 +        unsafe { ManuallyDrop::drop(&mut self.storage) };
 +    }
 +}
 +
 +impl fmt::Debug for RootDatabase {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_struct("RootDatabase").finish()
 +    }
 +}
 +
 +impl Upcast<dyn AstDatabase> for RootDatabase {
 +    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
 +        &*self
 +    }
 +}
 +
 +impl Upcast<dyn DefDatabase> for RootDatabase {
 +    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
 +        &*self
 +    }
 +}
 +
 +impl Upcast<dyn HirDatabase> for RootDatabase {
 +    fn upcast(&self) -> &(dyn HirDatabase + 'static) {
 +        &*self
 +    }
 +}
 +
 +impl FileLoader for RootDatabase {
 +    fn file_text(&self, file_id: FileId) -> Arc<String> {
 +        FileLoaderDelegate(self).file_text(file_id)
 +    }
 +    fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
 +        FileLoaderDelegate(self).resolve_path(path)
 +    }
 +    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
 +        FileLoaderDelegate(self).relevant_crates(file_id)
 +    }
 +}
 +
 +impl salsa::Database for RootDatabase {}
 +
 +impl Default for RootDatabase {
 +    fn default() -> RootDatabase {
 +        RootDatabase::new(None)
 +    }
 +}
 +
 +impl RootDatabase {
 +    pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
 +        let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) };
 +        db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
 +        db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
 +        db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
 +        db.set_enable_proc_attr_macros(false);
 +        db.update_lru_capacity(lru_capacity);
 +        db
 +    }
 +
 +    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
 +        let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
 +        base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
 +        hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
 +        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
 +    }
 +}
 +
 +impl salsa::ParallelDatabase for RootDatabase {
 +    fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
 +        salsa::Snapshot::new(RootDatabase { storage: ManuallyDrop::new(self.storage.snapshot()) })
 +    }
 +}
 +
 +#[salsa::query_group(LineIndexDatabaseStorage)]
 +pub trait LineIndexDatabase: base_db::SourceDatabase {
 +    fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 +}
 +
 +fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
 +    let text = db.file_text(file_id);
 +    Arc::new(LineIndex::new(&*text))
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum SymbolKind {
 +    Attribute,
 +    BuiltinAttr,
 +    Const,
 +    ConstParam,
 +    Derive,
 +    DeriveHelper,
 +    Enum,
 +    Field,
 +    Function,
 +    Impl,
 +    Label,
 +    LifetimeParam,
 +    Local,
 +    Macro,
 +    Module,
 +    SelfParam,
 +    SelfType,
 +    Static,
 +    Struct,
 +    ToolModule,
 +    Trait,
 +    TypeAlias,
 +    TypeParam,
 +    Union,
 +    ValueParam,
 +    Variant,
 +}
 +
 +impl From<hir::MacroKind> for SymbolKind {
 +    fn from(it: hir::MacroKind) -> Self {
 +        match it {
 +            hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::ProcMacro => {
 +                SymbolKind::Macro
 +            }
 +            hir::MacroKind::Derive => SymbolKind::Derive,
 +            hir::MacroKind::Attr => SymbolKind::Attribute,
 +        }
 +    }
 +}
 +
 +impl From<FileSymbolKind> for SymbolKind {
 +    fn from(it: FileSymbolKind) -> Self {
 +        match it {
 +            FileSymbolKind::Const => SymbolKind::Const,
 +            FileSymbolKind::Enum => SymbolKind::Enum,
 +            FileSymbolKind::Function => SymbolKind::Function,
 +            FileSymbolKind::Macro => SymbolKind::Macro,
 +            FileSymbolKind::Module => SymbolKind::Module,
 +            FileSymbolKind::Static => SymbolKind::Static,
 +            FileSymbolKind::Struct => SymbolKind::Struct,
 +            FileSymbolKind::Trait => SymbolKind::Trait,
 +            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
 +            FileSymbolKind::Union => SymbolKind::Union,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 +pub struct SnippetCap {
 +    _private: (),
 +}
 +
 +impl SnippetCap {
 +    pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
 +        if allow_snippets {
 +            Some(SnippetCap { _private: () })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    mod sourcegen_lints;
 +}
index 40af9e6fe2ad80f04042810ab5bc500548bc60b4,0000000000000000000000000000000000000000..12d873b4a0aa8be0c067f697cb7823375e7ce625
mode 100644,000000..100644
--- /dev/null
@@@ -1,287 -1,0 +1,288 @@@
-                     self.target_module.find_use_path(self.source_scope.db.upcast(), def)?;
 +//! See [`PathTransform`].
 +
 +use crate::helpers::mod_path_to_ast;
 +use either::Either;
 +use hir::{AsAssocItem, HirDisplay, SemanticsScope};
 +use rustc_hash::FxHashMap;
 +use syntax::{
 +    ast::{self, AstNode},
 +    ted, SyntaxNode,
 +};
 +
 +/// `PathTransform` substitutes path in SyntaxNodes in bulk.
 +///
 +/// This is mostly useful for IDE code generation. If you paste some existing
 +/// code into a new context (for example, to add method overrides to an `impl`
 +/// block), you generally want to appropriately qualify the names, and sometimes
 +/// you might want to substitute generic parameters as well:
 +///
 +/// ```
 +/// mod x {
 +///   pub struct A<V>;
 +///   pub trait T<U> { fn foo(&self, _: U) -> A<U>; }
 +/// }
 +///
 +/// mod y {
 +///   use x::T;
 +///
 +///   impl T<()> for () {
 +///      // If we invoke **Add Missing Members** here, we want to copy-paste `foo`.
 +///      // But we want a slightly-modified version of it:
 +///      fn foo(&self, _: ()) -> x::A<()> {}
 +///   }
 +/// }
 +/// ```
 +pub struct PathTransform<'a> {
 +    generic_def: hir::GenericDef,
 +    substs: Vec<ast::Type>,
 +    target_scope: &'a SemanticsScope<'a>,
 +    source_scope: &'a SemanticsScope<'a>,
 +}
 +
 +impl<'a> PathTransform<'a> {
 +    pub fn trait_impl(
 +        target_scope: &'a SemanticsScope<'a>,
 +        source_scope: &'a SemanticsScope<'a>,
 +        trait_: hir::Trait,
 +        impl_: ast::Impl,
 +    ) -> PathTransform<'a> {
 +        PathTransform {
 +            source_scope,
 +            target_scope,
 +            generic_def: trait_.into(),
 +            substs: get_syntactic_substs(impl_).unwrap_or_default(),
 +        }
 +    }
 +
 +    pub fn function_call(
 +        target_scope: &'a SemanticsScope<'a>,
 +        source_scope: &'a SemanticsScope<'a>,
 +        function: hir::Function,
 +        generic_arg_list: ast::GenericArgList,
 +    ) -> PathTransform<'a> {
 +        PathTransform {
 +            source_scope,
 +            target_scope,
 +            generic_def: function.into(),
 +            substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
 +        }
 +    }
 +
 +    pub fn apply(&self, syntax: &SyntaxNode) {
 +        self.build_ctx().apply(syntax)
 +    }
 +
 +    fn build_ctx(&self) -> Ctx<'a> {
 +        let db = self.source_scope.db;
 +        let target_module = self.target_scope.module();
 +        let source_module = self.source_scope.module();
 +        let skip = match self.generic_def {
 +            // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
 +            hir::GenericDef::Trait(_) => 1,
 +            _ => 0,
 +        };
 +        let substs_by_param: FxHashMap<_, _> = self
 +            .generic_def
 +            .type_params(db)
 +            .into_iter()
 +            .skip(skip)
 +            // The actual list of trait type parameters may be longer than the one
 +            // used in the `impl` block due to trailing default type parameters.
 +            // For that case we extend the `substs` with an empty iterator so we
 +            // can still hit those trailing values and check if they actually have
 +            // a default type. If they do, go for that type from `hir` to `ast` so
 +            // the resulting change can be applied correctly.
 +            .zip(self.substs.iter().map(Some).chain(std::iter::repeat(None)))
 +            .filter_map(|(k, v)| match k.split(db) {
 +                Either::Left(_) => None,
 +                Either::Right(t) => match v {
 +                    Some(v) => Some((k, v.clone())),
 +                    None => {
 +                        let default = t.default(db)?;
 +                        Some((
 +                            k,
 +                            ast::make::ty(
 +                                &default.display_source_code(db, source_module.into()).ok()?,
 +                            ),
 +                        ))
 +                    }
 +                },
 +            })
 +            .collect();
 +        Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope }
 +    }
 +}
 +
 +struct Ctx<'a> {
 +    substs: FxHashMap<hir::TypeOrConstParam, ast::Type>,
 +    target_module: hir::Module,
 +    source_scope: &'a SemanticsScope<'a>,
 +}
 +
 +impl<'a> Ctx<'a> {
 +    fn apply(&self, item: &SyntaxNode) {
 +        // `transform_path` may update a node's parent and that would break the
 +        // tree traversal. Thus all paths in the tree are collected into a vec
 +        // so that such operation is safe.
 +        let paths = item
 +            .preorder()
 +            .filter_map(|event| match event {
 +                syntax::WalkEvent::Enter(_) => None,
 +                syntax::WalkEvent::Leave(node) => Some(node),
 +            })
 +            .filter_map(ast::Path::cast)
 +            .collect::<Vec<_>>();
 +
 +        for path in paths {
 +            self.transform_path(path);
 +        }
 +    }
 +    fn transform_path(&self, path: ast::Path) -> Option<()> {
 +        if path.qualifier().is_some() {
 +            return None;
 +        }
 +        if path.segment().map_or(false, |s| {
 +            s.param_list().is_some() || (s.self_token().is_some() && path.parent_path().is_none())
 +        }) {
 +            // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway
 +            // don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing
 +            return None;
 +        }
 +
 +        let resolution = self.source_scope.speculative_resolve(&path)?;
 +
 +        match resolution {
 +            hir::PathResolution::TypeParam(tp) => {
 +                if let Some(subst) = self.substs.get(&tp.merge()) {
 +                    let parent = path.syntax().parent()?;
 +                    if let Some(parent) = ast::Path::cast(parent.clone()) {
 +                        // Path inside path means that there is an associated
 +                        // type/constant on the type parameter. It is necessary
 +                        // to fully qualify the type with `as Trait`. Even
 +                        // though it might be unnecessary if `subst` is generic
 +                        // type, always fully qualifying the path is safer
 +                        // because of potential clash of associated types from
 +                        // multiple traits
 +
 +                        let trait_ref = find_trait_for_assoc_item(
 +                            self.source_scope,
 +                            tp,
 +                            parent.segment()?.name_ref()?,
 +                        )
 +                        .and_then(|trait_ref| {
 +                            let found_path = self.target_module.find_use_path(
 +                                self.source_scope.db.upcast(),
 +                                hir::ModuleDef::Trait(trait_ref),
++                                false,
 +                            )?;
 +                            match ast::make::ty_path(mod_path_to_ast(&found_path)) {
 +                                ast::Type::PathType(path_ty) => Some(path_ty),
 +                                _ => None,
 +                            }
 +                        });
 +
 +                        let segment = ast::make::path_segment_ty(subst.clone(), trait_ref);
 +                        let qualified =
 +                            ast::make::path_from_segments(std::iter::once(segment), false);
 +                        ted::replace(path.syntax(), qualified.clone_for_update().syntax());
 +                    } else if let Some(path_ty) = ast::PathType::cast(parent) {
 +                        ted::replace(
 +                            path_ty.syntax(),
 +                            subst.clone_subtree().clone_for_update().syntax(),
 +                        );
 +                    } else {
 +                        ted::replace(
 +                            path.syntax(),
 +                            subst.clone_subtree().clone_for_update().syntax(),
 +                        );
 +                    }
 +                }
 +            }
 +            hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => {
 +                if let hir::ModuleDef::Trait(_) = def {
 +                    if matches!(path.segment()?.kind()?, ast::PathSegmentKind::Type { .. }) {
 +                        // `speculative_resolve` resolves segments like `<T as
 +                        // Trait>` into `Trait`, but just the trait name should
 +                        // not be used as the replacement of the original
 +                        // segment.
 +                        return None;
 +                    }
 +                }
 +
 +                let found_path =
++                    self.target_module.find_use_path(self.source_scope.db.upcast(), def, false)?;
 +                let res = mod_path_to_ast(&found_path).clone_for_update();
 +                if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
 +                    if let Some(segment) = res.segment() {
 +                        let old = segment.get_or_create_generic_arg_list();
 +                        ted::replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
 +                    }
 +                }
 +                ted::replace(path.syntax(), res.syntax())
 +            }
 +            hir::PathResolution::Local(_)
 +            | hir::PathResolution::ConstParam(_)
 +            | hir::PathResolution::SelfType(_)
 +            | hir::PathResolution::Def(_)
 +            | hir::PathResolution::BuiltinAttr(_)
 +            | hir::PathResolution::ToolModule(_)
 +            | hir::PathResolution::DeriveHelper(_) => (),
 +        }
 +        Some(())
 +    }
 +}
 +
 +// FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
 +// trait ref, and then go from the types in the substs back to the syntax).
 +fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
 +    let target_trait = impl_def.trait_()?;
 +    let path_type = match target_trait {
 +        ast::Type::PathType(path) => path,
 +        _ => return None,
 +    };
 +    let generic_arg_list = path_type.path()?.segment()?.generic_arg_list()?;
 +
 +    get_type_args_from_arg_list(generic_arg_list)
 +}
 +
 +fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<Vec<ast::Type>> {
 +    let mut result = Vec::new();
 +    for generic_arg in generic_arg_list.generic_args() {
 +        if let ast::GenericArg::TypeArg(type_arg) = generic_arg {
 +            result.push(type_arg.ty()?)
 +        }
 +    }
 +
 +    Some(result)
 +}
 +
 +fn find_trait_for_assoc_item(
 +    scope: &SemanticsScope<'_>,
 +    type_param: hir::TypeParam,
 +    assoc_item: ast::NameRef,
 +) -> Option<hir::Trait> {
 +    let db = scope.db;
 +    let trait_bounds = type_param.trait_bounds(db);
 +
 +    let assoc_item_name = assoc_item.text();
 +
 +    for trait_ in trait_bounds {
 +        let names = trait_.items(db).into_iter().filter_map(|item| match item {
 +            hir::AssocItem::TypeAlias(ta) => Some(ta.name(db)),
 +            hir::AssocItem::Const(cst) => cst.name(db),
 +            _ => None,
 +        });
 +
 +        for name in names {
 +            if assoc_item_name.as_str() == name.as_text()?.as_str() {
 +                // It is fine to return the first match because in case of
 +                // multiple possibilities, the exact trait must be disambiguated
 +                // in the definition of trait being implemented, so this search
 +                // should not be needed.
 +                return Some(trait_);
 +            }
 +        }
 +    }
 +
 +    None
 +}
index 7deffe8e0f637917c2ab05cac45ee069037caf69,0000000000000000000000000000000000000000..7cabdb55e8d284100a4a272f0888029340742bcb
mode 100644,000000..100644
--- /dev/null
@@@ -1,785 -1,0 +1,804 @@@
-         // these can't be closures because rust infers the lifetimes wrong ...
 +//! Implementation of find-usages functionality.
 +//!
 +//! It is based on the standard ide trick: first, we run a fast text search to
 +//! get a super-set of matches. Then, we we confirm each match using precise
 +//! name resolution.
 +
 +use std::{mem, sync::Arc};
 +
 +use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 +use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
++use memchr::memmem::Finder;
 +use once_cell::unsync::Lazy;
++use parser::SyntaxKind;
 +use stdx::hash::NoHashHashMap;
 +use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
 +
 +use crate::{
 +    defs::{Definition, NameClass, NameRefClass},
 +    traits::{as_trait_assoc_def, convert_to_def_in_trait},
 +    RootDatabase,
 +};
 +
 +#[derive(Debug, Default, Clone)]
 +pub struct UsageSearchResult {
 +    pub references: NoHashHashMap<FileId, Vec<FileReference>>,
 +}
 +
 +impl UsageSearchResult {
 +    pub fn is_empty(&self) -> bool {
 +        self.references.is_empty()
 +    }
 +
 +    pub fn len(&self) -> usize {
 +        self.references.len()
 +    }
 +
 +    pub fn iter(&self) -> impl Iterator<Item = (&FileId, &[FileReference])> + '_ {
 +        self.references.iter().map(|(file_id, refs)| (file_id, &**refs))
 +    }
 +
 +    pub fn file_ranges(&self) -> impl Iterator<Item = FileRange> + '_ {
 +        self.references.iter().flat_map(|(&file_id, refs)| {
 +            refs.iter().map(move |&FileReference { range, .. }| FileRange { file_id, range })
 +        })
 +    }
 +}
 +
 +impl IntoIterator for UsageSearchResult {
 +    type Item = (FileId, Vec<FileReference>);
 +    type IntoIter = <NoHashHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
 +
 +    fn into_iter(self) -> Self::IntoIter {
 +        self.references.into_iter()
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct FileReference {
 +    /// The range of the reference in the original file
 +    pub range: TextRange,
 +    /// The node of the reference in the (macro-)file
 +    pub name: ast::NameLike,
 +    pub category: Option<ReferenceCategory>,
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum ReferenceCategory {
 +    // FIXME: Add this variant and delete the `retain_adt_literal_usages` function.
 +    // Create
 +    Write,
 +    Read,
++    Import,
 +    // FIXME: Some day should be able to search in doc comments. Would probably
 +    // need to switch from enum to bitflags then?
 +    // DocComment
 +}
 +
 +/// Generally, `search_scope` returns files that might contain references for the element.
 +/// For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates.
 +/// In some cases, the location of the references is known to within a `TextRange`,
 +/// e.g. for things like local variables.
 +#[derive(Clone, Debug)]
 +pub struct SearchScope {
 +    entries: NoHashHashMap<FileId, Option<TextRange>>,
 +}
 +
 +impl SearchScope {
 +    fn new(entries: NoHashHashMap<FileId, Option<TextRange>>) -> SearchScope {
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning the entire crate graph of files.
 +    fn crate_graph(db: &RootDatabase) -> SearchScope {
 +        let mut entries = NoHashHashMap::default();
 +
 +        let graph = db.crate_graph();
 +        for krate in graph.iter() {
 +            let root_file = graph[krate].root_file_id;
 +            let source_root_id = db.file_source_root(root_file);
 +            let source_root = db.source_root(source_root_id);
 +            entries.extend(source_root.iter().map(|id| (id, None)));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning all the reverse dependencies of the given crate.
 +    fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
 +        let mut entries = NoHashHashMap::default();
 +        for rev_dep in of.transitive_reverse_dependencies(db) {
 +            let root_file = rev_dep.root_file(db);
 +            let source_root_id = db.file_source_root(root_file);
 +            let source_root = db.source_root(source_root_id);
 +            entries.extend(source_root.iter().map(|id| (id, None)));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning the given crate.
 +    fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
 +        let root_file = of.root_file(db);
 +        let source_root_id = db.file_source_root(root_file);
 +        let source_root = db.source_root(source_root_id);
 +        SearchScope { entries: source_root.iter().map(|id| (id, None)).collect() }
 +    }
 +
 +    /// Build a search scope spanning the given module and all its submodules.
 +    fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
 +        let mut entries = NoHashHashMap::default();
 +
 +        let (file_id, range) = {
 +            let InFile { file_id, value } = module.definition_source(db);
 +            if let Some((file_id, call_source)) = file_id.original_call_node(db) {
 +                (file_id, Some(call_source.text_range()))
 +            } else {
 +                (
 +                    file_id.original_file(db),
 +                    match value {
 +                        ModuleSource::SourceFile(_) => None,
 +                        ModuleSource::Module(it) => Some(it.syntax().text_range()),
 +                        ModuleSource::BlockExpr(it) => Some(it.syntax().text_range()),
 +                    },
 +                )
 +            }
 +        };
 +        entries.insert(file_id, range);
 +
 +        let mut to_visit: Vec<_> = module.children(db).collect();
 +        while let Some(module) = to_visit.pop() {
 +            if let InFile { file_id, value: ModuleSource::SourceFile(_) } =
 +                module.definition_source(db)
 +            {
 +                entries.insert(file_id.original_file(db), None);
 +            }
 +            to_visit.extend(module.children(db));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build an empty search scope.
 +    pub fn empty() -> SearchScope {
 +        SearchScope::new(NoHashHashMap::default())
 +    }
 +
 +    /// Build a empty search scope spanning the given file.
 +    pub fn single_file(file: FileId) -> SearchScope {
 +        SearchScope::new(std::iter::once((file, None)).collect())
 +    }
 +
 +    /// Build a empty search scope spanning the text range of the given file.
 +    pub fn file_range(range: FileRange) -> SearchScope {
 +        SearchScope::new(std::iter::once((range.file_id, Some(range.range))).collect())
 +    }
 +
 +    /// Build a empty search scope spanning the given files.
 +    pub fn files(files: &[FileId]) -> SearchScope {
 +        SearchScope::new(files.iter().map(|f| (*f, None)).collect())
 +    }
 +
 +    pub fn intersection(&self, other: &SearchScope) -> SearchScope {
 +        let (mut small, mut large) = (&self.entries, &other.entries);
 +        if small.len() > large.len() {
 +            mem::swap(&mut small, &mut large)
 +        }
 +
 +        let intersect_ranges =
 +            |r1: Option<TextRange>, r2: Option<TextRange>| -> Option<Option<TextRange>> {
 +                match (r1, r2) {
 +                    (None, r) | (r, None) => Some(r),
 +                    (Some(r1), Some(r2)) => r1.intersect(r2).map(Some),
 +                }
 +            };
 +        let res = small
 +            .iter()
 +            .filter_map(|(&file_id, &r1)| {
 +                let &r2 = large.get(&file_id)?;
 +                let r = intersect_ranges(r1, r2)?;
 +                Some((file_id, r))
 +            })
 +            .collect();
 +
 +        SearchScope::new(res)
 +    }
 +}
 +
 +impl IntoIterator for SearchScope {
 +    type Item = (FileId, Option<TextRange>);
 +    type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>;
 +
 +    fn into_iter(self) -> Self::IntoIter {
 +        self.entries.into_iter()
 +    }
 +}
 +
 +impl Definition {
 +    fn search_scope(&self, db: &RootDatabase) -> SearchScope {
 +        let _p = profile::span("search_scope");
 +
 +        if let Definition::BuiltinType(_) = self {
 +            return SearchScope::crate_graph(db);
 +        }
 +
 +        // def is crate root
 +        // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
 +        if let &Definition::Module(module) = self {
 +            if module.is_crate_root(db) {
 +                return SearchScope::reverse_dependencies(db, module.krate());
 +            }
 +        }
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return SearchScope::empty(),
 +        };
 +        let InFile { file_id, value: module_source } = module.definition_source(db);
 +        let file_id = file_id.original_file(db);
 +
 +        if let Definition::Local(var) = self {
 +            let def = match var.parent(db) {
 +                DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
 +                DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
 +                DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
 +            };
 +            return match def {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::SelfType(impl_) = self {
 +            return match impl_.source(db).map(|src| src.syntax().cloned()) {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
 +            let def = match param.parent(db) {
 +                hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Variant(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()),
 +            };
 +            return match def {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::Macro(macro_def) = self {
 +            return match macro_def.kind(db) {
 +                hir::MacroKind::Declarative => {
 +                    if macro_def.attrs(db).by_key("macro_export").exists() {
 +                        SearchScope::reverse_dependencies(db, module.krate())
 +                    } else {
 +                        SearchScope::krate(db, module.krate())
 +                    }
 +                }
 +                hir::MacroKind::BuiltIn => SearchScope::crate_graph(db),
 +                hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => {
 +                    SearchScope::reverse_dependencies(db, module.krate())
 +                }
 +            };
 +        }
 +
 +        if let Definition::DeriveHelper(_) = self {
 +            return SearchScope::reverse_dependencies(db, module.krate());
 +        }
 +
 +        let vis = self.visibility(db);
 +        if let Some(Visibility::Public) = vis {
 +            return SearchScope::reverse_dependencies(db, module.krate());
 +        }
 +        if let Some(Visibility::Module(module)) = vis {
 +            return SearchScope::module_and_children(db, module.into());
 +        }
 +
 +        let range = match module_source {
 +            ModuleSource::Module(m) => Some(m.syntax().text_range()),
 +            ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
 +            ModuleSource::SourceFile(_) => None,
 +        };
 +        match range {
 +            Some(range) => SearchScope::file_range(FileRange { file_id, range }),
 +            None => SearchScope::single_file(file_id),
 +        }
 +    }
 +
 +    pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
 +        FindUsages {
 +            local_repr: match self {
 +                Definition::Local(local) => Some(local.representative(sema.db)),
 +                _ => None,
 +            },
 +            def: self,
 +            trait_assoc_def: as_trait_assoc_def(sema.db, self),
 +            sema,
 +            scope: None,
 +            include_self_kw_refs: None,
 +            search_self_mod: false,
 +        }
 +    }
 +}
 +
 +#[derive(Clone)]
 +pub struct FindUsages<'a> {
 +    def: Definition,
 +    /// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition
 +    trait_assoc_def: Option<Definition>,
 +    sema: &'a Semantics<'a, RootDatabase>,
 +    scope: Option<SearchScope>,
 +    include_self_kw_refs: Option<hir::Type>,
 +    local_repr: Option<hir::Local>,
 +    search_self_mod: bool,
 +}
 +
 +impl<'a> FindUsages<'a> {
 +    /// Enable searching for `Self` when the definition is a type or `self` for modules.
 +    pub fn include_self_refs(mut self) -> FindUsages<'a> {
 +        self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
 +        self.search_self_mod = true;
 +        self
 +    }
 +
 +    /// Limit the search to a given [`SearchScope`].
 +    pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
 +        self.set_scope(Some(scope))
 +    }
 +
 +    /// Limit the search to a given [`SearchScope`].
 +    pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
 +        assert!(self.scope.is_none());
 +        self.scope = scope;
 +        self
 +    }
 +
 +    pub fn at_least_one(&self) -> bool {
 +        let mut found = false;
 +        self.search(&mut |_, _| {
 +            found = true;
 +            true
 +        });
 +        found
 +    }
 +
 +    pub fn all(self) -> UsageSearchResult {
 +        let mut res = UsageSearchResult::default();
 +        self.search(&mut |file_id, reference| {
 +            res.references.entry(file_id).or_default().push(reference);
 +            false
 +        });
 +        res
 +    }
 +
 +    fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
 +        let _p = profile::span("FindUsages:search");
 +        let sema = self.sema;
 +
 +        let search_scope = {
 +            let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db);
 +            match &self.scope {
 +                None => base,
 +                Some(scope) => base.intersection(scope),
 +            }
 +        };
 +
 +        let name = match self.def {
 +            // special case crate modules as these do not have a proper name
 +            Definition::Module(module) if module.is_crate_root(self.sema.db) => {
 +                // FIXME: This assumes the crate name is always equal to its display name when it really isn't
 +                module
 +                    .krate()
 +                    .display_name(self.sema.db)
 +                    .map(|crate_name| crate_name.crate_name().as_smol_str().clone())
 +            }
 +            _ => {
 +                let self_kw_refs = || {
 +                    self.include_self_kw_refs.as_ref().and_then(|ty| {
 +                        ty.as_adt()
 +                            .map(|adt| adt.name(self.sema.db))
 +                            .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
 +                    })
 +                };
 +                // We need to unescape the name in case it is written without "r#" in earlier
 +                // editions of Rust where it isn't a keyword.
 +                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.unescaped().to_smol_str())
 +            }
 +        };
 +        let name = match &name {
 +            Some(s) => s.as_str(),
 +            None => return,
 +        };
++        let finder = &Finder::new(name);
++        let include_self_kw_refs =
++            self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self")));
 +
-             name: &'a str,
++        // for<'a> |text: &'a str, name: &'a str, search_range: TextRange| -> impl Iterator<Item = TextSize> + 'a { ... }
 +        fn match_indices<'a>(
 +            text: &'a str,
-             text.match_indices(name).filter_map(move |(idx, _)| {
++            finder: &'a Finder<'a>,
 +            search_range: TextRange,
 +        ) -> impl Iterator<Item = TextSize> + 'a {
-             for offset in match_indices(&text, name, search_range) {
++            finder.find_iter(text.as_bytes()).filter_map(move |idx| {
 +                let offset: TextSize = idx.try_into().unwrap();
 +                if !search_range.contains_inclusive(offset) {
 +                    return None;
 +                }
 +                Some(offset)
 +            })
 +        }
 +
++        // for<'a> |scope: &'a SearchScope| -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a { ... }
 +        fn scope_files<'a>(
 +            sema: &'a Semantics<'_, RootDatabase>,
 +            scope: &'a SearchScope,
 +        ) -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a {
 +            scope.entries.iter().map(|(&file_id, &search_range)| {
 +                let text = sema.db.file_text(file_id);
 +                let search_range =
 +                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
 +
 +                (text, file_id, search_range)
 +            })
 +        }
 +
 +        // FIXME: There should be optimization potential here
 +        // Currently we try to descend everything we find which
 +        // means we call `Semantics::descend_into_macros` on
 +        // every textual hit. That function is notoriously
 +        // expensive even for things that do not get down mapped
 +        // into macros.
 +        for (text, file_id, search_range) in scope_files(sema, &search_scope) {
 +            let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 +
 +            // Search for occurrences of the items name
-             if let Some(self_ty) = &self.include_self_kw_refs {
-                 for offset in match_indices(&text, "Self", search_range) {
++            for offset in match_indices(&text, finder, search_range) {
 +                for name in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                    if match name {
 +                        ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
 +                        ast::NameLike::Name(name) => self.found_name(&name, sink),
 +                        ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink),
 +                    } {
 +                        return;
 +                    }
 +                }
 +            }
 +            // Search for occurrences of the `Self` referring to our type
-                 let is_crate_root = module.is_crate_root(self.sema.db);
++            if let Some((self_ty, finder)) = &include_self_kw_refs {
++                for offset in match_indices(&text, finder, search_range) {
 +                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                        if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        // Search for `super` and `crate` resolving to our module
 +        match self.def {
 +            Definition::Module(module) => {
 +                let scope = search_scope
 +                    .intersection(&SearchScope::module_and_children(self.sema.db, module));
 +
-                     for offset in match_indices(&text, "super", search_range) {
++                let is_crate_root =
++                    module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
++                let finder = &Finder::new("super");
 +
 +                for (text, file_id, search_range) in scope_files(sema, &scope) {
 +                    let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 +
-                     if is_crate_root {
-                         for offset in match_indices(&text, "crate", search_range) {
++                    for offset in match_indices(&text, finder, search_range) {
 +                        for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                            if self.found_name_ref(&name_ref, sink) {
 +                                return;
 +                            }
 +                        }
 +                    }
-                 for offset in match_indices(&text, "self", search_range) {
++                    if let Some(finder) = &is_crate_root {
++                        for offset in match_indices(&text, finder, search_range) {
 +                            for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                                if self.found_name_ref(&name_ref, sink) {
 +                                    return;
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +            _ => (),
 +        }
 +
 +        // search for module `self` references in our module's definition source
 +        match self.def {
 +            Definition::Module(module) if self.search_self_mod => {
 +                let src = module.definition_source(sema.db);
 +                let file_id = src.file_id.original_file(sema.db);
 +                let (file_id, search_range) = match src.value {
 +                    ModuleSource::Module(m) => (file_id, Some(m.syntax().text_range())),
 +                    ModuleSource::BlockExpr(b) => (file_id, Some(b.syntax().text_range())),
 +                    ModuleSource::SourceFile(_) => (file_id, None),
 +                };
 +
 +                let search_range = if let Some(&range) = search_scope.entries.get(&file_id) {
 +                    match (range, search_range) {
 +                        (None, range) | (range, None) => range,
 +                        (Some(range), Some(search_range)) => match range.intersect(search_range) {
 +                            Some(range) => Some(range),
 +                            None => return,
 +                        },
 +                    }
 +                } else {
 +                    return;
 +                };
 +
 +                let text = sema.db.file_text(file_id);
 +                let search_range =
 +                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
 +
 +                let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
++                let finder = &Finder::new("self");
 +
-                     category: None,
++                for offset in match_indices(&text, finder, search_range) {
 +                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                        if self.found_self_module_name_ref(&name_ref, sink) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +            _ => {}
 +        }
 +    }
 +
 +    fn found_self_ty_name_ref(
 +        &self,
 +        self_ty: &hir::Type,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(Definition::SelfType(impl_)))
 +                if impl_.self_ty(self.sema.db) == *self_ty =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_self_module_name_ref(
 +        &self,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(def @ Definition::Module(_))) if def == self.def => {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
-             return None;
++                    category: is_name_ref_in_import(name_ref).then(|| ReferenceCategory::Import),
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_lifetime(
 +        &self,
 +        lifetime: &ast::Lifetime,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify_lifetime(self.sema, lifetime) {
 +            Some(NameRefClass::Definition(def)) if def == self.def => {
 +                let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Lifetime(lifetime.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_name_ref(
 +        &self,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(def @ Definition::Local(local)))
 +                if matches!(
 +                    self.local_repr, Some(repr) if repr == local.representative(self.sema.db)
 +                ) =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: ReferenceCategory::new(&def, name_ref),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameRefClass::Definition(def))
 +                if match self.trait_assoc_def {
 +                    Some(trait_assoc_def) => {
 +                        // we have a trait assoc item, so force resolve all assoc items to their trait version
 +                        convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
 +                    }
 +                    None => self.def == def,
 +                } =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: ReferenceCategory::new(&def, name_ref),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameRefClass::Definition(def)) if self.include_self_kw_refs.is_some() => {
 +                if self.include_self_kw_refs == def_to_ty(self.sema, &def) {
 +                    let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                    let reference = FileReference {
 +                        range,
 +                        name: ast::NameLike::NameRef(name_ref.clone()),
 +                        category: ReferenceCategory::new(&def, name_ref),
 +                    };
 +                    sink(file_id, reference)
 +                } else {
 +                    false
 +                }
 +            }
 +            Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
 +                let field = Definition::Field(field);
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let access = match self.def {
 +                    Definition::Field(_) if field == self.def => {
 +                        ReferenceCategory::new(&field, name_ref)
 +                    }
 +                    Definition::Local(_) if matches!(self.local_repr, Some(repr) if repr == local.representative(self.sema.db)) => {
 +                        ReferenceCategory::new(&Definition::Local(local), name_ref)
 +                    }
 +                    _ => return false,
 +                };
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: access,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_name(
 +        &self,
 +        name: &ast::Name,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameClass::classify(self.sema, name) {
 +            Some(NameClass::PatFieldShorthand { local_def: _, field_ref })
 +                if matches!(
 +                    self.def, Definition::Field(_) if Definition::Field(field_ref) == self.def
 +                ) =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    // FIXME: mutable patterns should have `Write` access
 +                    category: Some(ReferenceCategory::Read),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameClass::ConstReference(def)) if self.def == def => {
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameClass::Definition(def @ Definition::Local(local))) if def != self.def => {
 +                if matches!(
 +                    self.local_repr,
 +                    Some(repr) if local.representative(self.sema.db) == repr
 +                ) {
 +                    let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                    let reference = FileReference {
 +                        range,
 +                        name: ast::NameLike::Name(name.clone()),
 +                        category: None,
 +                    };
 +                    return sink(file_id, reference);
 +                }
 +                false
 +            }
 +            Some(NameClass::Definition(def)) if def != self.def => {
 +                // if the def we are looking for is a trait (impl) assoc item, we'll have to resolve the items to trait definition assoc item
 +                if !matches!(
 +                    self.trait_assoc_def,
 +                    Some(trait_assoc_def)
 +                        if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
 +                ) {
 +                    return false;
 +                }
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option<hir::Type> {
 +    match def {
 +        Definition::Adt(adt) => Some(adt.ty(sema.db)),
 +        Definition::TypeAlias(it) => Some(it.ty(sema.db)),
 +        Definition::BuiltinType(it) => Some(it.ty(sema.db)),
 +        Definition::SelfType(it) => Some(it.self_ty(sema.db)),
 +        _ => None,
 +    }
 +}
 +
 +impl ReferenceCategory {
 +    fn new(def: &Definition, r: &ast::NameRef) -> Option<ReferenceCategory> {
 +        // Only Locals and Fields have accesses for now.
 +        if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
++            return is_name_ref_in_import(r).then(|| ReferenceCategory::Import);
 +        }
 +
 +        let mode = r.syntax().ancestors().find_map(|node| {
 +        match_ast! {
 +            match node {
 +                ast::BinExpr(expr) => {
 +                    if matches!(expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
 +                        // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
 +                        // FIXME: This is not terribly accurate.
 +                        if let Some(lhs) = expr.lhs() {
 +                            if lhs.syntax().text_range().end() == r.syntax().text_range().end() {
 +                                return Some(ReferenceCategory::Write);
 +                            }
 +                        }
 +                    }
 +                    Some(ReferenceCategory::Read)
 +                },
 +                _ => None
 +            }
 +        }
 +    });
 +
 +        // Default Locals and Fields to read
 +        mode.or(Some(ReferenceCategory::Read))
 +    }
 +}
++
++fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool {
++    name_ref
++        .syntax()
++        .parent()
++        .and_then(ast::PathSegment::cast)
++        .and_then(|it| it.parent_path().top_path().syntax().parent())
++        .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE)
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac6c6e8feeea01e1b2ef90cc2c664fd0b1bb76fe
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,267 @@@
++//! Tools to work with expressions present in format string literals for the `format_args!` family of macros.
++//! Primarily meant for assists and completions.
++
++/// Enum for represenging extraced format string args.
++/// Can either be extracted expressions (which includes identifiers),
++/// or placeholders `{}`.
++#[derive(Debug, PartialEq, Eq)]
++pub enum Arg {
++    Placeholder,
++    Ident(String),
++    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()])
++ ```
++*/
++
++pub fn with_placeholders(args: Vec<Arg>) -> Vec<String> {
++    let mut placeholder_id = 1;
++    args.into_iter()
++        .map(move |a| match a {
++            Arg::Expr(s) | Arg::Ident(s) => s,
++            Arg::Placeholder => {
++                let s = format!("${placeholder_id}");
++                placeholder_id += 1;
++                s
++            }
++        })
++        .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")]));
++ ```
++*/
++pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
++    #[derive(Debug, Clone, Copy, PartialEq)]
++    enum State {
++        NotArg,
++        MaybeArg,
++        Expr,
++        Ident,
++        MaybeIncorrect,
++        FormatOpts,
++    }
++
++    let mut state = State::NotArg;
++    let mut current_expr = String::new();
++    let mut extracted_expressions = Vec::new();
++    let mut output = String::new();
++
++    // Count of open braces inside of an expression.
++    // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
++    // "{MyStruct { val_a: 0, val_b: 1 }}".
++    let mut inexpr_open_count = 0;
++
++    let mut chars = input.chars().peekable();
++    while let Some(chr) = chars.next() {
++        match (state, chr) {
++            (State::NotArg, '{') => {
++                output.push(chr);
++                state = State::MaybeArg;
++            }
++            (State::NotArg, '}') => {
++                output.push(chr);
++                state = State::MaybeIncorrect;
++            }
++            (State::NotArg, _) => {
++                if matches!(chr, '\\' | '$') {
++                    output.push('\\');
++                }
++                output.push(chr);
++            }
++            (State::MaybeIncorrect, '}') => {
++                // It's okay, we met "}}".
++                output.push(chr);
++                state = State::NotArg;
++            }
++            (State::MaybeIncorrect, _) => {
++                // Error in the string.
++                return Err(());
++            }
++            // Escaped braces `{{`
++            (State::MaybeArg, '{') => {
++                output.push(chr);
++                state = State::NotArg;
++            }
++            (State::MaybeArg, '}') => {
++                // This is an empty sequence '{}'.
++                output.push(chr);
++                extracted_expressions.push(Arg::Placeholder);
++                state = State::NotArg;
++            }
++            (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
++                // this is probably the best we can do to avoid a false positive
++                if chr.is_alphabetic() || chr == '_' {
++                    state = State::Ident;
++                } else {
++                    state = State::Expr;
++                }
++            }
++            (State::Ident | State::Expr, '}') => {
++                if inexpr_open_count == 0 {
++                    output.push(chr);
++
++                    if matches!(state, State::Expr) {
++                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
++                    } else {
++                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
++                    }
++
++                    current_expr = String::new();
++                    state = State::NotArg;
++                } else {
++                    // We're closing one brace met before inside of the expression.
++                    current_expr.push(chr);
++                    inexpr_open_count -= 1;
++                }
++            }
++            (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => {
++                // path separator
++                state = State::Expr;
++                current_expr.push_str("::");
++                chars.next();
++            }
++            (State::Ident | State::Expr, ':') => {
++                if inexpr_open_count == 0 {
++                    // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
++                    output.push(chr);
++
++                    if matches!(state, State::Expr) {
++                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
++                    } else {
++                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
++                    }
++
++                    current_expr = String::new();
++                    state = State::FormatOpts;
++                } else {
++                    // We're inside of braced expression, assume that it's a struct field name/value delimiter.
++                    current_expr.push(chr);
++                }
++            }
++            (State::Ident | State::Expr, '{') => {
++                state = State::Expr;
++                current_expr.push(chr);
++                inexpr_open_count += 1;
++            }
++            (State::Ident | State::Expr, _) => {
++                if !(chr.is_alphanumeric() || chr == '_' || chr == '#') {
++                    state = State::Expr;
++                }
++
++                if matches!(chr, '\\' | '$') {
++                    current_expr.push('\\');
++                }
++                current_expr.push(chr);
++            }
++            (State::FormatOpts, '}') => {
++                output.push(chr);
++                state = State::NotArg;
++            }
++            (State::FormatOpts, _) => {
++                if matches!(chr, '\\' | '$') {
++                    output.push('\\');
++                }
++                output.push(chr);
++            }
++        }
++    }
++
++    if state != State::NotArg {
++        return Err(());
++    }
++
++    Ok((output, extracted_expressions))
++}
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++    use expect_test::{expect, Expect};
++
++    fn check(input: &str, expect: &Expect) {
++        let (output, exprs) = parse_format_exprs(input).unwrap_or(("-".to_string(), vec![]));
++        let outcome_repr = if !exprs.is_empty() {
++            format!("{}; {}", output, with_placeholders(exprs).join(", "))
++        } else {
++            output
++        };
++
++        expect.assert_eq(&outcome_repr);
++    }
++
++    #[test]
++    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"]),
++            ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
++            ("{expr:?}", expect![["{:?}; expr"]]),
++            ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
++            ("{$0}", expect![[r"{}; \$0"]]),
++            ("{malformed", expect![["-"]]),
++            ("malformed}", expect![["-"]]),
++            ("{{correct", expect![["{{correct"]]),
++            ("correct}}", expect![["correct}}"]]),
++            ("{correct}}}", expect![["{}}}; correct"]]),
++            ("{correct}}}}}", expect![["{}}}}}; correct"]]),
++            ("{incorrect}}", expect![["-"]]),
++            ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
++            ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
++            (
++                "{SomeStruct { val_a: 0, val_b: 1 }}",
++                expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
++            ),
++            ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
++            (
++                "{SomeStruct { val_a: 0, val_b: 1 }:?}",
++                expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
++            ),
++            ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
++            ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
++            ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
++            ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
++        ];
++
++        for (input, output) in test_vector {
++            check(input, output)
++        }
++    }
++
++    #[test]
++    fn arg_type() {
++        assert_eq!(
++            parse_format_exprs("{_ident} {r#raw_ident} {expr.obj} {name {thing: 42} } {}")
++                .unwrap()
++                .1,
++            vec![
++                Arg::Ident("_ident".to_owned()),
++                Arg::Ident("r#raw_ident".to_owned()),
++                Arg::Expr("expr.obj".to_owned()),
++                Arg::Expr("name {thing: 42}".to_owned()),
++                Arg::Placeholder
++            ]
++        );
++    }
++}
index a21db5b2cec9d448535f120a1bf244db8bb3301c,0000000000000000000000000000000000000000..3034295196b42a32a26882259e2338facaa52cc6
mode 100644,000000..100644
--- /dev/null
@@@ -1,310 -1,0 +1,312 @@@
 +//! This diagnostic provides an assist for creating a struct definition from a JSON
 +//! example.
 +
 +use hir::{PathResolution, Semantics};
 +use ide_db::{
 +    base_db::FileId,
 +    helpers::mod_path_to_ast,
 +    imports::insert_use::{insert_use, ImportScope},
 +    source_change::SourceChangeBuilder,
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::{format_to, never};
 +use syntax::{
 +    ast::{self, make},
 +    SyntaxKind, SyntaxNode,
 +};
 +use text_edit::TextEdit;
 +
 +use crate::{fix, Diagnostic, DiagnosticsConfig, Severity};
 +
 +#[derive(Default)]
 +struct State {
 +    result: String,
 +    struct_counts: usize,
 +    has_serialize: bool,
 +    has_deserialize: bool,
 +}
 +
 +impl State {
 +    fn generate_new_name(&mut self) -> ast::Name {
 +        self.struct_counts += 1;
 +        make::name(&format!("Struct{}", self.struct_counts))
 +    }
 +
 +    fn serde_derive(&self) -> String {
 +        let mut v = vec![];
 +        if self.has_serialize {
 +            v.push("Serialize");
 +        }
 +        if self.has_deserialize {
 +            v.push("Deserialize");
 +        }
 +        match v.as_slice() {
 +            [] => "".to_string(),
 +            [x] => format!("#[derive({x})]\n"),
 +            [x, y] => format!("#[derive({x}, {y})]\n"),
 +            _ => {
 +                never!();
 +                "".to_string()
 +            }
 +        }
 +    }
 +
 +    fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
 +        let name = self.generate_new_name();
 +        let ty = make::ty(&name.to_string());
 +        let strukt = make::struct_(
 +            None,
 +            name,
 +            None,
 +            make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
 +                |(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
 +            ))
 +            .into(),
 +        );
 +        format_to!(self.result, "{}{}\n", self.serde_derive(), strukt);
 +        ty
 +    }
 +
 +    fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
 +        match value {
 +            serde_json::Value::Null => make::ty_unit(),
 +            serde_json::Value::Bool(_) => make::ty("bool"),
 +            serde_json::Value::Number(it) => make::ty(if it.is_i64() { "i64" } else { "f64" }),
 +            serde_json::Value::String(_) => make::ty("String"),
 +            serde_json::Value::Array(it) => {
 +                let ty = match it.iter().next() {
 +                    Some(x) => self.type_of(x),
 +                    None => make::ty_placeholder(),
 +                };
 +                make::ty(&format!("Vec<{ty}>"))
 +            }
 +            serde_json::Value::Object(x) => self.build_struct(x),
 +        }
 +    }
 +}
 +
 +pub(crate) fn json_in_items(
 +    sema: &Semantics<'_, RootDatabase>,
 +    acc: &mut Vec<Diagnostic>,
 +    file_id: FileId,
 +    node: &SyntaxNode,
 +    config: &DiagnosticsConfig,
 +) {
 +    (|| {
 +        if node.kind() == SyntaxKind::ERROR
 +            && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY)
 +            && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY)
 +        {
 +            let node_string = node.to_string();
 +            if let Ok(it) = serde_json::from_str(&node_string) {
 +                if let serde_json::Value::Object(it) = it {
 +                    let import_scope = ImportScope::find_insert_use_container(node, sema)?;
 +                    let range = node.text_range();
 +                    let mut edit = TextEdit::builder();
 +                    edit.delete(range);
 +                    let mut state = State::default();
 +                    let semantics_scope = sema.scope(node)?;
 +                    let scope_resolve =
 +                        |it| semantics_scope.speculative_resolve(&make::path_from_text(it));
 +                    let scope_has = |it| scope_resolve(it).is_some();
 +                    let deserialize_resolved = scope_resolve("::serde::Deserialize");
 +                    let serialize_resolved = scope_resolve("::serde::Serialize");
 +                    state.has_deserialize = deserialize_resolved.is_some();
 +                    state.has_serialize = serialize_resolved.is_some();
 +                    state.build_struct(&it);
 +                    edit.insert(range.start(), state.result);
 +                    acc.push(
 +                        Diagnostic::new(
 +                            "json-is-not-rust",
 +                            "JSON syntax is not valid as a Rust item",
 +                            range,
 +                        )
 +                        .severity(Severity::WeakWarning)
 +                        .with_fixes(Some(vec![{
 +                            let mut scb = SourceChangeBuilder::new(file_id);
 +                            let scope = match import_scope.clone() {
 +                                ImportScope::File(it) => ImportScope::File(scb.make_mut(it)),
 +                                ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)),
 +                                ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)),
 +                            };
 +                            let current_module = semantics_scope.module();
 +                            if !scope_has("Serialize") {
 +                                if let Some(PathResolution::Def(it)) = serialize_resolved {
 +                                    if let Some(it) = current_module.find_use_path_prefixed(
 +                                        sema.db,
 +                                        it,
 +                                        config.insert_use.prefix_kind,
++                                        config.prefer_no_std,
 +                                    ) {
 +                                        insert_use(
 +                                            &scope,
 +                                            mod_path_to_ast(&it),
 +                                            &config.insert_use,
 +                                        );
 +                                    }
 +                                }
 +                            }
 +                            if !scope_has("Deserialize") {
 +                                if let Some(PathResolution::Def(it)) = deserialize_resolved {
 +                                    if let Some(it) = current_module.find_use_path_prefixed(
 +                                        sema.db,
 +                                        it,
 +                                        config.insert_use.prefix_kind,
++                                        config.prefer_no_std,
 +                                    ) {
 +                                        insert_use(
 +                                            &scope,
 +                                            mod_path_to_ast(&it),
 +                                            &config.insert_use,
 +                                        );
 +                                    }
 +                                }
 +                            }
 +                            let mut sc = scb.finish();
 +                            sc.insert_source_edit(file_id, edit.finish());
 +                            fix("convert_json_to_struct", "Convert JSON to struct", sc, range)
 +                        }])),
 +                    );
 +                }
 +            }
 +        }
 +        Some(())
 +    })();
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::{
 +        tests::{check_diagnostics_with_config, check_fix, check_no_fix},
 +        DiagnosticsConfig,
 +    };
 +
 +    #[test]
 +    fn diagnostic_for_simple_case() {
 +        let mut config = DiagnosticsConfig::test_sample();
 +        config.disabled.insert("syntax-error".to_string());
 +        check_diagnostics_with_config(
 +            config,
 +            r#"
 +            { "foo": "bar" }
 +         // ^^^^^^^^^^^^^^^^ 💡 weak: JSON syntax is not valid as a Rust item
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn types_of_primitives() {
 +        check_fix(
 +            r#"
 +            //- /lib.rs crate:lib deps:serde
 +            use serde::Serialize;
 +
 +            fn some_garbage() {
 +
 +            }
 +
 +            {$0
 +                "foo": "bar",
 +                "bar": 2.3,
 +                "baz": null,
 +                "bay": 57,
 +                "box": true
 +            }
 +            //- /serde.rs crate:serde
 +
 +            pub trait Serialize {
 +                fn serialize() -> u8;
 +            }
 +            "#,
 +            r#"
 +            use serde::Serialize;
 +
 +            fn some_garbage() {
 +
 +            }
 +
 +            #[derive(Serialize)]
 +            struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
 +
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn nested_structs() {
 +        check_fix(
 +            r#"
 +            {$0
 +                "foo": "bar",
 +                "bar": {
 +                    "kind": "Object",
 +                    "value": {}
 +                }
 +            }
 +            "#,
 +            r#"
 +            struct Struct3{  }
 +            struct Struct2{ kind: String, value: Struct3 }
 +            struct Struct1{ bar: Struct2, foo: String }
 +
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn arrays() {
 +        check_fix(
 +            r#"
 +            //- /lib.rs crate:lib deps:serde
 +            {
 +                "of_string": ["foo", "2", "x"], $0
 +                "of_object": [{
 +                    "x": 10,
 +                    "y": 20
 +                }, {
 +                    "x": 10,
 +                    "y": 20
 +                }],
 +                "nested": [[[2]]],
 +                "empty": []
 +            }
 +            //- /serde.rs crate:serde
 +
 +            pub trait Serialize {
 +                fn serialize() -> u8;
 +            }
 +            pub trait Deserialize {
 +                fn deserialize() -> u8;
 +            }
 +            "#,
 +            r#"
 +            use serde::Serialize;
 +            use serde::Deserialize;
 +
 +            #[derive(Serialize, Deserialize)]
 +            struct Struct2{ x: i64, y: i64 }
 +            #[derive(Serialize, Deserialize)]
 +            struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
 +
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_emit_outside_of_item_position() {
 +        check_no_fix(
 +            r#"
 +            fn foo() {
 +                let json = {$0
 +                    "foo": "bar",
 +                    "bar": {
 +                        "kind": "Object",
 +                        "value": {}
 +                    }
 +                };
 +            }
 +            "#,
 +        );
 +    }
 +}
index edb1fc0919c242c9f83dc921a488f5b76813e3a4,0000000000000000000000000000000000000000..7f140eb6a74a6223dbdf26da59289184e1354e75
mode 100644,000000..100644
--- /dev/null
@@@ -1,837 -1,0 +1,838 @@@
 +use either::Either;
 +use hir::{
 +    db::{AstDatabase, HirDatabase},
 +    known, AssocItem, HirDisplay, InFile, Type,
 +};
 +use ide_db::{
 +    assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
 +    source_change::SourceChange, use_trivial_contructor::use_trivial_constructor, FxHashMap,
 +};
 +use stdx::format_to;
 +use syntax::{
 +    algo,
 +    ast::{self, make},
 +    AstNode, SyntaxNode, SyntaxNodePtr,
 +};
 +use text_edit::TextEdit;
 +
 +use crate::{fix, Diagnostic, DiagnosticsContext};
 +
 +// Diagnostic: missing-fields
 +//
 +// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
 +//
 +// Example:
 +//
 +// ```rust
 +// struct A { a: u8, b: u8 }
 +//
 +// let a = A { a: 10 };
 +// ```
 +pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
 +    let mut message = String::from("missing structure fields:\n");
 +    for field in &d.missed_fields {
 +        format_to!(message, "- {}\n", field);
 +    }
 +
 +    let ptr = InFile::new(
 +        d.file,
 +        d.field_list_parent_path
 +            .clone()
 +            .map(SyntaxNodePtr::from)
 +            .unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())),
 +    );
 +
 +    Diagnostic::new("missing-fields", message, ctx.sema.diagnostics_display_range(ptr).range)
 +        .with_fixes(fixes(ctx, d))
 +}
 +
 +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Assist>> {
 +    // Note that although we could add a diagnostics to
 +    // fill the missing tuple field, e.g :
 +    // `struct A(usize);`
 +    // `let a = A { 0: () }`
 +    // but it is uncommon usage and it should not be encouraged.
 +    if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
 +        return None;
 +    }
 +
 +    let root = ctx.sema.db.parse_or_expand(d.file)?;
 +
 +    let current_module = match &d.field_list_parent {
 +        Either::Left(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()),
 +        Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()),
 +    };
 +
 +    let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| {
 +        let edit = {
 +            let mut builder = TextEdit::builder();
 +            if d.file.is_macro() {
 +                // we can't map the diff up into the macro input unfortunately, as the macro loses all
 +                // whitespace information so the diff wouldn't be applicable no matter what
 +                // This has the downside that the cursor will be moved in macros by doing it without a diff
 +                // but that is a trade off we can make.
 +                // FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here
 +                let range = ctx.sema.original_range_opt(old_syntax)?;
 +                builder.replace(range.range, new_syntax.to_string());
 +            } else {
 +                algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder);
 +            }
 +            builder.finish()
 +        };
 +        Some(vec![fix(
 +            "fill_missing_fields",
 +            "Fill struct fields",
 +            SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit),
 +            ctx.sema.original_range(parent_syntax).range,
 +        )])
 +    };
 +
 +    match &d.field_list_parent {
 +        Either::Left(record_expr) => {
 +            let field_list_parent = record_expr.to_node(&root);
 +            let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
 +
 +            let mut locals = FxHashMap::default();
 +            ctx.sema.scope(field_list_parent.syntax())?.process_all_names(&mut |name, def| {
 +                if let hir::ScopeDef::Local(local) = def {
 +                    locals.insert(name, local);
 +                }
 +            });
 +
 +            let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
 +                crate::ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 +                crate::ExprFillDefaultMode::Default => {
 +                    get_default_constructor(ctx, d, ty).unwrap_or_else(|| make::ext::expr_todo())
 +                }
 +            };
 +
 +            let old_field_list = field_list_parent.record_expr_field_list()?;
 +            let new_field_list = old_field_list.clone_for_update();
 +            for (f, ty) in missing_fields.iter() {
 +                let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
 +                    cov_mark::hit!(field_shorthand);
 +                    let candidate_ty = local_candidate.ty(ctx.sema.db);
 +                    if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
 +                        None
 +                    } else {
 +                        Some(generate_fill_expr(ty))
 +                    }
 +                } else {
 +                    let expr = (|| -> Option<ast::Expr> {
 +                        let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
 +
 +                        let type_path = current_module?.find_use_path(
 +                            ctx.sema.db,
 +                            item_for_path_search(ctx.sema.db, item_in_ns)?,
++                            ctx.config.prefer_no_std,
 +                        )?;
 +
 +                        use_trivial_constructor(
 +                            &ctx.sema.db,
 +                            ide_db::helpers::mod_path_to_ast(&type_path),
 +                            &ty,
 +                        )
 +                    })();
 +
 +                    if expr.is_some() {
 +                        expr
 +                    } else {
 +                        Some(generate_fill_expr(ty))
 +                    }
 +                };
 +                let field = make::record_expr_field(
 +                    make::name_ref(&f.name(ctx.sema.db).to_smol_str()),
 +                    field_expr,
 +                );
 +                new_field_list.add_field(field.clone_for_update());
 +            }
 +            build_text_edit(
 +                field_list_parent.syntax(),
 +                new_field_list.syntax(),
 +                old_field_list.syntax(),
 +            )
 +        }
 +        Either::Right(record_pat) => {
 +            let field_list_parent = record_pat.to_node(&root);
 +            let missing_fields = ctx.sema.record_pattern_missing_fields(&field_list_parent);
 +
 +            let old_field_list = field_list_parent.record_pat_field_list()?;
 +            let new_field_list = old_field_list.clone_for_update();
 +            for (f, _) in missing_fields.iter() {
 +                let field = make::record_pat_field_shorthand(make::name_ref(
 +                    &f.name(ctx.sema.db).to_smol_str(),
 +                ));
 +                new_field_list.add_field(field.clone_for_update());
 +            }
 +            build_text_edit(
 +                field_list_parent.syntax(),
 +                new_field_list.syntax(),
 +                old_field_list.syntax(),
 +            )
 +        }
 +    }
 +}
 +
 +fn make_ty(ty: &hir::Type, db: &dyn HirDatabase, module: hir::Module) -> ast::Type {
 +    let ty_str = match ty.as_adt() {
 +        Some(adt) => adt.name(db).to_string(),
 +        None => ty.display_source_code(db, module.into()).ok().unwrap_or_else(|| "_".to_string()),
 +    };
 +
 +    make::ty(&ty_str)
 +}
 +
 +fn get_default_constructor(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::MissingFields,
 +    ty: &Type,
 +) -> Option<ast::Expr> {
 +    if let Some(builtin_ty) = ty.as_builtin() {
 +        if builtin_ty.is_int() || builtin_ty.is_uint() {
 +            return Some(make::ext::zero_number());
 +        }
 +        if builtin_ty.is_float() {
 +            return Some(make::ext::zero_float());
 +        }
 +        if builtin_ty.is_char() {
 +            return Some(make::ext::empty_char());
 +        }
 +        if builtin_ty.is_str() {
 +            return Some(make::ext::empty_str());
 +        }
 +        if builtin_ty.is_bool() {
 +            return Some(make::ext::default_bool());
 +        }
 +    }
 +
 +    let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate();
 +    let module = krate.root_module(ctx.sema.db);
 +
 +    // Look for a ::new() associated function
 +    let has_new_func = ty
 +        .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| {
 +            if let AssocItem::Function(func) = assoc_item {
 +                if func.name(ctx.sema.db) == known::new
 +                    && func.assoc_fn_params(ctx.sema.db).is_empty()
 +                {
 +                    return Some(());
 +                }
 +            }
 +
 +            None
 +        })
 +        .is_some();
 +
 +    let famous_defs = FamousDefs(&ctx.sema, krate);
 +    if has_new_func {
 +        Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module)))
 +    } else if ty.as_adt() == famous_defs.core_option_Option()?.ty(ctx.sema.db).as_adt() {
 +        Some(make::ext::option_none())
 +    } else if !ty.is_array()
 +        && ty.impls_trait(ctx.sema.db, famous_defs.core_default_Default()?, &[])
 +    {
 +        Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module)))
 +    } else {
 +        None
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_diagnostics, check_fix};
 +
 +    #[test]
 +    fn missing_record_pat_field_diagnostic() {
 +        check_diagnostics(
 +            r#"
 +struct S { foo: i32, bar: () }
 +fn baz(s: S) {
 +    let S { foo: _ } = s;
 +      //^ 💡 error: missing structure fields:
 +      //| - bar
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
 +        check_diagnostics(
 +            r"
 +struct S { foo: i32, bar: () }
 +fn baz(s: S) -> i32 {
 +    match s {
 +        S { foo, .. } => foo,
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn missing_record_pat_field_box() {
 +        check_diagnostics(
 +            r"
 +struct S { s: Box<u32> }
 +fn x(a: S) {
 +    let S { box s } = a;
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn missing_record_pat_field_ref() {
 +        check_diagnostics(
 +            r"
 +struct S { s: u32 }
 +fn x(a: S) {
 +    let S { ref s } = a;
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn missing_record_expr_in_assignee_expr() {
 +        check_diagnostics(
 +            r"
 +struct S { s: usize, t: usize }
 +struct S2 { s: S, t: () }
 +struct T(S);
 +fn regular(a: S) {
 +    let s;
 +    S { s, .. } = a;
 +}
 +fn nested(a: S2) {
 +    let s;
 +    S2 { s: S { s, .. }, .. } = a;
 +}
 +fn in_tuple(a: (S,)) {
 +    let s;
 +    (S { s, .. },) = a;
 +}
 +fn in_array(a: [S;1]) {
 +    let s;
 +    [S { s, .. },] = a;
 +}
 +fn in_tuple_struct(a: T) {
 +    let s;
 +    T(S { s, .. }) = a;
 +}
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn range_mapping_out_of_macros() {
 +        check_fix(
 +            r#"
 +fn some() {}
 +fn items() {}
 +fn here() {}
 +
 +macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
 +
 +fn main() {
 +    let _x = id![Foo { a: $042 }];
 +}
 +
 +pub struct Foo { pub a: i32, pub b: i32 }
 +"#,
 +            r#"
 +fn some() {}
 +fn items() {}
 +fn here() {}
 +
 +macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
 +
 +fn main() {
 +    let _x = id![Foo {a:42, b: 0 }];
 +}
 +
 +pub struct Foo { pub a: i32, pub b: i32 }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_empty() {
 +        check_fix(
 +            r#"
 +//- minicore: option
 +struct TestStruct { one: i32, two: i64, three: Option<i32>, four: bool }
 +
 +fn test_fn() {
 +    let s = TestStruct {$0};
 +}
 +"#,
 +            r#"
 +struct TestStruct { one: i32, two: i64, three: Option<i32>, four: bool }
 +
 +fn test_fn() {
 +    let s = TestStruct { one: 0, two: 0, three: None, four: false };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_zst_fields() {
 +        check_fix(
 +            r#"
 +struct Empty;
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct {$0};
 +}
 +"#,
 +            r#"
 +struct Empty;
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct { one: 0, two: Empty };
 +}
 +"#,
 +        );
 +        check_fix(
 +            r#"
 +enum Empty { Foo };
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct {$0};
 +}
 +"#,
 +            r#"
 +enum Empty { Foo };
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct { one: 0, two: Empty::Foo };
 +}
 +"#,
 +        );
 +
 +        // make sure the assist doesn't fill non Unit variants
 +        check_fix(
 +            r#"
 +struct Empty {};
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct {$0};
 +}
 +"#,
 +            r#"
 +struct Empty {};
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct { one: 0, two: todo!() };
 +}
 +"#,
 +        );
 +        check_fix(
 +            r#"
 +enum Empty { Foo {} };
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct {$0};
 +}
 +"#,
 +            r#"
 +enum Empty { Foo {} };
 +
 +struct TestStruct { one: i32, two: Empty }
 +
 +fn test_fn() {
 +    let s = TestStruct { one: 0, two: todo!() };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_self() {
 +        check_fix(
 +            r#"
 +struct TestStruct { one: i32 }
 +
 +impl TestStruct {
 +    fn test_fn() { let s = Self {$0}; }
 +}
 +"#,
 +            r#"
 +struct TestStruct { one: i32 }
 +
 +impl TestStruct {
 +    fn test_fn() { let s = Self { one: 0 }; }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_enum() {
 +        check_fix(
 +            r#"
 +enum Expr {
 +    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
 +}
 +
 +impl Expr {
 +    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
 +        Expr::Bin {$0 }
 +    }
 +}
 +"#,
 +            r#"
 +enum Expr {
 +    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
 +}
 +
 +impl Expr {
 +    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
 +        Expr::Bin { lhs, rhs }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_partial() {
 +        check_fix(
 +            r#"
 +struct TestStruct { one: i32, two: i64 }
 +
 +fn test_fn() {
 +    let s = TestStruct{ two: 2$0 };
 +}
 +"#,
 +            r"
 +struct TestStruct { one: i32, two: i64 }
 +
 +fn test_fn() {
 +    let s = TestStruct{ two: 2, one: 0 };
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_new() {
 +        check_fix(
 +            r#"
 +struct TestWithNew(usize);
 +impl TestWithNew {
 +    pub fn new() -> Self {
 +        Self(0)
 +    }
 +}
 +struct TestStruct { one: i32, two: TestWithNew }
 +
 +fn test_fn() {
 +    let s = TestStruct{ $0 };
 +}
 +"#,
 +            r"
 +struct TestWithNew(usize);
 +impl TestWithNew {
 +    pub fn new() -> Self {
 +        Self(0)
 +    }
 +}
 +struct TestStruct { one: i32, two: TestWithNew }
 +
 +fn test_fn() {
 +    let s = TestStruct{ one: 0, two: TestWithNew::new()  };
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_default() {
 +        check_fix(
 +            r#"
 +//- minicore: default, option
 +struct TestWithDefault(usize);
 +impl Default for TestWithDefault {
 +    pub fn default() -> Self {
 +        Self(0)
 +    }
 +}
 +struct TestStruct { one: i32, two: TestWithDefault }
 +
 +fn test_fn() {
 +    let s = TestStruct{ $0 };
 +}
 +"#,
 +            r"
 +struct TestWithDefault(usize);
 +impl Default for TestWithDefault {
 +    pub fn default() -> Self {
 +        Self(0)
 +    }
 +}
 +struct TestStruct { one: i32, two: TestWithDefault }
 +
 +fn test_fn() {
 +    let s = TestStruct{ one: 0, two: TestWithDefault::default()  };
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_raw_ident() {
 +        check_fix(
 +            r#"
 +struct TestStruct { r#type: u8 }
 +
 +fn test_fn() {
 +    TestStruct { $0 };
 +}
 +"#,
 +            r"
 +struct TestStruct { r#type: u8 }
 +
 +fn test_fn() {
 +    TestStruct { r#type: 0  };
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_no_diagnostic() {
 +        check_diagnostics(
 +            r#"
 +struct TestStruct { one: i32, two: i64 }
 +
 +fn test_fn() {
 +    let one = 1;
 +    let s = TestStruct{ one, two: 2 };
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_no_diagnostic_on_spread() {
 +        check_diagnostics(
 +            r#"
 +struct TestStruct { one: i32, two: i64 }
 +
 +fn test_fn() {
 +    let one = 1;
 +    let s = TestStruct{ ..a };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_blank_line() {
 +        check_fix(
 +            r#"
 +struct S { a: (), b: () }
 +
 +fn f() {
 +    S {
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct S { a: (), b: () }
 +
 +fn f() {
 +    S {
 +        a: todo!(),
 +        b: todo!(),
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_shorthand() {
 +        cov_mark::check!(field_shorthand);
 +        check_fix(
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1i32;
 +    S {
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1i32;
 +    S {
 +        a,
 +        b,
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_shorthand_ty_mismatch() {
 +        check_fix(
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1usize;
 +    S {
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1usize;
 +    S {
 +        a,
 +        b: 0,
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_fields_shorthand_unifies() {
 +        check_fix(
 +            r#"
 +struct S<T> { a: &'static str, b: T }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1i32;
 +    S {
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct S<T> { a: &'static str, b: T }
 +
 +fn f() {
 +    let a = "hello";
 +    let b = 1i32;
 +    S {
 +        a,
 +        b,
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_pat_fields() {
 +        check_fix(
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let S {
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let S {
 +        a,
 +        b,
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fill_struct_pat_fields_partial() {
 +        check_fix(
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let S {
 +        a,$0
 +    };
 +}
 +"#,
 +            r#"
 +struct S { a: &'static str, b: i32 }
 +
 +fn f() {
 +    let S {
 +        a,
 +        b,
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn import_extern_crate_clash_with_inner_item() {
 +        // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
 +
 +        check_diagnostics(
 +            r#"
 +//- /lib.rs crate:lib deps:jwt
 +mod permissions;
 +
 +use permissions::jwt;
 +
 +fn f() {
 +    fn inner() {}
 +    jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
 +}
 +
 +//- /permissions.rs
 +pub mod jwt  {
 +    pub struct Claims {}
 +}
 +
 +//- /jwt/lib.rs crate:jwt
 +pub struct Claims {
 +    field: u8,
 +}
 +        "#,
 +        );
 +    }
 +}
index 6bf90e645b49ae4be4789207762044b05f584264,0000000000000000000000000000000000000000..62c69f90baa4f9f55b1b15bcb827f67883c3f1cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,573 -1,0 +1,598 @@@
-     let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
-     let expr_node = d.expr.value.to_node(&root);
 +use hir::{db::AstDatabase, HirDisplay, Type};
 +use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
 +use syntax::{
 +    ast::{self, BlockExpr, ExprStmt},
 +    AstNode,
 +};
 +use text_edit::TextEdit;
 +
 +use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticsContext};
 +
 +// Diagnostic: type-mismatch
 +//
 +// This diagnostic is triggered when the type of an expression does not match
 +// the expected type.
 +pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
 +    let display_range = adjusted_display_range::<ast::BlockExpr>(
 +        ctx,
 +        d.expr.clone().map(|it| it.into()),
 +        &|block| {
 +            let r_curly_range = block.stmt_list()?.r_curly_token()?.text_range();
 +            cov_mark::hit!(type_mismatch_on_block);
 +            Some(r_curly_range)
 +        },
 +    );
 +
 +    let mut diag = Diagnostic::new(
 +        "type-mismatch",
 +        format!(
 +            "expected {}, found {}",
 +            d.expected.display(ctx.sema.db),
 +            d.actual.display(ctx.sema.db)
 +        ),
 +        display_range,
 +    )
 +    .with_fixes(fixes(ctx, d));
 +    if diag.fixes.is_none() {
 +        diag.experimental = true;
 +    }
 +    diag
 +}
 +
 +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
 +    let mut fixes = Vec::new();
 +
 +    add_reference(ctx, d, &mut fixes);
 +    add_missing_ok_or_some(ctx, d, &mut fixes);
 +    remove_semicolon(ctx, d, &mut fixes);
 +    str_ref_to_owned(ctx, d, &mut fixes);
 +
 +    if fixes.is_empty() {
 +        None
 +    } else {
 +        Some(fixes)
 +    }
 +}
 +
 +fn add_reference(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::TypeMismatch,
 +    acc: &mut Vec<Assist>,
 +) -> Option<()> {
-     let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
 +    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;
 +
 +    let (_, mutability) = d.expected.as_reference()?;
 +    let actual_with_ref = Type::reference(&d.actual, mutability);
 +    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
 +        return None;
 +    }
 +
 +    let ampersands = format!("&{}", mutability.as_keyword_for_ref());
 +
++    let edit = TextEdit::insert(range.start(), ampersands);
 +    let source_change =
 +        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
 +    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
 +    Some(())
 +}
 +
 +fn add_missing_ok_or_some(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::TypeMismatch,
 +    acc: &mut Vec<Assist>,
 +) -> Option<()> {
 +    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
 +    let expr = d.expr.value.to_node(&root);
 +    let expr_range = expr.syntax().text_range();
 +    let scope = ctx.sema.scope(expr.syntax())?;
 +
 +    let expected_adt = d.expected.as_adt()?;
 +    let expected_enum = expected_adt.as_enum()?;
 +
 +    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
 +    let core_result = famous_defs.core_result_Result();
 +    let core_option = famous_defs.core_option_Option();
 +
 +    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
 +        return None;
 +    }
 +
 +    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };
 +
 +    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);
 +
 +    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
 +        return None;
 +    }
 +
 +    let mut builder = TextEdit::builder();
 +    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
 +    builder.insert(expr.syntax().text_range().end(), ")".to_string());
 +    let source_change =
 +        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
 +    let name = format!("Wrap in {}", variant_name);
 +    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
 +    Some(())
 +}
 +
 +fn remove_semicolon(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::TypeMismatch,
 +    acc: &mut Vec<Assist>,
 +) -> Option<()> {
 +    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
 +    let expr = d.expr.value.to_node(&root);
 +    if !d.actual.is_unit() {
 +        return None;
 +    }
 +    let block = BlockExpr::cast(expr.syntax().clone())?;
 +    let expr_before_semi =
 +        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
 +    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
 +    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
 +        return None;
 +    }
 +    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();
 +
 +    let edit = TextEdit::delete(semicolon_range);
 +    let source_change =
 +        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
 +
 +    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
 +    Some(())
 +}
 +
 +fn str_ref_to_owned(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::TypeMismatch,
 +    acc: &mut Vec<Assist>,
 +) -> Option<()> {
 +    let expected = d.expected.display(ctx.sema.db);
 +    let actual = d.actual.display(ctx.sema.db);
 +
 +    if expected.to_string() != "String" || actual.to_string() != "&str" {
 +        return None;
 +    }
 +
 +    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
 +    let expr = d.expr.value.to_node(&root);
 +    let expr_range = expr.syntax().text_range();
 +
 +    let to_owned = format!(".to_owned()");
 +
 +    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned);
 +    let source_change =
 +        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
 +    acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, expr_range));
 +
 +    Some(())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
 +
 +    #[test]
 +    fn missing_reference() {
 +        check_diagnostics(
 +            r#"
 +fn main() {
 +    test(123);
 +       //^^^ 💡 error: expected &i32, found i32
 +}
 +fn test(arg: &i32) {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_reference_to_int() {
 +        check_fix(
 +            r#"
 +fn main() {
 +    test(123$0);
 +}
 +fn test(arg: &i32) {}
 +            "#,
 +            r#"
 +fn main() {
 +    test(&123);
 +}
 +fn test(arg: &i32) {}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_mutable_reference_to_int() {
 +        check_fix(
 +            r#"
 +fn main() {
 +    test($0123);
 +}
 +fn test(arg: &mut i32) {}
 +            "#,
 +            r#"
 +fn main() {
 +    test(&mut 123);
 +}
 +fn test(arg: &mut i32) {}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_reference_to_array() {
 +        check_fix(
 +            r#"
 +//- minicore: coerce_unsized
 +fn main() {
 +    test($0[1, 2, 3]);
 +}
 +fn test(arg: &[i32]) {}
 +            "#,
 +            r#"
 +fn main() {
 +    test(&[1, 2, 3]);
 +}
 +fn test(arg: &[i32]) {}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_reference_with_autoderef() {
 +        check_fix(
 +            r#"
 +//- minicore: coerce_unsized, deref
 +struct Foo;
 +struct Bar;
 +impl core::ops::Deref for Foo {
 +    type Target = Bar;
 +}
 +
 +fn main() {
 +    test($0Foo);
 +}
 +fn test(arg: &Bar) {}
 +            "#,
 +            r#"
 +struct Foo;
 +struct Bar;
 +impl core::ops::Deref for Foo {
 +    type Target = Bar;
 +}
 +
 +fn main() {
 +    test(&Foo);
 +}
 +fn test(arg: &Bar) {}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_reference_to_method_call() {
 +        check_fix(
 +            r#"
 +fn main() {
 +    Test.call_by_ref($0123);
 +}
 +struct Test;
 +impl Test {
 +    fn call_by_ref(&self, arg: &i32) {}
 +}
 +            "#,
 +            r#"
 +fn main() {
 +    Test.call_by_ref(&123);
 +}
 +struct Test;
 +impl Test {
 +    fn call_by_ref(&self, arg: &i32) {}
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_reference_to_let_stmt() {
 +        check_fix(
 +            r#"
 +fn main() {
 +    let test: &i32 = $0123;
 +}
 +            "#,
 +            r#"
 +fn main() {
 +    let test: &i32 = &123;
 +}
 +            "#,
 +        );
 +    }
 +
++    #[test]
++    fn test_add_reference_to_macro_call() {
++        check_fix(
++            r#"
++macro_rules! thousand {
++    () => {
++        1000_u64
++    };
++}
++fn test(foo: &u64) {}
++fn main() {
++    test($0thousand!());
++}
++            "#,
++            r#"
++macro_rules! thousand {
++    () => {
++        1000_u64
++    };
++}
++fn test(foo: &u64) {}
++fn main() {
++    test(&thousand!());
++}
++            "#,
++        );
++    }
++
 +    #[test]
 +    fn test_add_mutable_reference_to_let_stmt() {
 +        check_fix(
 +            r#"
 +fn main() {
 +    let test: &mut i32 = $0123;
 +}
 +            "#,
 +            r#"
 +fn main() {
 +    let test: &mut i32 = &mut 123;
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_option() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +fn div(x: i32, y: i32) -> Option<i32> {
 +    if y == 0 {
 +        return None;
 +    }
 +    x / y$0
 +}
 +"#,
 +            r#"
 +fn div(x: i32, y: i32) -> Option<i32> {
 +    if y == 0 {
 +        return None;
 +    }
 +    Some(x / y)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn const_generic_type_mismatch() {
 +        check_diagnostics(
 +            r#"
 +            pub struct Rate<const N: u32>;
 +            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
 +                loop {}
 +            }
 +            fn run(t: Rate<5>) {
 +            }
 +            fn main() {
 +                run(f()) // FIXME: remove this error
 +                  //^^^ error: expected Rate<5>, found Rate<_>
 +            }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn const_generic_unknown() {
 +        check_diagnostics(
 +            r#"
 +            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
 +            fn run(t: Rate<u32, 1, 1>) {
 +            }
 +            fn main() {
 +                run(Rate::<_, _, _>(5));
 +            }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_option_tails() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +fn div(x: i32, y: i32) -> Option<i32> {
 +    if y == 0 {
 +        Some(0)
 +    } else if true {
 +        100$0
 +    } else {
 +        None
 +    }
 +}
 +"#,
 +            r#"
 +fn div(x: i32, y: i32) -> Option<i32> {
 +    if y == 0 {
 +        Some(0)
 +    } else if true {
 +        Some(100)
 +    } else {
 +        None
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +fn div(x: i32, y: i32) -> Result<i32, ()> {
 +    if y == 0 {
 +        return Err(());
 +    }
 +    x / y$0
 +}
 +"#,
 +            r#"
 +fn div(x: i32, y: i32) -> Result<i32, ()> {
 +    if y == 0 {
 +        return Err(());
 +    }
 +    Ok(x / y)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_handles_generic_functions() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +fn div<T>(x: T) -> Result<T, i32> {
 +    if x == 0 {
 +        return Err(7);
 +    }
 +    $0x
 +}
 +"#,
 +            r#"
 +fn div<T>(x: T) -> Result<T, i32> {
 +    if x == 0 {
 +        return Err(7);
 +    }
 +    Ok(x)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_handles_type_aliases() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +type MyResult<T> = Result<T, ()>;
 +
 +fn div(x: i32, y: i32) -> MyResult<i32> {
 +    if y == 0 {
 +        return Err(());
 +    }
 +    x $0/ y
 +}
 +"#,
 +            r#"
 +type MyResult<T> = Result<T, ()>;
 +
 +fn div(x: i32, y: i32) -> MyResult<i32> {
 +    if y == 0 {
 +        return Err(());
 +    }
 +    Ok(x / y)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_in_const_and_static() {
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +static A: Option<()> = {($0)};
 +            "#,
 +            r#"
 +static A: Option<()> = {Some(())};
 +            "#,
 +        );
 +        check_fix(
 +            r#"
 +//- minicore: option, result
 +const _: Option<()> = {($0)};
 +            "#,
 +            r#"
 +const _: Option<()> = {Some(())};
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
 +        check_no_fix(
 +            r#"
 +//- minicore: option, result
 +fn foo() -> Result<(), i32> { 0$0 }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
 +        check_no_fix(
 +            r#"
 +//- minicore: option, result
 +enum SomeOtherEnum { Ok(i32), Err(String) }
 +
 +fn foo() -> SomeOtherEnum { 0$0 }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn remove_semicolon() {
 +        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
 +    }
 +
 +    #[test]
 +    fn str_ref_to_owned() {
 +        check_fix(
 +            r#"
 +struct String;
 +
 +fn test() -> String {
 +    "a"$0
 +}
 +            "#,
 +            r#"
 +struct String;
 +
 +fn test() -> String {
 +    "a".to_owned()
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn type_mismatch_on_block() {
 +        cov_mark::check!(type_mismatch_on_block);
 +        check_diagnostics(
 +            r#"
 +fn f() -> i32 {
 +    let x = 1;
 +    let y = 2;
 +    let _ = x + y;
 +  }
 +//^ error: expected i32, found ()
 +"#,
 +        );
 +    }
 +}
index 61e63ea7a93ca68b37f19e172d1a2db08ebe537c,0000000000000000000000000000000000000000..ae299f0584148937c64b897e7cf658359a5c7069
mode 100644,000000..100644
--- /dev/null
@@@ -1,289 -1,0 +1,291 @@@
 +//! Diagnostics rendering and fixits.
 +//!
 +//! Most of the diagnostics originate from the dark depth of the compiler, and
 +//! are originally expressed in term of IR. When we emit the diagnostic, we are
 +//! usually not in the position to decide how to best "render" it in terms of
 +//! user-authored source code. We are especially not in the position to offer
 +//! fixits, as the compiler completely lacks the infrastructure to edit the
 +//! source code.
 +//!
 +//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate,
 +//! where we "cook" them so that each diagnostic is formulated in terms of `hir`
 +//! types. Well, at least that's the aspiration, the "cooking" is somewhat
 +//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic
 +//! structs from hir, and we want to render them to unified serializable
 +//! representation (span, level, message) here. If we can, we also provide
 +//! fixits. By the way, that's why we want to keep diagnostics structured
 +//! internally -- so that we have all the info to make fixes.
 +//!
 +//! We have one "handler" module per diagnostic code. Such a module contains
 +//! rendering, optional fixes and tests. It's OK if some low-level compiler
 +//! functionality ends up being tested via a diagnostic.
 +//!
 +//! There are also a couple of ad-hoc diagnostics implemented directly here, we
 +//! don't yet have a great pattern for how to do them properly.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod handlers {
 +    pub(crate) mod break_outside_of_loop;
 +    pub(crate) mod inactive_code;
 +    pub(crate) mod incorrect_case;
 +    pub(crate) mod invalid_derive_target;
 +    pub(crate) mod macro_error;
 +    pub(crate) mod malformed_derive;
 +    pub(crate) mod mismatched_arg_count;
 +    pub(crate) mod missing_fields;
 +    pub(crate) mod missing_match_arms;
 +    pub(crate) mod missing_unsafe;
 +    pub(crate) mod no_such_field;
 +    pub(crate) mod replace_filter_map_next_with_find_map;
 +    pub(crate) mod type_mismatch;
 +    pub(crate) mod unimplemented_builtin_macro;
 +    pub(crate) mod unresolved_extern_crate;
 +    pub(crate) mod unresolved_import;
 +    pub(crate) mod unresolved_macro_call;
 +    pub(crate) mod unresolved_module;
 +    pub(crate) mod unresolved_proc_macro;
 +
 +    // The handlers below are unusual, the implement the diagnostics as well.
 +    pub(crate) mod field_shorthand;
 +    pub(crate) mod useless_braces;
 +    pub(crate) mod unlinked_file;
 +    pub(crate) mod json_is_not_rust;
 +}
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use hir::{diagnostics::AnyDiagnostic, InFile, Semantics};
 +use ide_db::{
 +    assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
 +    base_db::{FileId, FileRange, SourceDatabase},
 +    imports::insert_use::InsertUseConfig,
 +    label::Label,
 +    source_change::SourceChange,
 +    FxHashSet, RootDatabase,
 +};
 +use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange};
 +
 +#[derive(Copy, Clone, Debug, PartialEq)]
 +pub struct DiagnosticCode(pub &'static str);
 +
 +impl DiagnosticCode {
 +    pub fn as_str(&self) -> &str {
 +        self.0
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Diagnostic {
 +    pub code: DiagnosticCode,
 +    pub message: String,
 +    pub range: TextRange,
 +    pub severity: Severity,
 +    pub unused: bool,
 +    pub experimental: bool,
 +    pub fixes: Option<Vec<Assist>>,
 +}
 +
 +impl Diagnostic {
 +    fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
 +        let message = message.into();
 +        Diagnostic {
 +            code: DiagnosticCode(code),
 +            message,
 +            range,
 +            severity: Severity::Error,
 +            unused: false,
 +            experimental: false,
 +            fixes: None,
 +        }
 +    }
 +
 +    fn experimental(mut self) -> Diagnostic {
 +        self.experimental = true;
 +        self
 +    }
 +
 +    fn severity(mut self, severity: Severity) -> Diagnostic {
 +        self.severity = severity;
 +        self
 +    }
 +
 +    fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic {
 +        self.fixes = fixes;
 +        self
 +    }
 +
 +    fn with_unused(mut self, unused: bool) -> Diagnostic {
 +        self.unused = unused;
 +        self
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone)]
 +pub enum Severity {
 +    Error,
 +    // We don't actually emit this one yet, but we should at some point.
 +    // Warning,
 +    WeakWarning,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ExprFillDefaultMode {
 +    Todo,
 +    Default,
 +}
 +impl Default for ExprFillDefaultMode {
 +    fn default() -> Self {
 +        Self::Todo
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct DiagnosticsConfig {
 +    pub proc_macros_enabled: bool,
 +    pub proc_attr_macros_enabled: bool,
 +    pub disable_experimental: bool,
 +    pub disabled: FxHashSet<String>,
 +    pub expr_fill_default: ExprFillDefaultMode,
 +    // FIXME: We may want to include a whole `AssistConfig` here
 +    pub insert_use: InsertUseConfig,
++    pub prefer_no_std: bool,
 +}
 +
 +impl DiagnosticsConfig {
 +    pub fn test_sample() -> Self {
 +        use hir::PrefixKind;
 +        use ide_db::imports::insert_use::ImportGranularity;
 +
 +        Self {
 +            proc_macros_enabled: Default::default(),
 +            proc_attr_macros_enabled: Default::default(),
 +            disable_experimental: Default::default(),
 +            disabled: Default::default(),
 +            expr_fill_default: Default::default(),
 +            insert_use: InsertUseConfig {
 +                granularity: ImportGranularity::Preserve,
 +                enforce_granularity: false,
 +                prefix_kind: PrefixKind::Plain,
 +                group: false,
 +                skip_glob_imports: false,
 +            },
++            prefer_no_std: false,
 +        }
 +    }
 +}
 +
 +struct DiagnosticsContext<'a> {
 +    config: &'a DiagnosticsConfig,
 +    sema: Semantics<'a, RootDatabase>,
 +    resolve: &'a AssistResolveStrategy,
 +}
 +
 +pub fn diagnostics(
 +    db: &RootDatabase,
 +    config: &DiagnosticsConfig,
 +    resolve: &AssistResolveStrategy,
 +    file_id: FileId,
 +) -> Vec<Diagnostic> {
 +    let _p = profile::span("diagnostics");
 +    let sema = Semantics::new(db);
 +    let parse = db.parse(file_id);
 +    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| {
 +            Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range())
 +        }),
 +    );
 +
 +    let parse = sema.parse(file_id);
 +
 +    for node in parse.syntax().descendants() {
 +        handlers::useless_braces::useless_braces(&mut res, file_id, &node);
 +        handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
 +        handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config);
 +    }
 +
 +    let module = sema.to_module_def(file_id);
 +
 +    let ctx = DiagnosticsContext { config, sema, resolve };
 +    if module.is_none() {
 +        handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
 +    }
 +
 +    let mut diags = Vec::new();
 +    if let Some(m) = module {
 +        m.diagnostics(db, &mut diags)
 +    }
 +
 +    for diag in diags {
 +        #[rustfmt::skip]
 +        let d = match diag {
 +            AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
 +            AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
 +            AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
 +            AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
 +            AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
 +            AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
 +            AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
 +            AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
 +            AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
 +            AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
 +            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
 +            AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
 +            AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
 +            AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
 +            AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
 +            AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
 +            AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
 +            AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
 +
 +            AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
 +                Some(it) => it,
 +                None => continue,
 +            }
 +        };
 +        res.push(d)
 +    }
 +
 +    res.retain(|d| {
 +        !ctx.config.disabled.contains(d.code.as_str())
 +            && !(ctx.config.disable_experimental && d.experimental)
 +    });
 +
 +    res
 +}
 +
 +fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
 +    let mut res = unresolved_fix(id, label, target);
 +    res.source_change = Some(source_change);
 +    res
 +}
 +
 +fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
 +    assert!(!id.contains(' '));
 +    Assist {
 +        id: AssistId(id, AssistKind::QuickFix),
 +        label: Label::new(label.to_string()),
 +        group: None,
 +        target,
 +        source_change: None,
 +        trigger_signature_help: false,
 +    }
 +}
 +
 +fn adjusted_display_range<N: AstNode>(
 +    ctx: &DiagnosticsContext<'_>,
 +    diag_ptr: InFile<SyntaxNodePtr>,
 +    adj: &dyn Fn(N) -> Option<TextRange>,
 +) -> TextRange {
 +    let FileRange { file_id, range } = ctx.sema.diagnostics_display_range(diag_ptr);
 +
 +    let source_file = ctx.sema.db.parse(file_id);
 +    find_node_at_range::<N>(&source_file.syntax_node(), range)
 +        .filter(|it| it.syntax().text_range() == range)
 +        .and_then(adj)
 +        .unwrap_or(range)
 +}
index e3a837ddcdb054247fbdc9de581effc1281d2692,0000000000000000000000000000000000000000..57b5ab6abda6936f281eaf5315854261cd4d0e7b
mode 100644,000000..100644
--- /dev/null
@@@ -1,803 -1,0 +1,804 @@@
-                 let mod_path = module.find_use_path(sema.db, module_def).ok_or_else(|| {
-                     match_error!("Failed to render template path `{}` at match location")
-                 })?;
 +//! This module is responsible for matching a search pattern against a node in the AST. In the
 +//! process of matching, placeholder values are recorded.
 +
 +use crate::{
 +    parsing::{Constraint, NodeKind, Placeholder, Var},
 +    resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
 +    SsrMatches,
 +};
 +use hir::Semantics;
 +use ide_db::{base_db::FileRange, FxHashMap};
 +use std::{cell::Cell, iter::Peekable};
 +use syntax::{
 +    ast::{self, AstNode, AstToken},
 +    SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken,
 +};
 +
 +// Creates a match error. If we're currently attempting to match some code that we thought we were
 +// going to match, as indicated by the --debug-snippet flag, then populate the reason field.
 +macro_rules! match_error {
 +    ($e:expr) => {{
 +            MatchFailed {
 +                reason: if recording_match_fail_reasons() {
 +                    Some(format!("{}", $e))
 +                } else {
 +                    None
 +                }
 +            }
 +    }};
 +    ($fmt:expr, $($arg:tt)+) => {{
 +        MatchFailed {
 +            reason: if recording_match_fail_reasons() {
 +                Some(format!($fmt, $($arg)+))
 +            } else {
 +                None
 +            }
 +        }
 +    }};
 +}
 +
 +// Fails the current match attempt, recording the supplied reason if we're recording match fail reasons.
 +macro_rules! fail_match {
 +    ($($args:tt)*) => {return Err(match_error!($($args)*))};
 +}
 +
 +/// Information about a match that was found.
 +#[derive(Debug)]
 +pub struct Match {
 +    pub(crate) range: FileRange,
 +    pub(crate) matched_node: SyntaxNode,
 +    pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>,
 +    pub(crate) ignored_comments: Vec<ast::Comment>,
 +    pub(crate) rule_index: usize,
 +    /// The depth of matched_node.
 +    pub(crate) depth: usize,
 +    // Each path in the template rendered for the module in which the match was found.
 +    pub(crate) rendered_template_paths: FxHashMap<SyntaxNode, hir::ModPath>,
 +}
 +
 +/// Information about a placeholder bound in a match.
 +#[derive(Debug)]
 +pub(crate) struct PlaceholderMatch {
 +    pub(crate) range: FileRange,
 +    /// More matches, found within `node`.
 +    pub(crate) inner_matches: SsrMatches,
 +    /// How many times the code that the placeholder matched needed to be dereferenced. Will only be
 +    /// non-zero if the placeholder matched to the receiver of a method call.
 +    pub(crate) autoderef_count: usize,
 +    pub(crate) autoref_kind: ast::SelfParamKind,
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct MatchFailureReason {
 +    pub(crate) reason: String,
 +}
 +
 +/// An "error" indicating that matching failed. Use the fail_match! macro to create and return this.
 +#[derive(Clone)]
 +pub(crate) struct MatchFailed {
 +    /// The reason why we failed to match. Only present when debug_active true in call to
 +    /// `get_match`.
 +    pub(crate) reason: Option<String>,
 +}
 +
 +/// Checks if `code` matches the search pattern found in `search_scope`, returning information about
 +/// the match, if it does. Since we only do matching in this module and searching is done by the
 +/// parent module, we don't populate nested matches.
 +pub(crate) fn get_match(
 +    debug_active: bool,
 +    rule: &ResolvedRule,
 +    code: &SyntaxNode,
 +    restrict_range: &Option<FileRange>,
 +    sema: &Semantics<'_, ide_db::RootDatabase>,
 +) -> Result<Match, MatchFailed> {
 +    record_match_fails_reasons_scope(debug_active, || {
 +        Matcher::try_match(rule, code, restrict_range, sema)
 +    })
 +}
 +
 +/// Checks if our search pattern matches a particular node of the AST.
 +struct Matcher<'db, 'sema> {
 +    sema: &'sema Semantics<'db, ide_db::RootDatabase>,
 +    /// If any placeholders come from anywhere outside of this range, then the match will be
 +    /// rejected.
 +    restrict_range: Option<FileRange>,
 +    rule: &'sema ResolvedRule,
 +}
 +
 +/// Which phase of matching we're currently performing. We do two phases because most attempted
 +/// matches will fail and it means we can defer more expensive checks to the second phase.
 +enum Phase<'a> {
 +    /// On the first phase, we perform cheap checks. No state is mutated and nothing is recorded.
 +    First,
 +    /// On the second phase, we construct the `Match`. Things like what placeholders bind to is
 +    /// recorded.
 +    Second(&'a mut Match),
 +}
 +
 +impl<'db, 'sema> Matcher<'db, 'sema> {
 +    fn try_match(
 +        rule: &ResolvedRule,
 +        code: &SyntaxNode,
 +        restrict_range: &Option<FileRange>,
 +        sema: &'sema Semantics<'db, ide_db::RootDatabase>,
 +    ) -> Result<Match, MatchFailed> {
 +        let match_state = Matcher { sema, restrict_range: *restrict_range, rule };
 +        // First pass at matching, where we check that node types and idents match.
 +        match_state.attempt_match_node(&mut Phase::First, &rule.pattern.node, code)?;
 +        match_state.validate_range(&sema.original_range(code))?;
 +        let mut the_match = Match {
 +            range: sema.original_range(code),
 +            matched_node: code.clone(),
 +            placeholder_values: FxHashMap::default(),
 +            ignored_comments: Vec::new(),
 +            rule_index: rule.index,
 +            depth: 0,
 +            rendered_template_paths: FxHashMap::default(),
 +        };
 +        // Second matching pass, where we record placeholder matches, ignored comments and maybe do
 +        // any other more expensive checks that we didn't want to do on the first pass.
 +        match_state.attempt_match_node(
 +            &mut Phase::Second(&mut the_match),
 +            &rule.pattern.node,
 +            code,
 +        )?;
 +        the_match.depth = sema.ancestors_with_macros(the_match.matched_node.clone()).count();
 +        if let Some(template) = &rule.template {
 +            the_match.render_template_paths(template, sema)?;
 +        }
 +        Ok(the_match)
 +    }
 +
 +    /// Checks that `range` is within the permitted range if any. This is applicable when we're
 +    /// processing a macro expansion and we want to fail the match if we're working with a node that
 +    /// didn't originate from the token tree of the macro call.
 +    fn validate_range(&self, range: &FileRange) -> Result<(), MatchFailed> {
 +        if let Some(restrict_range) = &self.restrict_range {
 +            if restrict_range.file_id != range.file_id
 +                || !restrict_range.range.contains_range(range.range)
 +            {
 +                fail_match!("Node originated from a macro");
 +            }
 +        }
 +        Ok(())
 +    }
 +
 +    fn attempt_match_node(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &SyntaxNode,
 +        code: &SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        // Handle placeholders.
 +        if let Some(placeholder) = self.get_placeholder_for_node(pattern) {
 +            for constraint in &placeholder.constraints {
 +                self.check_constraint(constraint, code)?;
 +            }
 +            if let Phase::Second(matches_out) = phase {
 +                let original_range = self.sema.original_range(code);
 +                // We validated the range for the node when we started the match, so the placeholder
 +                // probably can't fail range validation, but just to be safe...
 +                self.validate_range(&original_range)?;
 +                matches_out.placeholder_values.insert(
 +                    placeholder.ident.clone(),
 +                    PlaceholderMatch::from_range(original_range),
 +                );
 +            }
 +            return Ok(());
 +        }
 +        // We allow a UFCS call to match a method call, provided they resolve to the same function.
 +        if let Some(pattern_ufcs) = self.rule.pattern.ufcs_function_calls.get(pattern) {
 +            if let Some(code) = ast::MethodCallExpr::cast(code.clone()) {
 +                return self.attempt_match_ufcs_to_method_call(phase, pattern_ufcs, &code);
 +            }
 +            if let Some(code) = ast::CallExpr::cast(code.clone()) {
 +                return self.attempt_match_ufcs_to_ufcs(phase, pattern_ufcs, &code);
 +            }
 +        }
 +        if pattern.kind() != code.kind() {
 +            fail_match!(
 +                "Pattern had `{}` ({:?}), code had `{}` ({:?})",
 +                pattern.text(),
 +                pattern.kind(),
 +                code.text(),
 +                code.kind()
 +            );
 +        }
 +        // Some kinds of nodes have special handling. For everything else, we fall back to default
 +        // matching.
 +        match code.kind() {
 +            SyntaxKind::RECORD_EXPR_FIELD_LIST => {
 +                self.attempt_match_record_field_list(phase, pattern, code)
 +            }
 +            SyntaxKind::TOKEN_TREE => self.attempt_match_token_tree(phase, pattern, code),
 +            SyntaxKind::PATH => self.attempt_match_path(phase, pattern, code),
 +            _ => self.attempt_match_node_children(phase, pattern, code),
 +        }
 +    }
 +
 +    fn attempt_match_node_children(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &SyntaxNode,
 +        code: &SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        self.attempt_match_sequences(
 +            phase,
 +            PatternIterator::new(pattern),
 +            code.children_with_tokens(),
 +        )
 +    }
 +
 +    fn attempt_match_sequences(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern_it: PatternIterator,
 +        mut code_it: SyntaxElementChildren,
 +    ) -> Result<(), MatchFailed> {
 +        let mut pattern_it = pattern_it.peekable();
 +        loop {
 +            match phase.next_non_trivial(&mut code_it) {
 +                None => {
 +                    if let Some(p) = pattern_it.next() {
 +                        fail_match!("Part of the pattern was unmatched: {:?}", p);
 +                    }
 +                    return Ok(());
 +                }
 +                Some(SyntaxElement::Token(c)) => {
 +                    self.attempt_match_token(phase, &mut pattern_it, &c)?;
 +                }
 +                Some(SyntaxElement::Node(c)) => match pattern_it.next() {
 +                    Some(SyntaxElement::Node(p)) => {
 +                        self.attempt_match_node(phase, &p, &c)?;
 +                    }
 +                    Some(p) => fail_match!("Pattern wanted '{}', code has {}", p, c.text()),
 +                    None => fail_match!("Pattern reached end, code has {}", c.text()),
 +                },
 +            }
 +        }
 +    }
 +
 +    fn attempt_match_token(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &mut Peekable<PatternIterator>,
 +        code: &syntax::SyntaxToken,
 +    ) -> Result<(), MatchFailed> {
 +        phase.record_ignored_comments(code);
 +        // Ignore whitespace and comments.
 +        if code.kind().is_trivia() {
 +            return Ok(());
 +        }
 +        if let Some(SyntaxElement::Token(p)) = pattern.peek() {
 +            // If the code has a comma and the pattern is about to close something, then accept the
 +            // comma without advancing the pattern. i.e. ignore trailing commas.
 +            if code.kind() == SyntaxKind::COMMA && is_closing_token(p.kind()) {
 +                return Ok(());
 +            }
 +            // Conversely, if the pattern has a comma and the code doesn't, skip that part of the
 +            // pattern and continue to match the code.
 +            if p.kind() == SyntaxKind::COMMA && is_closing_token(code.kind()) {
 +                pattern.next();
 +            }
 +        }
 +        // Consume an element from the pattern and make sure it matches.
 +        match pattern.next() {
 +            Some(SyntaxElement::Token(p)) => {
 +                if p.kind() != code.kind() || p.text() != code.text() {
 +                    fail_match!(
 +                        "Pattern wanted token '{}' ({:?}), but code had token '{}' ({:?})",
 +                        p.text(),
 +                        p.kind(),
 +                        code.text(),
 +                        code.kind()
 +                    )
 +                }
 +            }
 +            Some(SyntaxElement::Node(p)) => {
 +                // Not sure if this is actually reachable.
 +                fail_match!(
 +                    "Pattern wanted {:?}, but code had token '{}' ({:?})",
 +                    p,
 +                    code.text(),
 +                    code.kind()
 +                );
 +            }
 +            None => {
 +                fail_match!("Pattern exhausted, while code remains: `{}`", code.text());
 +            }
 +        }
 +        Ok(())
 +    }
 +
 +    fn check_constraint(
 +        &self,
 +        constraint: &Constraint,
 +        code: &SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        match constraint {
 +            Constraint::Kind(kind) => {
 +                kind.matches(code)?;
 +            }
 +            Constraint::Not(sub) => {
 +                if self.check_constraint(&*sub, code).is_ok() {
 +                    fail_match!("Constraint {:?} failed for '{}'", constraint, code.text());
 +                }
 +            }
 +        }
 +        Ok(())
 +    }
 +
 +    /// Paths are matched based on whether they refer to the same thing, even if they're written
 +    /// differently.
 +    fn attempt_match_path(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &SyntaxNode,
 +        code: &SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        if let Some(pattern_resolved) = self.rule.pattern.resolved_paths.get(pattern) {
 +            let pattern_path = ast::Path::cast(pattern.clone()).unwrap();
 +            let code_path = ast::Path::cast(code.clone()).unwrap();
 +            if let (Some(pattern_segment), Some(code_segment)) =
 +                (pattern_path.segment(), code_path.segment())
 +            {
 +                // Match everything within the segment except for the name-ref, which is handled
 +                // separately via comparing what the path resolves to below.
 +                self.attempt_match_opt(
 +                    phase,
 +                    pattern_segment.generic_arg_list(),
 +                    code_segment.generic_arg_list(),
 +                )?;
 +                self.attempt_match_opt(
 +                    phase,
 +                    pattern_segment.param_list(),
 +                    code_segment.param_list(),
 +                )?;
 +            }
 +            if matches!(phase, Phase::Second(_)) {
 +                let resolution = self
 +                    .sema
 +                    .resolve_path(&code_path)
 +                    .ok_or_else(|| match_error!("Failed to resolve path `{}`", code.text()))?;
 +                if pattern_resolved.resolution != resolution {
 +                    fail_match!("Pattern had path `{}` code had `{}`", pattern.text(), code.text());
 +                }
 +            }
 +        } else {
 +            return self.attempt_match_node_children(phase, pattern, code);
 +        }
 +        Ok(())
 +    }
 +
 +    fn attempt_match_opt<T: AstNode>(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: Option<T>,
 +        code: Option<T>,
 +    ) -> Result<(), MatchFailed> {
 +        match (pattern, code) {
 +            (Some(p), Some(c)) => self.attempt_match_node(phase, p.syntax(), c.syntax()),
 +            (None, None) => Ok(()),
 +            (Some(p), None) => fail_match!("Pattern `{}` had nothing to match", p.syntax().text()),
 +            (None, Some(c)) => {
 +                fail_match!("Nothing in pattern to match code `{}`", c.syntax().text())
 +            }
 +        }
 +    }
 +
 +    /// We want to allow the records to match in any order, so we have special matching logic for
 +    /// them.
 +    fn attempt_match_record_field_list(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &SyntaxNode,
 +        code: &SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        // Build a map keyed by field name.
 +        let mut fields_by_name: FxHashMap<SmolStr, SyntaxNode> = FxHashMap::default();
 +        for child in code.children() {
 +            if let Some(record) = ast::RecordExprField::cast(child.clone()) {
 +                if let Some(name) = record.field_name() {
 +                    fields_by_name.insert(name.text().into(), child.clone());
 +                }
 +            }
 +        }
 +        for p in pattern.children_with_tokens() {
 +            if let SyntaxElement::Node(p) = p {
 +                if let Some(name_element) = p.first_child_or_token() {
 +                    if self.get_placeholder(&name_element).is_some() {
 +                        // If the pattern is using placeholders for field names then order
 +                        // independence doesn't make sense. Fall back to regular ordered
 +                        // matching.
 +                        return self.attempt_match_node_children(phase, pattern, code);
 +                    }
 +                    if let Some(ident) = only_ident(name_element) {
 +                        let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| {
 +                            match_error!(
 +                                "Placeholder has record field '{}', but code doesn't",
 +                                ident
 +                            )
 +                        })?;
 +                        self.attempt_match_node(phase, &p, &code_record)?;
 +                    }
 +                }
 +            }
 +        }
 +        if let Some(unmatched_fields) = fields_by_name.keys().next() {
 +            fail_match!(
 +                "{} field(s) of a record literal failed to match, starting with {}",
 +                fields_by_name.len(),
 +                unmatched_fields
 +            );
 +        }
 +        Ok(())
 +    }
 +
 +    /// Outside of token trees, a placeholder can only match a single AST node, whereas in a token
 +    /// tree it can match a sequence of tokens. Note, that this code will only be used when the
 +    /// pattern matches the macro invocation. For matches within the macro call, we'll already have
 +    /// expanded the macro.
 +    fn attempt_match_token_tree(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern: &SyntaxNode,
 +        code: &syntax::SyntaxNode,
 +    ) -> Result<(), MatchFailed> {
 +        let mut pattern = PatternIterator::new(pattern).peekable();
 +        let mut children = code.children_with_tokens();
 +        while let Some(child) = children.next() {
 +            if let Some(placeholder) = pattern.peek().and_then(|p| self.get_placeholder(p)) {
 +                pattern.next();
 +                let next_pattern_token = pattern
 +                    .peek()
 +                    .and_then(|p| match p {
 +                        SyntaxElement::Token(t) => Some(t.clone()),
 +                        SyntaxElement::Node(n) => n.first_token(),
 +                    })
 +                    .map(|p| p.text().to_string());
 +                let first_matched_token = child.clone();
 +                let mut last_matched_token = child;
 +                // Read code tokens util we reach one equal to the next token from our pattern
 +                // or we reach the end of the token tree.
 +                for next in &mut children {
 +                    match &next {
 +                        SyntaxElement::Token(t) => {
 +                            if Some(t.to_string()) == next_pattern_token {
 +                                pattern.next();
 +                                break;
 +                            }
 +                        }
 +                        SyntaxElement::Node(n) => {
 +                            if let Some(first_token) = n.first_token() {
 +                                if Some(first_token.text()) == next_pattern_token.as_deref() {
 +                                    if let Some(SyntaxElement::Node(p)) = pattern.next() {
 +                                        // We have a subtree that starts with the next token in our pattern.
 +                                        self.attempt_match_token_tree(phase, &p, n)?;
 +                                        break;
 +                                    }
 +                                }
 +                            }
 +                        }
 +                    };
 +                    last_matched_token = next;
 +                }
 +                if let Phase::Second(match_out) = phase {
 +                    match_out.placeholder_values.insert(
 +                        placeholder.ident.clone(),
 +                        PlaceholderMatch::from_range(FileRange {
 +                            file_id: self.sema.original_range(code).file_id,
 +                            range: first_matched_token
 +                                .text_range()
 +                                .cover(last_matched_token.text_range()),
 +                        }),
 +                    );
 +                }
 +                continue;
 +            }
 +            // Match literal (non-placeholder) tokens.
 +            match child {
 +                SyntaxElement::Token(token) => {
 +                    self.attempt_match_token(phase, &mut pattern, &token)?;
 +                }
 +                SyntaxElement::Node(node) => match pattern.next() {
 +                    Some(SyntaxElement::Node(p)) => {
 +                        self.attempt_match_token_tree(phase, &p, &node)?;
 +                    }
 +                    Some(SyntaxElement::Token(p)) => fail_match!(
 +                        "Pattern has token '{}', code has subtree '{}'",
 +                        p.text(),
 +                        node.text()
 +                    ),
 +                    None => fail_match!("Pattern has nothing, code has '{}'", node.text()),
 +                },
 +            }
 +        }
 +        if let Some(p) = pattern.next() {
 +            fail_match!("Reached end of token tree in code, but pattern still has {:?}", p);
 +        }
 +        Ok(())
 +    }
 +
 +    fn attempt_match_ufcs_to_method_call(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern_ufcs: &UfcsCallInfo,
 +        code: &ast::MethodCallExpr,
 +    ) -> Result<(), MatchFailed> {
 +        use ast::HasArgList;
 +        let code_resolved_function = self
 +            .sema
 +            .resolve_method_call(code)
 +            .ok_or_else(|| match_error!("Failed to resolve method call"))?;
 +        if pattern_ufcs.function != code_resolved_function {
 +            fail_match!("Method call resolved to a different function");
 +        }
 +        // Check arguments.
 +        let mut pattern_args = pattern_ufcs
 +            .call_expr
 +            .arg_list()
 +            .ok_or_else(|| match_error!("Pattern function call has no args"))?
 +            .args();
 +        // If the function we're calling takes a self parameter, then we store additional
 +        // information on the placeholder match about autoderef and autoref. This allows us to use
 +        // the placeholder in a context where autoderef and autoref don't apply.
 +        if code_resolved_function.self_param(self.sema.db).is_some() {
 +            if let (Some(pattern_type), Some(expr)) =
 +                (&pattern_ufcs.qualifier_type, &code.receiver())
 +            {
 +                let deref_count = self.check_expr_type(pattern_type, expr)?;
 +                let pattern_receiver = pattern_args.next();
 +                self.attempt_match_opt(phase, pattern_receiver.clone(), code.receiver())?;
 +                if let Phase::Second(match_out) = phase {
 +                    if let Some(placeholder_value) = pattern_receiver
 +                        .and_then(|n| self.get_placeholder_for_node(n.syntax()))
 +                        .and_then(|placeholder| {
 +                            match_out.placeholder_values.get_mut(&placeholder.ident)
 +                        })
 +                    {
 +                        placeholder_value.autoderef_count = deref_count;
 +                        placeholder_value.autoref_kind = self
 +                            .sema
 +                            .resolve_method_call_as_callable(code)
 +                            .and_then(|callable| callable.receiver_param(self.sema.db))
 +                            .map(|self_param| self_param.kind())
 +                            .unwrap_or(ast::SelfParamKind::Owned);
 +                    }
 +                }
 +            }
 +        } else {
 +            self.attempt_match_opt(phase, pattern_args.next(), code.receiver())?;
 +        }
 +        let mut code_args =
 +            code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args();
 +        loop {
 +            match (pattern_args.next(), code_args.next()) {
 +                (None, None) => return Ok(()),
 +                (p, c) => self.attempt_match_opt(phase, p, c)?,
 +            }
 +        }
 +    }
 +
 +    fn attempt_match_ufcs_to_ufcs(
 +        &self,
 +        phase: &mut Phase<'_>,
 +        pattern_ufcs: &UfcsCallInfo,
 +        code: &ast::CallExpr,
 +    ) -> Result<(), MatchFailed> {
 +        use ast::HasArgList;
 +        // Check that the first argument is the expected type.
 +        if let (Some(pattern_type), Some(expr)) = (
 +            &pattern_ufcs.qualifier_type,
 +            &code.arg_list().and_then(|code_args| code_args.args().next()),
 +        ) {
 +            self.check_expr_type(pattern_type, expr)?;
 +        }
 +        self.attempt_match_node_children(phase, pattern_ufcs.call_expr.syntax(), code.syntax())
 +    }
 +
 +    /// Verifies that `expr` matches `pattern_type`, possibly after dereferencing some number of
 +    /// times. Returns the number of times it needed to be dereferenced.
 +    fn check_expr_type(
 +        &self,
 +        pattern_type: &hir::Type,
 +        expr: &ast::Expr,
 +    ) -> Result<usize, MatchFailed> {
 +        use hir::HirDisplay;
 +        let code_type = self
 +            .sema
 +            .type_of_expr(expr)
 +            .ok_or_else(|| {
 +                match_error!("Failed to get receiver type for `{}`", expr.syntax().text())
 +            })?
 +            .original;
 +        // Temporary needed to make the borrow checker happy.
 +        let res = code_type
 +            .autoderef(self.sema.db)
 +            .enumerate()
 +            .find(|(_, deref_code_type)| pattern_type == deref_code_type)
 +            .map(|(count, _)| count)
 +            .ok_or_else(|| {
 +                match_error!(
 +                    "Pattern type `{}` didn't match code type `{}`",
 +                    pattern_type.display(self.sema.db),
 +                    code_type.display(self.sema.db)
 +                )
 +            });
 +        res
 +    }
 +
 +    fn get_placeholder_for_node(&self, node: &SyntaxNode) -> Option<&Placeholder> {
 +        self.get_placeholder(&SyntaxElement::Node(node.clone()))
 +    }
 +
 +    fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> {
 +        only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident))
 +    }
 +}
 +
 +impl Match {
 +    fn render_template_paths(
 +        &mut self,
 +        template: &ResolvedPattern,
 +        sema: &Semantics<'_, ide_db::RootDatabase>,
 +    ) -> Result<(), MatchFailed> {
 +        let module = sema
 +            .scope(&self.matched_node)
 +            .ok_or_else(|| match_error!("Matched node isn't in a module"))?
 +            .module();
 +        for (path, resolved_path) in &template.resolved_paths {
 +            if let hir::PathResolution::Def(module_def) = resolved_path.resolution {
++                let mod_path =
++                    module.find_use_path(sema.db, module_def, false).ok_or_else(|| {
++                        match_error!("Failed to render template path `{}` at match location")
++                    })?;
 +                self.rendered_template_paths.insert(path.clone(), mod_path);
 +            }
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl Phase<'_> {
 +    fn next_non_trivial(&mut self, code_it: &mut SyntaxElementChildren) -> Option<SyntaxElement> {
 +        loop {
 +            let c = code_it.next();
 +            if let Some(SyntaxElement::Token(t)) = &c {
 +                self.record_ignored_comments(t);
 +                if t.kind().is_trivia() {
 +                    continue;
 +                }
 +            }
 +            return c;
 +        }
 +    }
 +
 +    fn record_ignored_comments(&mut self, token: &SyntaxToken) {
 +        if token.kind() == SyntaxKind::COMMENT {
 +            if let Phase::Second(match_out) = self {
 +                if let Some(comment) = ast::Comment::cast(token.clone()) {
 +                    match_out.ignored_comments.push(comment);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn is_closing_token(kind: SyntaxKind) -> bool {
 +    kind == SyntaxKind::R_PAREN || kind == SyntaxKind::R_CURLY || kind == SyntaxKind::R_BRACK
 +}
 +
 +pub(crate) fn record_match_fails_reasons_scope<F, T>(debug_active: bool, f: F) -> T
 +where
 +    F: Fn() -> T,
 +{
 +    RECORDING_MATCH_FAIL_REASONS.with(|c| c.set(debug_active));
 +    let res = f();
 +    RECORDING_MATCH_FAIL_REASONS.with(|c| c.set(false));
 +    res
 +}
 +
 +// For performance reasons, we don't want to record the reason why every match fails, only the bit
 +// of code that the user indicated they thought would match. We use a thread local to indicate when
 +// we are trying to match that bit of code. This saves us having to pass a boolean into all the bits
 +// of code that can make the decision to not match.
 +thread_local! {
 +    pub static RECORDING_MATCH_FAIL_REASONS: Cell<bool> = Cell::new(false);
 +}
 +
 +fn recording_match_fail_reasons() -> bool {
 +    RECORDING_MATCH_FAIL_REASONS.with(|c| c.get())
 +}
 +
 +impl PlaceholderMatch {
 +    fn from_range(range: FileRange) -> Self {
 +        Self {
 +            range,
 +            inner_matches: SsrMatches::default(),
 +            autoderef_count: 0,
 +            autoref_kind: ast::SelfParamKind::Owned,
 +        }
 +    }
 +}
 +
 +impl NodeKind {
 +    fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> {
 +        let ok = match self {
 +            Self::Literal => {
 +                cov_mark::hit!(literal_constraint);
 +                ast::Literal::can_cast(node.kind())
 +            }
 +        };
 +        if !ok {
 +            fail_match!("Code '{}' isn't of kind {:?}", node.text(), self);
 +        }
 +        Ok(())
 +    }
 +}
 +
 +// If `node` contains nothing but an ident then return it, otherwise return None.
 +fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> {
 +    match element {
 +        SyntaxElement::Token(t) => {
 +            if t.kind() == SyntaxKind::IDENT {
 +                return Some(t);
 +            }
 +        }
 +        SyntaxElement::Node(n) => {
 +            let mut children = n.children_with_tokens();
 +            if let (Some(only_child), None) = (children.next(), children.next()) {
 +                return only_ident(only_child);
 +            }
 +        }
 +    }
 +    None
 +}
 +
 +struct PatternIterator {
 +    iter: SyntaxElementChildren,
 +}
 +
 +impl Iterator for PatternIterator {
 +    type Item = SyntaxElement;
 +
 +    fn next(&mut self) -> Option<SyntaxElement> {
 +        for element in &mut self.iter {
 +            if !element.kind().is_trivia() {
 +                return Some(element);
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +impl PatternIterator {
 +    fn new(parent: &SyntaxNode) -> Self {
 +        Self { iter: parent.children_with_tokens() }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::{MatchFinder, SsrRule};
 +
 +    #[test]
 +    fn parse_match_replace() {
 +        let rule: SsrRule = "foo($x) ==>> bar($x)".parse().unwrap();
 +        let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }";
 +
 +        let (db, position, selections) = crate::tests::single_file(input);
 +        let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
 +        match_finder.add_rule(rule).unwrap();
 +        let matches = match_finder.matches();
 +        assert_eq!(matches.matches.len(), 1);
 +        assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)");
 +        assert_eq!(matches.matches[0].placeholder_values.len(), 1);
 +
 +        let edits = match_finder.edits();
 +        assert_eq!(edits.len(), 1);
 +        let edit = &edits[&position.file_id];
 +        let mut after = input.to_string();
 +        edit.apply(&mut after);
 +        assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }");
 +    }
 +}
index 210c5c7facd2de1a42ad6ccbffadb6181e15abd2,0000000000000000000000000000000000000000..bfbe0db6e4b84f3c579a376cd9ca40faa2cade2c
mode 100644,000000..100644
--- /dev/null
@@@ -1,789 -1,0 +1,846 @@@
-                 konst.source(db).and_then(|node| name_range(db, node, file_id))
 +use hir::{HasSource, InFile, Semantics};
 +use ide_db::{
 +    base_db::{FileId, FilePosition, FileRange},
 +    defs::Definition,
 +    helpers::visit_file_defs,
 +    RootDatabase,
 +};
 +use syntax::{ast::HasName, AstNode, TextRange};
 +
 +use crate::{
 +    fn_references::find_all_methods,
 +    goto_implementation::goto_implementation,
 +    references::find_all_refs,
 +    runnables::{runnables, Runnable},
 +    NavigationTarget, RunnableKind,
 +};
 +
 +// Feature: Annotations
 +//
 +// Provides user with annotations above items for looking up references or impl blocks
 +// and running/debugging binaries.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[]
 +#[derive(Debug)]
 +pub struct Annotation {
 +    pub range: TextRange,
 +    pub kind: AnnotationKind,
 +}
 +
 +#[derive(Debug)]
 +pub enum AnnotationKind {
 +    Runnable(Runnable),
 +    HasImpls { file_id: FileId, data: Option<Vec<NavigationTarget>> },
 +    HasReferences { file_id: FileId, data: Option<Vec<FileRange>> },
 +}
 +
 +pub struct AnnotationConfig {
 +    pub binary_target: bool,
 +    pub annotate_runnables: bool,
 +    pub annotate_impls: bool,
 +    pub annotate_references: bool,
 +    pub annotate_method_references: bool,
 +    pub annotate_enum_variant_references: bool,
++    pub location: AnnotationLocation,
++}
++
++pub enum AnnotationLocation {
++    AboveName,
++    AboveWholeItem,
 +}
 +
 +pub(crate) fn annotations(
 +    db: &RootDatabase,
 +    config: &AnnotationConfig,
 +    file_id: FileId,
 +) -> Vec<Annotation> {
 +    let mut annotations = Vec::default();
 +
 +    if config.annotate_runnables {
 +        for runnable in runnables(db, file_id) {
 +            if should_skip_runnable(&runnable.kind, config.binary_target) {
 +                continue;
 +            }
 +
 +            let range = runnable.nav.focus_or_full_range();
 +
 +            annotations.push(Annotation { range, kind: AnnotationKind::Runnable(runnable) });
 +        }
 +    }
 +
 +    visit_file_defs(&Semantics::new(db), file_id, &mut |def| {
 +        let range = match def {
 +            Definition::Const(konst) if config.annotate_references => {
-                 trait_.source(db).and_then(|node| name_range(db, node, file_id))
++                konst.source(db).and_then(|node| name_range(db, config, node, file_id))
 +            }
 +            Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => {
-                                 variant.source(db).and_then(|node| name_range(db, node, file_id))
++                trait_.source(db).and_then(|node| name_range(db, config, node, file_id))
 +            }
 +            Definition::Adt(adt) => match adt {
 +                hir::Adt::Enum(enum_) => {
 +                    if config.annotate_enum_variant_references {
 +                        enum_
 +                            .variants(db)
 +                            .into_iter()
 +                            .map(|variant| {
-                         enum_.source(db).and_then(|node| name_range(db, node, file_id))
++                                variant
++                                    .source(db)
++                                    .and_then(|node| name_range(db, config, node, file_id))
 +                            })
 +                            .flatten()
 +                            .for_each(|range| {
 +                                annotations.push(Annotation {
 +                                    range,
 +                                    kind: AnnotationKind::HasReferences { file_id, data: None },
 +                                })
 +                            })
 +                    }
 +                    if config.annotate_references || config.annotate_impls {
-                         adt.source(db).and_then(|node| name_range(db, node, file_id))
++                        enum_.source(db).and_then(|node| name_range(db, config, node, file_id))
 +                    } else {
 +                        None
 +                    }
 +                }
 +                _ => {
 +                    if config.annotate_references || config.annotate_impls {
-                     return value.name().map(|it| it.syntax().text_range());
++                        adt.source(db).and_then(|node| name_range(db, config, node, file_id))
 +                    } else {
 +                        None
 +                    }
 +                }
 +            },
 +            _ => None,
 +        };
 +
 +        let range = match range {
 +            Some(range) => range,
 +            None => return,
 +        };
 +
 +        if config.annotate_impls && !matches!(def, Definition::Const(_)) {
 +            annotations
 +                .push(Annotation { range, kind: AnnotationKind::HasImpls { file_id, data: None } });
 +        }
++
 +        if config.annotate_references {
 +            annotations.push(Annotation {
 +                range,
 +                kind: AnnotationKind::HasReferences { file_id, data: None },
 +            });
 +        }
 +
 +        fn name_range<T: HasName>(
 +            db: &RootDatabase,
++            config: &AnnotationConfig,
 +            node: InFile<T>,
 +            source_file_id: FileId,
 +        ) -> Option<TextRange> {
 +            if let Some(InFile { file_id, value }) = node.original_ast_node(db) {
 +                if file_id == source_file_id.into() {
-     fn check(ra_fixture: &str, expect: Expect) {
++                    return match config.location {
++                        AnnotationLocation::AboveName => {
++                            value.name().map(|name| name.syntax().text_range())
++                        }
++                        AnnotationLocation::AboveWholeItem => Some(value.syntax().text_range()),
++                    };
 +                }
 +            }
 +            None
 +        }
 +    });
 +
 +    if config.annotate_method_references {
 +        annotations.extend(find_all_methods(db, file_id).into_iter().map(
 +            |FileRange { file_id, range }| Annotation {
 +                range,
 +                kind: AnnotationKind::HasReferences { file_id, data: None },
 +            },
 +        ));
 +    }
 +
 +    annotations
 +}
 +
 +pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
 +    match annotation.kind {
 +        AnnotationKind::HasImpls { file_id, ref mut data } => {
 +            *data =
 +                goto_implementation(db, FilePosition { file_id, offset: annotation.range.start() })
 +                    .map(|range| range.info);
 +        }
 +        AnnotationKind::HasReferences { file_id, ref mut data } => {
 +            *data = find_all_refs(
 +                &Semantics::new(db),
 +                FilePosition { file_id, offset: annotation.range.start() },
 +                None,
 +            )
 +            .map(|result| {
 +                result
 +                    .into_iter()
 +                    .flat_map(|res| res.references)
 +                    .flat_map(|(file_id, access)| {
 +                        access.into_iter().map(move |(range, _)| FileRange { file_id, range })
 +                    })
 +                    .collect()
 +            });
 +        }
 +        _ => {}
 +    };
 +
 +    annotation
 +}
 +
 +fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
 +    match kind {
 +        RunnableKind::Bin => !binary_target,
 +        _ => false,
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +
 +    use crate::{fixture, Annotation, AnnotationConfig};
 +
-             .annotations(
-                 &AnnotationConfig {
-                     binary_target: true,
-                     annotate_runnables: true,
-                     annotate_impls: true,
-                     annotate_references: true,
-                     annotate_method_references: true,
-                     annotate_enum_variant_references: true,
-                 },
-                 file_id,
-             )
++    use super::AnnotationLocation;
++
++    const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig {
++        binary_target: true,
++        annotate_runnables: true,
++        annotate_impls: true,
++        annotate_references: true,
++        annotate_method_references: true,
++        annotate_enum_variant_references: true,
++        location: AnnotationLocation::AboveName,
++    };
++
++    fn check_with_config(ra_fixture: &str, expect: Expect, config: &AnnotationConfig) {
 +        let (analysis, file_id) = fixture::file(ra_fixture);
 +
 +        let annotations: Vec<Annotation> = analysis
++            .annotations(config, file_id)
 +            .unwrap()
 +            .into_iter()
 +            .map(|annotation| analysis.resolve_annotation(annotation).unwrap())
 +            .collect();
 +
 +        expect.assert_debug_eq(&annotations);
 +    }
 +
++    fn check(ra_fixture: &str, expect: Expect) {
++        check_with_config(ra_fixture, expect, &DEFAULT_CONFIG);
++    }
++
 +    #[test]
 +    fn const_annotations() {
 +        check(
 +            r#"
 +const DEMO: i32 = 123;
 +
 +const UNUSED: i32 = 123;
 +
 +fn main() {
 +    let hello = DEMO;
 +}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 53..57,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 50..85,
 +                                    focus_range: 53..57,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 6..10,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 78..82,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 30..36,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 53..57,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_references_annotations() {
 +        check(
 +            r#"
 +struct Test;
 +
 +fn main() {
 +    let test = Test;
 +}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 17..21,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 14..48,
 +                                    focus_range: 17..21,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasImpls {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 41..45,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 17..21,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_and_trait_impls_annotations() {
 +        check(
 +            r#"
 +struct Test;
 +
 +trait MyCoolTrait {}
 +
 +impl MyCoolTrait for Test {}
 +
 +fn main() {
 +    let test = Test;
 +}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 69..73,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 66..100,
 +                                    focus_range: 69..73,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasImpls {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    NavigationTarget {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        full_range: 36..64,
 +                                        focus_range: 57..61,
 +                                        name: "impl",
 +                                        kind: Impl,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 57..61,
 +                                    },
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 93..97,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 20..31,
 +                        kind: HasImpls {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    NavigationTarget {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        full_range: 36..64,
 +                                        focus_range: 57..61,
 +                                        name: "impl",
 +                                        kind: Impl,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 20..31,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 41..52,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 69..73,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn runnable_annotation() {
 +        check(
 +            r#"
 +fn main() {}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 3..7,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 3..7,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 3..7,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn method_annotations() {
 +        check(
 +            r#"
 +struct Test;
 +
 +impl Test {
 +    fn self_by_ref(&self) {}
 +}
 +
 +fn main() {
 +    Test.self_by_ref();
 +}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 61..65,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 58..95,
 +                                    focus_range: 61..65,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasImpls {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    NavigationTarget {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        full_range: 14..56,
 +                                        focus_range: 19..23,
 +                                        name: "impl",
 +                                        kind: Impl,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 7..11,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 19..23,
 +                                    },
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 74..78,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 33..44,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [
 +                                    FileRange {
 +                                        file_id: FileId(
 +                                            0,
 +                                        ),
 +                                        range: 79..90,
 +                                    },
 +                                ],
 +                            ),
 +                        },
 +                    },
 +                    Annotation {
 +                        range: 61..65,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_annotations() {
 +        check(
 +            r#"
 +fn main() {}
 +
 +mod tests {
 +    #[test]
 +    fn my_cool_test() {}
 +}
 +            "#,
 +            expect![[r#"
 +                [
 +                    Annotation {
 +                        range: 3..7,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 3..7,
 +                                    name: "main",
 +                                    kind: Function,
 +                                },
 +                                kind: Bin,
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 18..23,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 14..64,
 +                                    focus_range: 18..23,
 +                                    name: "tests",
 +                                    kind: Module,
 +                                    description: "mod tests",
 +                                },
 +                                kind: TestMod {
 +                                    path: "tests",
 +                                },
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 45..57,
 +                        kind: Runnable(
 +                            Runnable {
 +                                use_name_in_title: false,
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 30..62,
 +                                    focus_range: 45..57,
 +                                    name: "my_cool_test",
 +                                    kind: Function,
 +                                },
 +                                kind: Test {
 +                                    test_id: Path(
 +                                        "tests::my_cool_test",
 +                                    ),
 +                                    attr: TestAttr {
 +                                        ignore: false,
 +                                    },
 +                                },
 +                                cfg: None,
 +                            },
 +                        ),
 +                    },
 +                    Annotation {
 +                        range: 3..7,
 +                        kind: HasReferences {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            data: Some(
 +                                [],
 +                            ),
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_no_annotations_outside_module_tree() {
 +        check(
 +            r#"
 +//- /foo.rs
 +struct Foo;
 +//- /lib.rs
 +// this file comes last since `check` checks the first file only
 +"#,
 +            expect![[r#"
 +                []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_no_annotations_macro_struct_def() {
 +        check(
 +            r#"
 +//- /lib.rs
 +macro_rules! m {
 +    () => {
 +        struct A {}
 +    };
 +}
 +
 +m!();
 +"#,
 +            expect![[r#"
 +                []
 +            "#]],
 +        );
 +    }
++
++    #[test]
++    fn test_annotations_appear_above_whole_item_when_configured_to_do_so() {
++        check_with_config(
++            r#"
++/// This is a struct named Foo, obviously.
++#[derive(Clone)]
++struct Foo;
++"#,
++            expect![[r#"
++                [
++                    Annotation {
++                        range: 0..71,
++                        kind: HasImpls {
++                            file_id: FileId(
++                                0,
++                            ),
++                            data: Some(
++                                [],
++                            ),
++                        },
++                    },
++                    Annotation {
++                        range: 0..71,
++                        kind: HasReferences {
++                            file_id: FileId(
++                                0,
++                            ),
++                            data: None,
++                        },
++                    },
++                ]
++            "#]],
++            &AnnotationConfig { location: AnnotationLocation::AboveWholeItem, ..DEFAULT_CONFIG },
++        );
++    }
 +}
index f190da326e455fd8a6563df8ad19fd73d1aff90d,0000000000000000000000000000000000000000..1bdd626f1e834cbec0c8437639d46b130988c55d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1378 -1,0 +1,1379 @@@
-   //^^^^^
 +use hir::Semantics;
 +use ide_db::{
 +    base_db::{FileId, FilePosition},
 +    defs::{Definition, IdentClass},
 +    helpers::pick_best_token,
 +    search::{FileReference, ReferenceCategory, SearchScope},
 +    syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr},
 +    FxHashSet, RootDatabase,
 +};
 +use syntax::{
 +    ast::{self, HasLoopBody},
 +    match_ast, AstNode,
 +    SyntaxKind::{self, IDENT, INT_NUMBER},
 +    SyntaxNode, SyntaxToken, TextRange, T,
 +};
 +
 +use crate::{references, NavigationTarget, TryToNav};
 +
 +#[derive(PartialEq, Eq, Hash)]
 +pub struct HighlightedRange {
 +    pub range: TextRange,
 +    // FIXME: This needs to be more precise. Reference category makes sense only
 +    // for references, but we also have defs. And things like exit points are
 +    // neither.
 +    pub category: Option<ReferenceCategory>,
 +}
 +
 +#[derive(Default, Clone)]
 +pub struct HighlightRelatedConfig {
 +    pub references: bool,
 +    pub exit_points: bool,
 +    pub break_points: bool,
 +    pub yield_points: bool,
 +}
 +
 +// Feature: Highlight Related
 +//
 +// Highlights constructs related to the thing under the cursor:
 +//
 +// . if on an identifier, highlights all references to that identifier in the current file
 +// . if on an `async` or `await token, highlights all yield points for that async context
 +// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
 +// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
 +//
 +// Note: `?` and `->` do not currently trigger this behavior in the VSCode editor.
 +pub(crate) fn highlight_related(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: HighlightRelatedConfig,
 +    FilePosition { offset, file_id }: FilePosition,
 +) -> Option<Vec<HighlightedRange>> {
 +    let _p = profile::span("highlight_related");
 +    let syntax = sema.parse(file_id).syntax().clone();
 +
 +    let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
 +        T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
 +        T![->] => 3,
 +        kind if kind.is_keyword() => 2,
 +        IDENT | INT_NUMBER => 1,
 +        _ => 0,
 +    })?;
 +    match token.kind() {
 +        T![?] if config.exit_points && token.parent().and_then(ast::TryExpr::cast).is_some() => {
 +            highlight_exit_points(sema, token)
 +        }
 +        T![fn] | T![return] | T![->] if config.exit_points => highlight_exit_points(sema, token),
 +        T![await] | T![async] if config.yield_points => highlight_yield_points(token),
 +        T![for] if config.break_points && token.parent().and_then(ast::ForExpr::cast).is_some() => {
 +            highlight_break_points(token)
 +        }
 +        T![break] | T![loop] | T![while] | T![continue] if config.break_points => {
 +            highlight_break_points(token)
 +        }
 +        _ if config.references => highlight_references(sema, &syntax, token, file_id),
 +        _ => None,
 +    }
 +}
 +
 +fn highlight_references(
 +    sema: &Semantics<'_, RootDatabase>,
 +    node: &SyntaxNode,
 +    token: SyntaxToken,
 +    file_id: FileId,
 +) -> Option<Vec<HighlightedRange>> {
 +    let defs = find_defs(sema, token);
 +    let usages = defs
 +        .iter()
 +        .filter_map(|&d| {
 +            d.usages(sema)
 +                .set_scope(Some(SearchScope::single_file(file_id)))
 +                .include_self_refs()
 +                .all()
 +                .references
 +                .remove(&file_id)
 +        })
 +        .flatten()
 +        .map(|FileReference { category: access, range, .. }| HighlightedRange {
 +            range,
 +            category: access,
 +        });
 +    let mut res = FxHashSet::default();
 +
 +    let mut def_to_hl_range = |def| {
 +        let hl_range = match def {
 +            Definition::Module(module) => {
 +                Some(NavigationTarget::from_module_to_decl(sema.db, module))
 +            }
 +            def => def.try_to_nav(sema.db),
 +        }
 +        .filter(|decl| decl.file_id == file_id)
 +        .and_then(|decl| decl.focus_range)
 +        .map(|range| {
 +            let category =
 +                references::decl_mutability(&def, node, range).then(|| ReferenceCategory::Write);
 +            HighlightedRange { range, category }
 +        });
 +        if let Some(hl_range) = hl_range {
 +            res.insert(hl_range);
 +        }
 +    };
 +    for &def in &defs {
 +        match def {
 +            Definition::Local(local) => local
 +                .associated_locals(sema.db)
 +                .iter()
 +                .for_each(|&local| def_to_hl_range(Definition::Local(local))),
 +            def => def_to_hl_range(def),
 +        }
 +    }
 +
 +    res.extend(usages);
 +    if res.is_empty() {
 +        None
 +    } else {
 +        Some(res.into_iter().collect())
 +    }
 +}
 +
 +fn highlight_exit_points(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: SyntaxToken,
 +) -> Option<Vec<HighlightedRange>> {
 +    fn hl(
 +        sema: &Semantics<'_, RootDatabase>,
 +        body: Option<ast::Expr>,
 +    ) -> Option<Vec<HighlightedRange>> {
 +        let mut highlights = Vec::new();
 +        let body = body?;
 +        walk_expr(&body, &mut |expr| match expr {
 +            ast::Expr::ReturnExpr(expr) => {
 +                if let Some(token) = expr.return_token() {
 +                    highlights.push(HighlightedRange { category: None, range: token.text_range() });
 +                }
 +            }
 +            ast::Expr::TryExpr(try_) => {
 +                if let Some(token) = try_.question_mark_token() {
 +                    highlights.push(HighlightedRange { category: None, range: token.text_range() });
 +                }
 +            }
 +            ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroExpr(_) => {
 +                if sema.type_of_expr(&expr).map_or(false, |ty| ty.original.is_never()) {
 +                    highlights.push(HighlightedRange {
 +                        category: None,
 +                        range: expr.syntax().text_range(),
 +                    });
 +                }
 +            }
 +            _ => (),
 +        });
 +        let tail = match body {
 +            ast::Expr::BlockExpr(b) => b.tail_expr(),
 +            e => Some(e),
 +        };
 +
 +        if let Some(tail) = tail {
 +            for_each_tail_expr(&tail, &mut |tail| {
 +                let range = match tail {
 +                    ast::Expr::BreakExpr(b) => b
 +                        .break_token()
 +                        .map_or_else(|| tail.syntax().text_range(), |tok| tok.text_range()),
 +                    _ => tail.syntax().text_range(),
 +                };
 +                highlights.push(HighlightedRange { category: None, range })
 +            });
 +        }
 +        Some(highlights)
 +    }
 +    for anc in token.parent_ancestors() {
 +        return match_ast! {
 +            match anc {
 +                ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)),
 +                ast::ClosureExpr(closure) => hl(sema, closure.body()),
 +                ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
 +                    hl(sema, Some(block_expr.into()))
 +                } else {
 +                    continue;
 +                },
 +                _ => continue,
 +            }
 +        };
 +    }
 +    None
 +}
 +
 +fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
 +    fn hl(
 +        cursor_token_kind: SyntaxKind,
 +        token: Option<SyntaxToken>,
 +        label: Option<ast::Label>,
 +        body: Option<ast::StmtList>,
 +    ) -> Option<Vec<HighlightedRange>> {
 +        let mut highlights = Vec::new();
 +        let range = cover_range(
 +            token.map(|tok| tok.text_range()),
 +            label.as_ref().map(|it| it.syntax().text_range()),
 +        );
 +        highlights.extend(range.map(|range| HighlightedRange { category: None, range }));
 +        for_each_break_and_continue_expr(label, body, &mut |expr| {
 +            let range: Option<TextRange> = match (cursor_token_kind, expr) {
 +                (T![for] | T![while] | T![loop] | T![break], ast::Expr::BreakExpr(break_)) => {
 +                    cover_range(
 +                        break_.break_token().map(|it| it.text_range()),
 +                        break_.lifetime().map(|it| it.syntax().text_range()),
 +                    )
 +                }
 +                (
 +                    T![for] | T![while] | T![loop] | T![continue],
 +                    ast::Expr::ContinueExpr(continue_),
 +                ) => cover_range(
 +                    continue_.continue_token().map(|it| it.text_range()),
 +                    continue_.lifetime().map(|it| it.syntax().text_range()),
 +                ),
 +                _ => None,
 +            };
 +            highlights.extend(range.map(|range| HighlightedRange { category: None, range }));
 +        });
 +        Some(highlights)
 +    }
 +    let parent = token.parent()?;
 +    let lbl = match_ast! {
 +        match parent {
 +            ast::BreakExpr(b) => b.lifetime(),
 +            ast::ContinueExpr(c) => c.lifetime(),
 +            ast::LoopExpr(l) => l.label().and_then(|it| it.lifetime()),
 +            ast::ForExpr(f) => f.label().and_then(|it| it.lifetime()),
 +            ast::WhileExpr(w) => w.label().and_then(|it| it.lifetime()),
 +            ast::BlockExpr(b) => Some(b.label().and_then(|it| it.lifetime())?),
 +            _ => return None,
 +        }
 +    };
 +    let lbl = lbl.as_ref();
 +    let label_matches = |def_lbl: Option<ast::Label>| match lbl {
 +        Some(lbl) => {
 +            Some(lbl.text()) == def_lbl.and_then(|it| it.lifetime()).as_ref().map(|it| it.text())
 +        }
 +        None => true,
 +    };
 +    let token_kind = token.kind();
 +    for anc in token.parent_ancestors().flat_map(ast::Expr::cast) {
 +        return match anc {
 +            ast::Expr::LoopExpr(l) if label_matches(l.label()) => hl(
 +                token_kind,
 +                l.loop_token(),
 +                l.label(),
 +                l.loop_body().and_then(|it| it.stmt_list()),
 +            ),
 +            ast::Expr::ForExpr(f) if label_matches(f.label()) => hl(
 +                token_kind,
 +                f.for_token(),
 +                f.label(),
 +                f.loop_body().and_then(|it| it.stmt_list()),
 +            ),
 +            ast::Expr::WhileExpr(w) if label_matches(w.label()) => hl(
 +                token_kind,
 +                w.while_token(),
 +                w.label(),
 +                w.loop_body().and_then(|it| it.stmt_list()),
 +            ),
 +            ast::Expr::BlockExpr(e) if e.label().is_some() && label_matches(e.label()) => {
 +                hl(token_kind, None, e.label(), e.stmt_list())
 +            }
 +            _ => continue,
 +        };
 +    }
 +    None
 +}
 +
 +fn highlight_yield_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
 +    fn hl(
 +        async_token: Option<SyntaxToken>,
 +        body: Option<ast::Expr>,
 +    ) -> Option<Vec<HighlightedRange>> {
 +        let mut highlights =
 +            vec![HighlightedRange { category: None, range: async_token?.text_range() }];
 +        if let Some(body) = body {
 +            walk_expr(&body, &mut |expr| {
 +                if let ast::Expr::AwaitExpr(expr) = expr {
 +                    if let Some(token) = expr.await_token() {
 +                        highlights
 +                            .push(HighlightedRange { category: None, range: token.text_range() });
 +                    }
 +                }
 +            });
 +        }
 +        Some(highlights)
 +    }
 +    for anc in token.parent_ancestors() {
 +        return match_ast! {
 +            match anc {
 +                ast::Fn(fn_) => hl(fn_.async_token(), fn_.body().map(ast::Expr::BlockExpr)),
 +                ast::BlockExpr(block_expr) => {
 +                    if block_expr.async_token().is_none() {
 +                        continue;
 +                    }
 +                    hl(block_expr.async_token(), Some(block_expr.into()))
 +                },
 +                ast::ClosureExpr(closure) => hl(closure.async_token(), closure.body()),
 +                _ => continue,
 +            }
 +        };
 +    }
 +    None
 +}
 +
 +fn cover_range(r0: Option<TextRange>, r1: Option<TextRange>) -> Option<TextRange> {
 +    match (r0, r1) {
 +        (Some(r0), Some(r1)) => Some(r0.cover(r1)),
 +        (Some(range), None) => Some(range),
 +        (None, Some(range)) => Some(range),
 +        (None, None) => None,
 +    }
 +}
 +
 +fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSet<Definition> {
 +    sema.descend_into_macros(token)
 +        .into_iter()
 +        .filter_map(|token| IdentClass::classify_token(sema, &token))
 +        .map(IdentClass::definitions_no_ops)
 +        .flatten()
 +        .collect()
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::fixture;
 +
 +    use super::*;
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str) {
 +        let config = HighlightRelatedConfig {
 +            break_points: true,
 +            exit_points: true,
 +            references: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(ra_fixture, config);
 +    }
 +
 +    #[track_caller]
 +    fn check_with_config(ra_fixture: &str, config: HighlightRelatedConfig) {
 +        let (analysis, pos, annotations) = fixture::annotations(ra_fixture);
 +
 +        let hls = analysis.highlight_related(config, pos).unwrap().unwrap_or_default();
 +
 +        let mut expected = annotations
 +            .into_iter()
 +            .map(|(r, access)| (r.range, (!access.is_empty()).then(|| access)))
 +            .collect::<Vec<_>>();
 +
 +        let mut actual = hls
 +            .into_iter()
 +            .map(|hl| {
 +                (
 +                    hl.range,
 +                    hl.category.map(|it| {
 +                        match it {
 +                            ReferenceCategory::Read => "read",
 +                            ReferenceCategory::Write => "write",
++                            ReferenceCategory::Import => "import",
 +                        }
 +                        .to_string()
 +                    }),
 +                )
 +            })
 +            .collect::<Vec<_>>();
 +        actual.sort_by_key(|(range, _)| range.start());
 +        expected.sort_by_key(|(range, _)| range.start());
 +
 +        assert_eq!(expected, actual);
 +    }
 +
 +    #[test]
 +    fn test_hl_tuple_fields() {
 +        check(
 +            r#"
 +struct Tuple(u32, u32);
 +
 +fn foo(t: Tuple) {
 +    t.0$0;
 +   // ^ read
 +    t.0;
 +   // ^ read
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_module() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo$0;
 + // ^^^
 +//- /foo.rs
 +struct Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_self_in_crate_root() {
 +        check(
 +            r#"
 +use crate$0;
-   //^^^^
++  //^^^^^ import
 +use self;
-       //^^^^^
++  //^^^^ import
 +mod __ {
 +    use super;
-   //^^^
++      //^^^^^ import
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +//- /main.rs crate:main deps:lib
 +use lib$0;
-  // ^^^^
++  //^^^ import
 +//- /lib.rs crate:lib
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_self_in_module() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo;
 +//- /foo.rs
 +use self$0;
++ // ^^^^ import
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_local() {
 +        check(
 +            r#"
 +fn foo() {
 +    let mut bar = 3;
 +         // ^^^ write
 +    bar$0;
 + // ^^^ read
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_local_in_attr() {
 +        check(
 +            r#"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +fn foo() {
 +    let mut bar = 3;
 +         // ^^^ write
 +    bar$0;
 + // ^^^ read
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_multi_macro_usage() {
 +        check(
 +            r#"
 +macro_rules! foo {
 +    ($ident:ident) => {
 +        fn $ident() -> $ident { loop {} }
 +        struct $ident;
 +    }
 +}
 +
 +foo!(bar$0);
 +  // ^^^
 +fn foo() {
 +    let bar: bar = bar();
 +          // ^^^
 +                // ^^^
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +macro_rules! foo {
 +    ($ident:ident) => {
 +        fn $ident() -> $ident { loop {} }
 +        struct $ident;
 +    }
 +}
 +
 +foo!(bar);
 +  // ^^^
 +fn foo() {
 +    let bar: bar$0 = bar();
 +          // ^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_yield_points() {
 +        check(
 +            r#"
 +pub async fn foo() {
 + // ^^^^^
 +    let x = foo()
 +        .await$0
 +      // ^^^^^
 +        .await;
 +      // ^^^^^
 +    || { 0.await };
 +    (async { 0.await }).await
 +                     // ^^^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_yield_points2() {
 +        check(
 +            r#"
 +pub async$0 fn foo() {
 + // ^^^^^
 +    let x = foo()
 +        .await
 +      // ^^^^^
 +        .await;
 +      // ^^^^^
 +    || { 0.await };
 +    (async { 0.await }).await
 +                     // ^^^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_yield_nested_fn() {
 +        check(
 +            r#"
 +async fn foo() {
 +    async fn foo2() {
 + // ^^^^^
 +        async fn foo3() {
 +            0.await
 +        }
 +        0.await$0
 +       // ^^^^^
 +    }
 +    0.await
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_yield_nested_async_blocks() {
 +        check(
 +            r#"
 +async fn foo() {
 +    (async {
 +  // ^^^^^
 +        (async {
 +           0.await
 +        }).await$0 }
 +        // ^^^^^
 +    ).await;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_exit_points() {
 +        check(
 +            r#"
 +fn foo() -> u32 {
 +    if true {
 +        return$0 0;
 +     // ^^^^^^
 +    }
 +
 +    0?;
 +  // ^
 +    0xDEAD_BEEF
 + // ^^^^^^^^^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_exit_points2() {
 +        check(
 +            r#"
 +fn foo() ->$0 u32 {
 +    if true {
 +        return 0;
 +     // ^^^^^^
 +    }
 +
 +    0?;
 +  // ^
 +    0xDEAD_BEEF
 + // ^^^^^^^^^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_exit_points3() {
 +        check(
 +            r#"
 +fn$0 foo() -> u32 {
 +    if true {
 +        return 0;
 +     // ^^^^^^
 +    }
 +
 +    0?;
 +  // ^
 +    0xDEAD_BEEF
 + // ^^^^^^^^^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_prefer_ref_over_tail_exit() {
 +        check(
 +            r#"
 +fn foo() -> u32 {
 +// ^^^
 +    if true {
 +        return 0;
 +    }
 +
 +    0?;
 +
 +    foo$0()
 + // ^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_never_call_is_exit_point() {
 +        check(
 +            r#"
 +struct Never;
 +impl Never {
 +    fn never(self) -> ! { loop {} }
 +}
 +macro_rules! never {
 +    () => { never() }
 +}
 +fn never() -> ! { loop {} }
 +fn foo() ->$0 u32 {
 +    never();
 + // ^^^^^^^
 +    never!();
 + // ^^^^^^^^
 +
 +    Never.never();
 + // ^^^^^^^^^^^^^
 +
 +    0
 + // ^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_inner_tail_exit_points() {
 +        check(
 +            r#"
 +fn foo() ->$0 u32 {
 +    if true {
 +        unsafe {
 +            return 5;
 +         // ^^^^^^
 +            5
 +         // ^
 +        }
 +    } else if false {
 +        0
 +     // ^
 +    } else {
 +        match 5 {
 +            6 => 100,
 +              // ^^^
 +            7 => loop {
 +                break 5;
 +             // ^^^^^
 +            }
 +            8 => 'a: loop {
 +                'b: loop {
 +                    break 'a 5;
 +                 // ^^^^^
 +                    break 'b 5;
 +                    break 5;
 +                };
 +            }
 +            //
 +            _ => 500,
 +              // ^^^
 +        }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_inner_tail_exit_points_labeled_block() {
 +        check(
 +            r#"
 +fn foo() ->$0 u32 {
 +    'foo: {
 +        break 'foo 0;
 +     // ^^^^^
 +        loop {
 +            break;
 +            break 'foo 0;
 +         // ^^^^^
 +        }
 +        0
 +     // ^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_loop() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: loop {
 + // ^^^^^^^^^^^^
 +         break;
 +      // ^^^^^
 +         'inner: loop {
 +            break;
 +            'innermost: loop {
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                break 'inner;
 +            }
 +            break$0 'outer;
 +         // ^^^^^^^^^^^^
 +            break;
 +        }
 +        break;
 +     // ^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_loop2() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: loop {
 +        break;
 +        'inner: loop {
 +     // ^^^^^^^^^^^^
 +            break;
 +         // ^^^^^
 +            'innermost: loop {
 +                break 'outer;
 +                break 'inner;
 +             // ^^^^^^^^^^^^
 +            }
 +            break 'outer;
 +            break$0;
 +         // ^^^^^
 +        }
 +        break;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_for() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: for _ in () {
 + // ^^^^^^^^^^^
 +         break;
 +      // ^^^^^
 +         'inner: for _ in () {
 +            break;
 +            'innermost: for _ in () {
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                break 'inner;
 +            }
 +            break$0 'outer;
 +         // ^^^^^^^^^^^^
 +            break;
 +        }
 +        break;
 +     // ^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_for_but_not_continue() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: for _ in () {
 + // ^^^^^^^^^^^
 +        break;
 +     // ^^^^^
 +        continue;
 +        'inner: for _ in () {
 +            break;
 +            continue;
 +            'innermost: for _ in () {
 +                continue 'outer;
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                continue 'inner;
 +                break 'inner;
 +            }
 +            break$0 'outer;
 +         // ^^^^^^^^^^^^
 +            continue 'outer;
 +            break;
 +            continue;
 +        }
 +        break;
 +     // ^^^^^
 +        continue;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_continue_for_but_not_break() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: for _ in () {
 + // ^^^^^^^^^^^
 +        break;
 +        continue;
 +     // ^^^^^^^^
 +        'inner: for _ in () {
 +            break;
 +            continue;
 +            'innermost: for _ in () {
 +                continue 'outer;
 +             // ^^^^^^^^^^^^^^^
 +                break 'outer;
 +                continue 'inner;
 +                break 'inner;
 +            }
 +            break 'outer;
 +            continue$0 'outer;
 +         // ^^^^^^^^^^^^^^^
 +            break;
 +            continue;
 +        }
 +        break;
 +        continue;
 +     // ^^^^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_and_continue() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: fo$0r _ in () {
 + // ^^^^^^^^^^^
 +        break;
 +     // ^^^^^
 +        continue;
 +     // ^^^^^^^^
 +        'inner: for _ in () {
 +            break;
 +            continue;
 +            'innermost: for _ in () {
 +                continue 'outer;
 +             // ^^^^^^^^^^^^^^^
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                continue 'inner;
 +                break 'inner;
 +            }
 +            break 'outer;
 +         // ^^^^^^^^^^^^
 +            continue 'outer;
 +         // ^^^^^^^^^^^^^^^
 +            break;
 +            continue;
 +        }
 +        break;
 +     // ^^^^^
 +        continue;
 +     // ^^^^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_while() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: while true {
 + // ^^^^^^^^^^^^^
 +         break;
 +      // ^^^^^
 +         'inner: while true {
 +            break;
 +            'innermost: while true {
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                break 'inner;
 +            }
 +            break$0 'outer;
 +         // ^^^^^^^^^^^^
 +            break;
 +        }
 +        break;
 +     // ^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_labeled_block() {
 +        check(
 +            r#"
 +fn foo() {
 +    'outer: {
 + // ^^^^^^^
 +         break;
 +      // ^^^^^
 +         'inner: {
 +            break;
 +            'innermost: {
 +                break 'outer;
 +             // ^^^^^^^^^^^^
 +                break 'inner;
 +            }
 +            break$0 'outer;
 +         // ^^^^^^^^^^^^
 +            break;
 +        }
 +        break;
 +     // ^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_unlabeled_loop() {
 +        check(
 +            r#"
 +fn foo() {
 +    loop {
 + // ^^^^
 +        break$0;
 +     // ^^^^^
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_break_unlabeled_block_in_loop() {
 +        check(
 +            r#"
 +fn foo() {
 +    loop {
 + // ^^^^
 +        {
 +            break$0;
 +         // ^^^^^
 +        }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_field_shorthand() {
 +        check(
 +            r#"
 +struct Struct { field: u32 }
 +              //^^^^^
 +fn function(field: u32) {
 +          //^^^^^
 +    Struct { field$0 }
 +           //^^^^^ read
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_ref_local() {
 +        let config = HighlightRelatedConfig {
 +            references: false,
 +            break_points: true,
 +            exit_points: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +fn foo() {
 +    let x$0 = 5;
 +    let y = x * 2;
 +}
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_ref_local_preserved_break() {
 +        let config = HighlightRelatedConfig {
 +            references: false,
 +            break_points: true,
 +            exit_points: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +fn foo() {
 +    let x$0 = 5;
 +    let y = x * 2;
 +
 +    loop {
 +        break;
 +    }
 +}
 +"#,
 +            config.clone(),
 +        );
 +
 +        check_with_config(
 +            r#"
 +fn foo() {
 +    let x = 5;
 +    let y = x * 2;
 +
 +    loop$0 {
 +//  ^^^^
 +        break;
 +//      ^^^^^
 +    }
 +}
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_ref_local_preserved_yield() {
 +        let config = HighlightRelatedConfig {
 +            references: false,
 +            break_points: true,
 +            exit_points: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +async fn foo() {
 +    let x$0 = 5;
 +    let y = x * 2;
 +
 +    0.await;
 +}
 +"#,
 +            config.clone(),
 +        );
 +
 +        check_with_config(
 +            r#"
 +    async fn foo() {
 +//  ^^^^^
 +        let x = 5;
 +        let y = x * 2;
 +
 +        0.await$0;
 +//        ^^^^^
 +}
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_ref_local_preserved_exit() {
 +        let config = HighlightRelatedConfig {
 +            references: false,
 +            break_points: true,
 +            exit_points: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +fn foo() -> i32 {
 +    let x$0 = 5;
 +    let y = x * 2;
 +
 +    if true {
 +        return y;
 +    }
 +
 +    0?
 +}
 +"#,
 +            config.clone(),
 +        );
 +
 +        check_with_config(
 +            r#"
 +fn foo() ->$0 i32 {
 +    let x = 5;
 +    let y = x * 2;
 +
 +    if true {
 +        return y;
 +//      ^^^^^^
 +    }
 +
 +    0?
 +//   ^
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_break() {
 +        let config = HighlightRelatedConfig {
 +            references: true,
 +            break_points: false,
 +            exit_points: true,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +fn foo() {
 +    loop {
 +        break$0;
 +    }
 +}
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_yield() {
 +        let config = HighlightRelatedConfig {
 +            references: true,
 +            break_points: true,
 +            exit_points: true,
 +            yield_points: false,
 +        };
 +
 +        check_with_config(
 +            r#"
 +async$0 fn foo() {
 +    0.await;
 +}
 +"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_disabled_exit() {
 +        let config = HighlightRelatedConfig {
 +            references: true,
 +            break_points: true,
 +            exit_points: false,
 +            yield_points: true,
 +        };
 +
 +        check_with_config(
 +            r#"
 +fn foo() ->$0 i32 {
 +    if true {
 +        return -1;
 +    }
 +
 +    42
 +}"#,
 +            config,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_multi_local() {
 +        check(
 +            r#"
 +fn foo((
 +    foo$0
 +  //^^^
 +    | foo
 +    //^^^
 +    | foo
 +    //^^^
 +): ()) {
 +    foo;
 +  //^^^read
 +    let foo;
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +fn foo((
 +    foo
 +  //^^^
 +    | foo$0
 +    //^^^
 +    | foo
 +    //^^^
 +): ()) {
 +    foo;
 +  //^^^read
 +    let foo;
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +fn foo((
 +    foo
 +  //^^^
 +    | foo
 +    //^^^
 +    | foo
 +    //^^^
 +): ()) {
 +    foo$0;
 +  //^^^read
 +    let foo;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_hl_trait_impl_methods() {
 +        check(
 +            r#"
 +trait Trait {
 +    fn func$0(self) {}
 +     //^^^^
 +}
 +
 +impl Trait for () {
 +    fn func(self) {}
 +     //^^^^
 +}
 +
 +fn main() {
 +    <()>::func(());
 +        //^^^^
 +    ().func();
 +     //^^^^
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +trait Trait {
 +    fn func(self) {}
 +     //^^^^
 +}
 +
 +impl Trait for () {
 +    fn func$0(self) {}
 +     //^^^^
 +}
 +
 +fn main() {
 +    <()>::func(());
 +        //^^^^
 +    ().func();
 +     //^^^^
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +trait Trait {
 +    fn func(self) {}
 +     //^^^^
 +}
 +
 +impl Trait for () {
 +    fn func(self) {}
 +     //^^^^
 +}
 +
 +fn main() {
 +    <()>::func(());
 +        //^^^^
 +    ().func$0();
 +     //^^^^
 +}
 +"#,
 +        );
 +    }
 +}
index d1b1d2c331a513d3ca6a17d4de2609f672f6ed92,0000000000000000000000000000000000000000..93fcd7cad7a18e976a5a0ea98f389ac4aa02b8ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,2928 -1,0 +1,2996 @@@
 +use std::fmt;
 +
 +use either::Either;
 +use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::to_lower_snake_case;
 +use syntax::{
 +    ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
 +    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
 +    TextSize, T,
 +};
 +
 +use crate::FileId;
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct InlayHintsConfig {
 +    pub render_colons: bool,
 +    pub type_hints: bool,
 +    pub parameter_hints: bool,
 +    pub chaining_hints: bool,
 +    pub reborrow_hints: ReborrowHints,
 +    pub closure_return_type_hints: ClosureReturnTypeHints,
 +    pub binding_mode_hints: bool,
 +    pub lifetime_elision_hints: LifetimeElisionHints,
 +    pub param_names_for_lifetime_elision_hints: bool,
 +    pub hide_named_constructor_hints: bool,
 +    pub hide_closure_initialization_hints: bool,
 +    pub max_length: Option<usize>,
 +    pub closing_brace_hints_min_lines: Option<usize>,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ClosureReturnTypeHints {
 +    Always,
 +    WithBlock,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum LifetimeElisionHints {
 +    Always,
 +    SkipTrivial,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ReborrowHints {
 +    Always,
 +    MutableOnly,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum InlayKind {
 +    BindingModeHint,
 +    ChainingHint,
 +    ClosingBraceHint,
 +    ClosureReturnTypeHint,
 +    GenericParamListHint,
 +    ImplicitReborrowHint,
 +    LifetimeHint,
 +    ParameterHint,
 +    TypeHint,
 +}
 +
 +#[derive(Debug)]
 +pub struct InlayHint {
 +    pub range: TextRange,
 +    pub kind: InlayKind,
 +    pub label: InlayHintLabel,
 +    pub tooltip: Option<InlayTooltip>,
 +}
 +
 +#[derive(Debug)]
 +pub enum InlayTooltip {
 +    String(String),
 +    HoverRanged(FileId, TextRange),
 +    HoverOffset(FileId, TextSize),
 +}
 +
 +pub struct InlayHintLabel {
 +    pub parts: Vec<InlayHintLabelPart>,
 +}
 +
 +impl InlayHintLabel {
 +    pub fn as_simple_str(&self) -> Option<&str> {
 +        match &*self.parts {
 +            [part] => part.as_simple_str(),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn prepend_str(&mut self, s: &str) {
 +        match &mut *self.parts {
 +            [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
 +            _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
 +        }
 +    }
 +
 +    pub fn append_str(&mut self, s: &str) {
 +        match &mut *self.parts {
 +            [.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
 +            _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
 +        }
 +    }
 +}
 +
 +impl From<String> for InlayHintLabel {
 +    fn from(s: String) -> Self {
 +        Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
 +    }
 +}
 +
 +impl fmt::Display for InlayHintLabel {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
 +    }
 +}
 +
 +impl fmt::Debug for InlayHintLabel {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_list().entries(&self.parts).finish()
 +    }
 +}
 +
 +pub struct InlayHintLabelPart {
 +    pub text: String,
 +    /// Source location represented by this label part. The client will use this to fetch the part's
 +    /// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location
 +    /// refers to (not necessarily the location itself).
 +    /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
 +    /// them both.
 +    pub linked_location: Option<FileRange>,
 +}
 +
 +impl InlayHintLabelPart {
 +    pub fn as_simple_str(&self) -> Option<&str> {
 +        match self {
 +            Self { text, linked_location: None } => Some(text),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl fmt::Debug for InlayHintLabelPart {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self.as_simple_str() {
 +            Some(string) => string.fmt(f),
 +            None => f
 +                .debug_struct("InlayHintLabelPart")
 +                .field("text", &self.text)
 +                .field("linked_location", &self.linked_location)
 +                .finish(),
 +        }
 +    }
 +}
 +
 +// Feature: Inlay Hints
 +//
 +// rust-analyzer shows additional information inline with the source code.
 +// Editors usually render this using read-only virtual text snippets interspersed with code.
 +//
 +// rust-analyzer by default shows hints for
 +//
 +// * types of local variables
 +// * names of function arguments
 +// * types of chained expressions
 +//
 +// Optionally, one can enable additional hints for
 +//
 +// * return types of closure expressions
 +// * elided lifetimes
 +// * compiler inserted reborrows
 +//
 +// |===
 +// | Editor  | Action Name
 +//
 +// | VS Code | **rust-analyzer: Toggle inlay hints*
 +// |===
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
 +pub(crate) fn inlay_hints(
 +    db: &RootDatabase,
 +    file_id: FileId,
 +    range_limit: Option<FileRange>,
 +    config: &InlayHintsConfig,
 +) -> Vec<InlayHint> {
 +    let _p = profile::span("inlay_hints");
 +    let sema = Semantics::new(db);
 +    let file = sema.parse(file_id);
 +    let file = file.syntax();
 +
 +    let mut acc = Vec::new();
 +
 +    if let Some(scope) = sema.scope(&file) {
 +        let famous_defs = FamousDefs(&sema, scope.krate());
 +
 +        let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
 +        match range_limit {
 +            Some(FileRange { range, .. }) => match file.covering_element(range) {
 +                NodeOrToken::Token(_) => return acc,
 +                NodeOrToken::Node(n) => n
 +                    .descendants()
 +                    .filter(|descendant| range.intersect(descendant.text_range()).is_some())
 +                    .for_each(hints),
 +            },
 +            None => file.descendants().for_each(hints),
 +        };
 +    }
 +
 +    acc
 +}
 +
 +fn hints(
 +    hints: &mut Vec<InlayHint>,
 +    famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    node: SyntaxNode,
 +) {
 +    closing_brace_hints(hints, sema, config, file_id, node.clone());
 +    match_ast! {
 +        match node {
 +            ast::Expr(expr) => {
 +                chaining_hints(hints, sema, &famous_defs, config, file_id, &expr);
 +                match expr {
 +                    ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
 +                    ast::Expr::MethodCallExpr(it) => {
 +                        param_name_hints(hints, sema, config, ast::Expr::from(it))
 +                    }
 +                    ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it),
 +                    // We could show reborrows for all expressions, but usually that is just noise to the user
 +                    // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
 +                    ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
 +                    _ => None,
 +                }
 +            },
 +            ast::Pat(it) => {
 +                binding_mode_hints(hints, sema, config, &it);
 +                if let ast::Pat::IdentPat(it) = it {
 +                    bind_pat_hints(hints, sema, config, file_id, &it);
 +                }
 +                Some(())
 +            },
 +            ast::Item(it) => match it {
 +                // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
 +                ast::Item::Impl(_) => None,
 +                ast::Item::Fn(it) => fn_lifetime_fn_hints(hints, config, it),
 +                // static type elisions
 +                ast::Item::Static(it) => implicit_static_hints(hints, config, Either::Left(it)),
 +                ast::Item::Const(it) => implicit_static_hints(hints, config, Either::Right(it)),
 +                _ => None,
 +            },
 +            // FIXME: fn-ptr type, dyn fn type, and trait object type elisions
 +            ast::Type(_) => None,
 +            _ => None,
 +        }
 +    };
 +}
 +
 +fn closing_brace_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    node: SyntaxNode,
 +) -> Option<()> {
 +    let min_lines = config.closing_brace_hints_min_lines?;
 +
 +    let name = |it: ast::Name| it.syntax().text_range();
 +
 +    let mut closing_token;
 +    let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
 +        closing_token = item_list.r_curly_token()?;
 +
 +        let parent = item_list.syntax().parent()?;
 +        match_ast! {
 +            match parent {
 +                ast::Impl(imp) => {
 +                    let imp = sema.to_def(&imp)?;
 +                    let ty = imp.self_ty(sema.db);
 +                    let trait_ = imp.trait_(sema.db);
 +                    let hint_text = match trait_ {
 +                        Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
 +                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
 +                    };
 +                    (hint_text, None)
 +                },
 +                ast::Trait(tr) => {
 +                    (format!("trait {}", tr.name()?), tr.name().map(name))
 +                },
 +                _ => return None,
 +            }
 +        }
 +    } else if let Some(list) = ast::ItemList::cast(node.clone()) {
 +        closing_token = list.r_curly_token()?;
 +
 +        let module = ast::Module::cast(list.syntax().parent()?)?;
 +        (format!("mod {}", module.name()?), module.name().map(name))
 +    } else if let Some(block) = ast::BlockExpr::cast(node.clone()) {
 +        closing_token = block.stmt_list()?.r_curly_token()?;
 +
 +        let parent = block.syntax().parent()?;
 +        match_ast! {
 +            match parent {
 +                ast::Fn(it) => {
 +                    // FIXME: this could include parameters, but `HirDisplay` prints too much info
 +                    // and doesn't respect the max length either, so the hints end up way too long
 +                    (format!("fn {}", it.name()?), it.name().map(name))
 +                },
 +                ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
 +                ast::Const(it) => {
 +                    if it.underscore_token().is_some() {
 +                        ("const _".into(), None)
 +                    } else {
 +                        (format!("const {}", it.name()?), it.name().map(name))
 +                    }
 +                },
 +                _ => return None,
 +            }
 +        }
 +    } else if let Some(mac) = ast::MacroCall::cast(node.clone()) {
 +        let last_token = mac.syntax().last_token()?;
 +        if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY {
 +            return None;
 +        }
 +        closing_token = last_token;
 +
 +        (
 +            format!("{}!", mac.path()?),
 +            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()),
 +        )
 +    } else {
 +        return None;
 +    };
 +
 +    if let Some(mut next) = closing_token.next_token() {
 +        if next.kind() == T![;] {
 +            if let Some(tok) = next.next_token() {
 +                closing_token = next;
 +                next = tok;
 +            }
 +        }
 +        if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) {
 +            // Only display the hint if the `}` is the last token on the line
 +            return None;
 +        }
 +    }
 +
 +    let mut lines = 1;
 +    node.text().for_each_chunk(|s| lines += s.matches('\n').count());
 +    if lines < min_lines {
 +        return None;
 +    }
 +
 +    let linked_location = name_range.map(|range| FileRange { file_id, range });
 +    acc.push(InlayHint {
 +        range: closing_token.text_range(),
 +        kind: InlayKind::ClosingBraceHint,
 +        label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] },
 +        tooltip: None, // provided by label part location
 +    });
 +
 +    None
 +}
 +
 +fn implicit_static_hints(
 +    acc: &mut Vec<InlayHint>,
 +    config: &InlayHintsConfig,
 +    statik_or_const: Either<ast::Static, ast::Const>,
 +) -> Option<()> {
 +    if config.lifetime_elision_hints != LifetimeElisionHints::Always {
 +        return None;
 +    }
 +
 +    if let Either::Right(it) = &statik_or_const {
 +        if ast::AssocItemList::can_cast(
 +            it.syntax().parent().map_or(SyntaxKind::EOF, |it| it.kind()),
 +        ) {
 +            return None;
 +        }
 +    }
 +
 +    if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) {
 +        if ty.lifetime().is_none() {
 +            let t = ty.amp_token()?;
 +            acc.push(InlayHint {
 +                range: t.text_range(),
 +                kind: InlayKind::LifetimeHint,
 +                label: "'static".to_owned().into(),
 +                tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
 +            });
 +        }
 +    }
 +
 +    Some(())
 +}
 +
 +fn fn_lifetime_fn_hints(
 +    acc: &mut Vec<InlayHint>,
 +    config: &InlayHintsConfig,
 +    func: ast::Fn,
 +) -> Option<()> {
 +    if config.lifetime_elision_hints == LifetimeElisionHints::Never {
 +        return None;
 +    }
 +
 +    let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
 +        range: t.text_range(),
 +        kind: InlayKind::LifetimeHint,
 +        label: label.into(),
 +        tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
 +    };
 +
 +    let param_list = func.param_list()?;
 +    let generic_param_list = func.generic_param_list();
 +    let ret_type = func.ret_type();
 +    let self_param = param_list.self_param().filter(|it| it.amp_token().is_some());
 +
 +    let is_elided = |lt: &Option<ast::Lifetime>| match lt {
 +        Some(lt) => matches!(lt.text().as_str(), "'_"),
 +        None => true,
 +    };
 +
 +    let potential_lt_refs = {
 +        let mut acc: Vec<_> = vec![];
 +        if let Some(self_param) = &self_param {
 +            let lifetime = self_param.lifetime();
 +            let is_elided = is_elided(&lifetime);
 +            acc.push((None, self_param.amp_token(), lifetime, is_elided));
 +        }
 +        param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| {
 +            // FIXME: check path types
 +            walk_ty(&ty, &mut |ty| match ty {
 +                ast::Type::RefType(r) => {
 +                    let lifetime = r.lifetime();
 +                    let is_elided = is_elided(&lifetime);
 +                    acc.push((
 +                        pat.as_ref().and_then(|it| match it {
 +                            ast::Pat::IdentPat(p) => p.name(),
 +                            _ => None,
 +                        }),
 +                        r.amp_token(),
 +                        lifetime,
 +                        is_elided,
 +                    ))
 +                }
 +                _ => (),
 +            })
 +        });
 +        acc
 +    };
 +
 +    // allocate names
 +    let mut gen_idx_name = {
 +        let mut gen = (0u8..).map(|idx| match idx {
 +            idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
 +            idx => format!("'{idx}").into(),
 +        });
 +        move || gen.next().unwrap_or_default()
 +    };
 +    let mut allocated_lifetimes = vec![];
 +
 +    let mut used_names: FxHashMap<SmolStr, usize> =
 +        match config.param_names_for_lifetime_elision_hints {
 +            true => generic_param_list
 +                .iter()
 +                .flat_map(|gpl| gpl.lifetime_params())
 +                .filter_map(|param| param.lifetime())
 +                .filter_map(|lt| Some((SmolStr::from(lt.text().as_str().get(1..)?), 0)))
 +                .collect(),
 +            false => Default::default(),
 +        };
 +    {
 +        let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided);
 +        if let Some(_) = &self_param {
 +            if let Some(_) = potential_lt_refs.next() {
 +                allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
 +                    // self can't be used as a lifetime, so no need to check for collisions
 +                    "'self".into()
 +                } else {
 +                    gen_idx_name()
 +                });
 +            }
 +        }
 +        potential_lt_refs.for_each(|(name, ..)| {
 +            let name = match name {
 +                Some(it) if config.param_names_for_lifetime_elision_hints => {
 +                    if let Some(c) = used_names.get_mut(it.text().as_str()) {
 +                        *c += 1;
 +                        SmolStr::from(format!("'{text}{c}", text = it.text().as_str()))
 +                    } else {
 +                        used_names.insert(it.text().as_str().into(), 0);
 +                        SmolStr::from_iter(["\'", it.text().as_str()])
 +                    }
 +                }
 +                _ => gen_idx_name(),
 +            };
 +            allocated_lifetimes.push(name);
 +        });
 +    }
 +
 +    // fetch output lifetime if elision rule applies
 +    let output = match potential_lt_refs.as_slice() {
 +        [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => {
 +            match lifetime {
 +                Some(lt) => match lt.text().as_str() {
 +                    "'_" => allocated_lifetimes.get(0).cloned(),
 +                    "'static" => None,
 +                    name => Some(name.into()),
 +                },
 +                None => allocated_lifetimes.get(0).cloned(),
 +            }
 +        }
 +        [..] => None,
 +    };
 +
 +    if allocated_lifetimes.is_empty() && output.is_none() {
 +        return None;
 +    }
 +
 +    // apply hints
 +    // apply output if required
 +    let mut is_trivial = true;
 +    if let (Some(output_lt), Some(r)) = (&output, ret_type) {
 +        if let Some(ty) = r.ty() {
 +            walk_ty(&ty, &mut |ty| match ty {
 +                ast::Type::RefType(ty) if ty.lifetime().is_none() => {
 +                    if let Some(amp) = ty.amp_token() {
 +                        is_trivial = false;
 +                        acc.push(mk_lt_hint(amp, output_lt.to_string()));
 +                    }
 +                }
 +                _ => (),
 +            })
 +        }
 +    }
 +
 +    if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial {
 +        return None;
 +    }
 +
 +    let mut a = allocated_lifetimes.iter();
 +    for (_, amp_token, _, is_elided) in potential_lt_refs {
 +        if is_elided {
 +            let t = amp_token?;
 +            let lt = a.next()?;
 +            acc.push(mk_lt_hint(t, lt.to_string()));
 +        }
 +    }
 +
 +    // generate generic param list things
 +    match (generic_param_list, allocated_lifetimes.as_slice()) {
 +        (_, []) => (),
 +        (Some(gpl), allocated_lifetimes) => {
 +            let angle_tok = gpl.l_angle_token()?;
 +            let is_empty = gpl.generic_params().next().is_none();
 +            acc.push(InlayHint {
 +                range: angle_tok.text_range(),
 +                kind: InlayKind::LifetimeHint,
 +                label: format!(
 +                    "{}{}",
 +                    allocated_lifetimes.iter().format(", "),
 +                    if is_empty { "" } else { ", " }
 +                )
 +                .into(),
 +                tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
 +            });
 +        }
 +        (None, allocated_lifetimes) => acc.push(InlayHint {
 +            range: func.name()?.syntax().text_range(),
 +            kind: InlayKind::GenericParamListHint,
 +            label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
 +            tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
 +        }),
 +    }
 +    Some(())
 +}
 +
 +fn closure_ret_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    closure: ast::ClosureExpr,
 +) -> Option<()> {
 +    if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
 +        return None;
 +    }
 +
 +    if closure.ret_type().is_some() {
 +        return None;
 +    }
 +
 +    if !closure_has_block_body(&closure)
 +        && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock
 +    {
 +        return None;
 +    }
 +
 +    let param_list = closure.param_list()?;
 +
 +    let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
 +    let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
 +    let callable = ty.as_callable(sema.db)?;
 +    let ty = callable.return_type();
 +    if ty.is_unit() {
 +        return None;
 +    }
 +    acc.push(InlayHint {
 +        range: param_list.syntax().text_range(),
 +        kind: InlayKind::ClosureReturnTypeHint,
 +        label: hint_iterator(sema, &famous_defs, config, &ty)
 +            .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
 +            .into(),
 +        tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
 +    });
 +    Some(())
 +}
 +
 +fn reborrow_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    expr: &ast::Expr,
 +) -> Option<()> {
 +    if config.reborrow_hints == ReborrowHints::Never {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +    let desc_expr = descended.as_ref().unwrap_or(expr);
 +    let mutability = sema.is_implicit_reborrow(desc_expr)?;
 +    let label = match mutability {
 +        hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
 +        hir::Mutability::Mut => "&mut *",
 +        _ => return None,
 +    };
 +    acc.push(InlayHint {
 +        range: expr.syntax().text_range(),
 +        kind: InlayKind::ImplicitReborrowHint,
 +        label: label.to_string().into(),
 +        tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
 +    });
 +    Some(())
 +}
 +
 +fn chaining_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    expr: &ast::Expr,
 +) -> Option<()> {
 +    if !config.chaining_hints {
 +        return None;
 +    }
 +
 +    if matches!(expr, ast::Expr::RecordExpr(_)) {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +    let desc_expr = descended.as_ref().unwrap_or(expr);
 +
 +    let mut tokens = expr
 +        .syntax()
 +        .siblings_with_tokens(Direction::Next)
 +        .filter_map(NodeOrToken::into_token)
 +        .filter(|t| match t.kind() {
 +            SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
 +            SyntaxKind::COMMENT => false,
 +            _ => true,
 +        });
 +
 +    // Chaining can be defined as an expression whose next sibling tokens are newline and dot
 +    // Ignoring extra whitespace and comments
 +    let next = tokens.next()?.kind();
 +    if next == SyntaxKind::WHITESPACE {
 +        let mut next_next = tokens.next()?.kind();
 +        while next_next == SyntaxKind::WHITESPACE {
 +            next_next = tokens.next()?.kind();
 +        }
 +        if next_next == T![.] {
 +            let ty = sema.type_of_expr(desc_expr)?.original;
 +            if ty.is_unknown() {
 +                return None;
 +            }
 +            if matches!(expr, ast::Expr::PathExpr(_)) {
 +                if let Some(hir::Adt::Struct(st)) = ty.as_adt() {
 +                    if st.fields(sema.db).is_empty() {
 +                        return None;
 +                    }
 +                }
 +            }
 +            acc.push(InlayHint {
 +                range: expr.syntax().text_range(),
 +                kind: InlayKind::ChainingHint,
 +                label: hint_iterator(sema, &famous_defs, config, &ty)
 +                    .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
 +                    .into(),
 +                tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
 +            });
 +        }
 +    }
 +    Some(())
 +}
 +
 +fn param_name_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    expr: ast::Expr,
 +) -> Option<()> {
 +    if !config.parameter_hints {
 +        return None;
 +    }
 +
 +    let (callable, arg_list) = get_callable(sema, &expr)?;
 +    let hints = callable
 +        .params(sema.db)
 +        .into_iter()
 +        .zip(arg_list.args())
 +        .filter_map(|((param, _ty), arg)| {
 +            // Only annotate hints for expressions that exist in the original file
 +            let range = sema.original_range_opt(arg.syntax())?;
 +            let (param_name, name_syntax) = match param.as_ref()? {
 +                Either::Left(pat) => ("self".to_string(), pat.name()),
 +                Either::Right(pat) => match pat {
 +                    ast::Pat::IdentPat(it) => (it.name()?.to_string(), it.name()),
 +                    _ => return None,
 +                },
 +            };
 +            Some((name_syntax, param_name, arg, range))
 +        })
 +        .filter(|(_, param_name, arg, _)| {
 +            !should_hide_param_name_hint(sema, &callable, param_name, arg)
 +        })
 +        .map(|(param, param_name, _, FileRange { range, .. })| {
 +            let mut tooltip = None;
 +            if let Some(name) = param {
 +                if let hir::CallableKind::Function(f) = callable.kind() {
 +                    // assert the file is cached so we can map out of macros
 +                    if let Some(_) = sema.source(f) {
 +                        tooltip = sema.original_range_opt(name.syntax());
 +                    }
 +                }
 +            }
 +
 +            InlayHint {
 +                range,
 +                kind: InlayKind::ParameterHint,
 +                label: param_name.into(),
 +                tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
 +            }
 +        });
 +
 +    acc.extend(hints);
 +    Some(())
 +}
 +
 +fn binding_mode_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    pat: &ast::Pat,
 +) -> Option<()> {
 +    if !config.binding_mode_hints {
 +        return None;
 +    }
 +
 +    let range = pat.syntax().text_range();
 +    sema.pattern_adjustments(&pat).iter().for_each(|ty| {
 +        let reference = ty.is_reference();
 +        let mut_reference = ty.is_mutable_reference();
 +        let r = match (reference, mut_reference) {
 +            (true, true) => "&mut",
 +            (true, false) => "&",
 +            _ => return,
 +        };
 +        acc.push(InlayHint {
 +            range,
 +            kind: InlayKind::BindingModeHint,
 +            label: r.to_string().into(),
 +            tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
 +        });
 +    });
 +    match pat {
 +        ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
 +            let bm = sema.binding_mode_of_pat(pat)?;
 +            let bm = match bm {
 +                hir::BindingMode::Move => return None,
 +                hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
 +                hir::BindingMode::Ref(Mutability::Shared) => "ref",
 +            };
 +            acc.push(InlayHint {
 +                range,
 +                kind: InlayKind::BindingModeHint,
 +                label: bm.to_string().into(),
 +                tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
 +            });
 +        }
 +        _ => (),
 +    }
 +
 +    Some(())
 +}
 +
 +fn bind_pat_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    pat: &ast::IdentPat,
 +) -> Option<()> {
 +    if !config.type_hints {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(pat.clone()).pop();
 +    let desc_pat = descended.as_ref().unwrap_or(pat);
 +    let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
 +
 +    if should_not_display_type_hint(sema, config, pat, &ty) {
 +        return None;
 +    }
 +
 +    let krate = sema.scope(desc_pat.syntax())?.krate();
 +    let famous_defs = FamousDefs(sema, krate);
 +    let label = hint_iterator(sema, &famous_defs, config, &ty);
 +
 +    let label = match label {
 +        Some(label) => label,
 +        None => {
 +            let ty_name = ty.display_truncated(sema.db, config.max_length).to_string();
 +            if config.hide_named_constructor_hints
 +                && is_named_constructor(sema, pat, &ty_name).is_some()
 +            {
 +                return None;
 +            }
 +            ty_name
 +        }
 +    };
 +
 +    acc.push(InlayHint {
 +        range: match pat.name() {
 +            Some(name) => name.syntax().text_range(),
 +            None => pat.syntax().text_range(),
 +        },
 +        kind: InlayKind::TypeHint,
 +        label: label.into(),
 +        tooltip: pat
 +            .name()
 +            .map(|it| it.syntax().text_range())
 +            .map(|it| InlayTooltip::HoverRanged(file_id, it)),
 +    });
 +
 +    Some(())
 +}
 +
 +fn is_named_constructor(
 +    sema: &Semantics<'_, RootDatabase>,
 +    pat: &ast::IdentPat,
 +    ty_name: &str,
 +) -> Option<()> {
 +    let let_node = pat.syntax().parent()?;
 +    let expr = match_ast! {
 +        match let_node {
 +            ast::LetStmt(it) => it.initializer(),
 +            ast::LetExpr(it) => it.expr(),
 +            _ => None,
 +        }
 +    }?;
 +
 +    let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
 +    // unwrap postfix expressions
 +    let expr = match expr {
 +        ast::Expr::TryExpr(it) => it.expr(),
 +        ast::Expr::AwaitExpr(it) => it.expr(),
 +        expr => Some(expr),
 +    }?;
 +    let expr = match expr {
 +        ast::Expr::CallExpr(call) => match call.expr()? {
 +            ast::Expr::PathExpr(path) => path,
 +            _ => return None,
 +        },
 +        ast::Expr::PathExpr(path) => path,
 +        _ => return None,
 +    };
 +    let path = expr.path()?;
 +
 +    let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db);
 +    let callable_kind = callable.map(|it| it.kind());
 +    let qual_seg = match callable_kind {
 +        Some(hir::CallableKind::Function(_) | hir::CallableKind::TupleEnumVariant(_)) => {
 +            path.qualifier()?.segment()
 +        }
 +        _ => path.segment(),
 +    }?;
 +
 +    let ctor_name = match qual_seg.kind()? {
 +        ast::PathSegmentKind::Name(name_ref) => {
 +            match qual_seg.generic_arg_list().map(|it| it.generic_args()) {
 +                Some(generics) => format!("{}<{}>", name_ref, generics.format(", ")),
 +                None => name_ref.to_string(),
 +            }
 +        }
 +        ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(),
 +        _ => return None,
 +    };
 +    (ctor_name == ty_name).then(|| ())
 +}
 +
 +/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
 +fn hint_iterator(
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    ty: &hir::Type,
 +) -> Option<String> {
 +    let db = sema.db;
 +    let strukt = ty.strip_references().as_adt()?;
 +    let krate = strukt.module(db).krate();
 +    if krate != famous_defs.core()? {
 +        return None;
 +    }
 +    let iter_trait = famous_defs.core_iter_Iterator()?;
 +    let iter_mod = famous_defs.core_iter()?;
 +
 +    // Assert that this struct comes from `core::iter`.
 +    if !(strukt.visibility(db) == hir::Visibility::Public
 +        && strukt.module(db).path_to_root(db).contains(&iter_mod))
 +    {
 +        return None;
 +    }
 +
 +    if ty.impls_trait(db, iter_trait, &[]) {
 +        let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
 +            hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
 +            _ => None,
 +        })?;
 +        if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
 +            const LABEL_START: &str = "impl Iterator<Item = ";
 +            const LABEL_END: &str = ">";
 +
 +            let ty_display = hint_iterator(sema, famous_defs, config, &ty)
 +                .map(|assoc_type_impl| assoc_type_impl.to_string())
 +                .unwrap_or_else(|| {
 +                    ty.display_truncated(
 +                        db,
 +                        config
 +                            .max_length
 +                            .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
 +                    )
 +                    .to_string()
 +                });
 +            return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END));
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool {
 +    if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() {
 +        let pat_text = bind_pat.to_string();
 +        enum_data
 +            .variants(db)
 +            .into_iter()
 +            .map(|variant| variant.name(db).to_smol_str())
 +            .any(|enum_name| enum_name == pat_text)
 +    } else {
 +        false
 +    }
 +}
 +
 +fn should_not_display_type_hint(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    bind_pat: &ast::IdentPat,
 +    pat_ty: &hir::Type,
 +) -> bool {
 +    let db = sema.db;
 +
 +    if pat_ty.is_unknown() {
 +        return true;
 +    }
 +
 +    if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() {
 +        if s.fields(db).is_empty() && s.name(db).to_smol_str() == bind_pat.to_string() {
 +            return true;
 +        }
 +    }
 +
 +    if config.hide_closure_initialization_hints {
 +        if let Some(parent) = bind_pat.syntax().parent() {
 +            if let Some(it) = ast::LetStmt::cast(parent.clone()) {
 +                if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
 +                    if closure_has_block_body(&closure) {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    for node in bind_pat.syntax().ancestors() {
 +        match_ast! {
 +            match node {
 +                ast::LetStmt(it) => return it.ty().is_some(),
 +                // FIXME: We might wanna show type hints in parameters for non-top level patterns as well
 +                ast::Param(it) => return it.ty().is_some(),
 +                ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
 +                ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
 +                ast::IfExpr(_) => return false,
 +                ast::WhileExpr(_) => return false,
 +                ast::ForExpr(it) => {
 +                    // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
 +                    // Type of expr should be iterable.
 +                    return it.in_token().is_none() ||
 +                        it.iterable()
 +                            .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
 +                            .map(TypeInfo::original)
 +                            .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
 +    matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
 +}
 +
 +fn should_hide_param_name_hint(
 +    sema: &Semantics<'_, RootDatabase>,
 +    callable: &hir::Callable,
 +    param_name: &str,
 +    argument: &ast::Expr,
 +) -> bool {
 +    // These are to be tested in the `parameter_hint_heuristics` test
 +    // hide when:
 +    // - the parameter name is a suffix of the function's name
 +    // - the argument is a qualified constructing or call expression where the qualifier is an ADT
 +    // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
 +    //   of argument with _ splitting it off
 +    // - param starts with `ra_fixture`
 +    // - param is a well known name in a unary function
 +
 +    let param_name = param_name.trim_start_matches('_');
 +    if param_name.is_empty() {
 +        return true;
 +    }
 +
 +    if matches!(argument, ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(UnaryOp::Not)) {
 +        return false;
 +    }
 +
 +    let fn_name = match callable.kind() {
 +        hir::CallableKind::Function(it) => Some(it.name(sema.db).to_smol_str()),
 +        _ => None,
 +    };
 +    let fn_name = fn_name.as_deref();
 +    is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
 +        || is_argument_similar_to_param_name(argument, param_name)
 +        || param_name.starts_with("ra_fixture")
 +        || (callable.n_params() == 1 && is_obvious_param(param_name))
 +        || is_adt_constructor_similar_to_param_name(sema, argument, param_name)
 +}
 +
 +fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
 +    // check whether param_name and argument are the same or
 +    // whether param_name is a prefix/suffix of argument(split at `_`)
 +    let argument = match get_string_representation(argument) {
 +        Some(argument) => argument,
 +        None => return false,
 +    };
 +
 +    // std is honestly too panic happy...
 +    let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at));
 +
 +    let param_name = param_name.trim_start_matches('_');
 +    let argument = argument.trim_start_matches('_');
 +
 +    match str_split_at(argument, param_name.len()) {
 +        Some((prefix, rest)) if prefix.eq_ignore_ascii_case(param_name) => {
 +            return rest.is_empty() || rest.starts_with('_');
 +        }
 +        _ => (),
 +    }
 +    match argument.len().checked_sub(param_name.len()).and_then(|at| str_split_at(argument, at)) {
 +        Some((rest, suffix)) if param_name.eq_ignore_ascii_case(suffix) => {
 +            return rest.is_empty() || rest.ends_with('_');
 +        }
 +        _ => (),
 +    }
 +    false
 +}
 +
 +/// Hide the parameter name of a unary function if it is a `_` - prefixed suffix of the function's name, or equal.
 +///
 +/// `fn strip_suffix(suffix)` will be hidden.
 +/// `fn stripsuffix(suffix)` will not be hidden.
 +fn is_param_name_suffix_of_fn_name(
 +    param_name: &str,
 +    callable: &Callable,
 +    fn_name: Option<&str>,
 +) -> bool {
 +    match (callable.n_params(), fn_name) {
 +        (1, Some(function)) => {
 +            function == param_name
 +                || function
 +                    .len()
 +                    .checked_sub(param_name.len())
 +                    .and_then(|at| function.is_char_boundary(at).then(|| function.split_at(at)))
 +                    .map_or(false, |(prefix, suffix)| {
 +                        suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_')
 +                    })
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn is_adt_constructor_similar_to_param_name(
 +    sema: &Semantics<'_, RootDatabase>,
 +    argument: &ast::Expr,
 +    param_name: &str,
 +) -> bool {
 +    let path = match argument {
 +        ast::Expr::CallExpr(c) => c.expr().and_then(|e| match e {
 +            ast::Expr::PathExpr(p) => p.path(),
 +            _ => None,
 +        }),
 +        ast::Expr::PathExpr(p) => p.path(),
 +        ast::Expr::RecordExpr(r) => r.path(),
 +        _ => return false,
 +    };
 +    let path = match path {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +    (|| match sema.resolve_path(&path)? {
 +        hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => {
 +            Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name)
 +        }
 +        hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::Variant(_)) => {
 +            if to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name {
 +                return Some(true);
 +            }
 +            let qual = path.qualifier()?;
 +            match sema.resolve_path(&qual)? {
 +                hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => {
 +                    Some(to_lower_snake_case(&qual.segment()?.name_ref()?.text()) == param_name)
 +                }
 +                _ => None,
 +            }
 +        }
 +        _ => None,
 +    })()
 +    .unwrap_or(false)
 +}
 +
 +fn get_string_representation(expr: &ast::Expr) -> Option<String> {
 +    match expr {
 +        ast::Expr::MethodCallExpr(method_call_expr) => {
 +            let name_ref = method_call_expr.name_ref()?;
 +            match name_ref.text().as_str() {
 +                "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
 +                name_ref => Some(name_ref.to_owned()),
 +            }
 +        }
 +        ast::Expr::MacroExpr(macro_expr) => {
 +            Some(macro_expr.macro_call()?.path()?.segment()?.to_string())
 +        }
 +        ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
 +        ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
 +        ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
 +        ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
 +        ast::Expr::CastExpr(cast_expr) => get_string_representation(&cast_expr.expr()?),
 +        _ => None,
 +    }
 +}
 +
 +fn is_obvious_param(param_name: &str) -> bool {
 +    // avoid displaying hints for common functions like map, filter, etc.
 +    // or other obvious words used in std
 +    let is_obvious_param_name =
 +        matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
 +    param_name.len() == 1 || is_obvious_param_name
 +}
 +
 +fn get_callable(
 +    sema: &Semantics<'_, RootDatabase>,
 +    expr: &ast::Expr,
 +) -> Option<(hir::Callable, ast::ArgList)> {
 +    match expr {
 +        ast::Expr::CallExpr(expr) => {
 +            let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +            let expr = descended.as_ref().unwrap_or(expr);
 +            sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list())
 +        }
 +        ast::Expr::MethodCallExpr(expr) => {
 +            let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +            let expr = descended.as_ref().unwrap_or(expr);
 +            sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())
 +        }
 +        _ => None,
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +    use ide_db::base_db::FileRange;
 +    use itertools::Itertools;
 +    use syntax::{TextRange, TextSize};
 +    use test_utils::extract_annotations;
 +
 +    use crate::inlay_hints::ReborrowHints;
 +    use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 +
 +    use super::ClosureReturnTypeHints;
 +
 +    const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
 +        render_colons: false,
 +        type_hints: false,
 +        parameter_hints: false,
 +        chaining_hints: false,
 +        lifetime_elision_hints: LifetimeElisionHints::Never,
 +        closure_return_type_hints: ClosureReturnTypeHints::Never,
 +        reborrow_hints: ReborrowHints::Always,
 +        binding_mode_hints: false,
 +        hide_named_constructor_hints: false,
 +        hide_closure_initialization_hints: false,
 +        param_names_for_lifetime_elision_hints: false,
 +        max_length: None,
 +        closing_brace_hints_min_lines: None,
 +    };
 +    const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
 +        type_hints: true,
 +        parameter_hints: true,
 +        chaining_hints: true,
 +        reborrow_hints: ReborrowHints::Always,
 +        closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
 +        binding_mode_hints: true,
 +        lifetime_elision_hints: LifetimeElisionHints::Always,
 +        ..DISABLED_CONFIG
 +    };
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str) {
 +        check_with_config(TEST_CONFIG, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_params(ra_fixture: &str) {
 +        check_with_config(
 +            InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG },
 +            ra_fixture,
 +        );
 +    }
 +
 +    #[track_caller]
 +    fn check_types(ra_fixture: &str) {
 +        check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_chains(ra_fixture: &str) {
 +        check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
 +        let (analysis, file_id) = fixture::file(ra_fixture);
 +        let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
 +        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 +        let actual = inlay_hints
 +            .into_iter()
 +            .map(|it| (it.range, it.label.to_string()))
 +            .sorted_by_key(|(range, _)| range.start())
 +            .collect::<Vec<_>>();
 +        expected.sort_by_key(|(range, _)| range.start());
 +
 +        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
 +        let (analysis, file_id) = fixture::file(ra_fixture);
 +        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 +        expect.assert_debug_eq(&inlay_hints)
 +    }
 +
 +    #[test]
 +    fn hints_disabled() {
 +        check_with_config(
 +            InlayHintsConfig { render_colons: true, ..DISABLED_CONFIG },
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(4, 4);
 +}"#,
 +        );
 +    }
 +
 +    // Parameter hint tests
 +
 +    #[test]
 +    fn param_hints_only() {
 +        check_params(
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(
 +        4,
 +      //^ a
 +        4,
 +      //^ b
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_hints_on_closure() {
 +        check_params(
 +            r#"
 +fn main() {
 +    let clo = |a: u8, b: u8| a + b;
 +    clo(
 +        1,
 +      //^ a
 +        2,
 +      //^ b
 +    );
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_similar_to_fn_name_still_hints() {
 +        check_params(
 +            r#"
 +fn max(x: i32, y: i32) -> i32 { x + y }
 +fn main() {
 +    let _x = max(
 +        4,
 +      //^ x
 +        4,
 +      //^ y
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_similar_to_fn_name() {
 +        check_params(
 +            r#"
 +fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
 +fn main() {
 +    let _x = param_with_underscore(
 +        4,
 +    );
 +}"#,
 +        );
 +        check_params(
 +            r#"
 +fn param_with_underscore(underscore: i32) -> i32 { underscore }
 +fn main() {
 +    let _x = param_with_underscore(
 +        4,
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_same_as_fn_name() {
 +        check_params(
 +            r#"
 +fn foo(foo: i32) -> i32 { foo }
 +fn main() {
 +    let _x = foo(
 +        4,
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn never_hide_param_when_multiple_params() {
 +        check_params(
 +            r#"
 +fn foo(foo: i32, bar: i32) -> i32 { bar + baz }
 +fn main() {
 +    let _x = foo(
 +        4,
 +      //^ foo
 +        8,
 +      //^ bar
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_hints_look_through_as_ref_and_clone() {
 +        check_params(
 +            r#"
 +fn foo(bar: i32, baz: f32) {}
 +
 +fn main() {
 +    let bar = 3;
 +    let baz = &"baz";
 +    let fez = 1.0;
 +    foo(bar.clone(), bar.clone());
 +                   //^^^^^^^^^^^ baz
 +    foo(bar.as_ref(), bar.as_ref());
 +                    //^^^^^^^^^^^^ baz
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn self_param_hints() {
 +        check_params(
 +            r#"
 +struct Foo;
 +
 +impl Foo {
 +    fn foo(self: Self) {}
 +    fn bar(self: &Self) {}
 +}
 +
 +fn main() {
 +    Foo::foo(Foo);
 +           //^^^ self
 +    Foo::bar(&Foo);
 +           //^^^^ self
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn param_name_hints_show_for_literals() {
 +        check_params(
 +            r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
 +fn main() {
 +    test(
 +        0xa_b,
 +      //^^^^^ a
 +        0xa_b,
 +      //^^^^^ b
 +    );
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn function_call_parameter_hint() {
 +        check_params(
 +            r#"
 +//- minicore: option
 +struct FileId {}
 +struct SmolStr {}
 +
 +struct TextRange {}
 +struct SyntaxKind {}
 +struct NavigationTarget {}
 +
 +struct Test {}
 +
 +impl Test {
 +    fn method(&self, mut param: i32) -> i32 { param * 2 }
 +
 +    fn from_syntax(
 +        file_id: FileId,
 +        name: SmolStr,
 +        focus_range: Option<TextRange>,
 +        full_range: TextRange,
 +        kind: SyntaxKind,
 +        docs: Option<String>,
 +    ) -> NavigationTarget {
 +        NavigationTarget {}
 +    }
 +}
 +
 +fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
 +    foo + bar
 +}
 +
 +fn main() {
 +    let not_literal = 1;
 +    let _: i32 = test_func(1,    2,      "hello", 3,  not_literal);
 +                         //^ foo ^ bar   ^^^^^^^ msg  ^^^^^^^^^^^ last
 +    let t: Test = Test {};
 +    t.method(123);
 +           //^^^ param
 +    Test::method(&t,      3456);
 +               //^^ self  ^^^^ param
 +    Test::from_syntax(
 +        FileId {},
 +        "impl".into(),
 +      //^^^^^^^^^^^^^ name
 +        None,
 +      //^^^^ focus_range
 +        TextRange {},
 +      //^^^^^^^^^^^^ full_range
 +        SyntaxKind {},
 +      //^^^^^^^^^^^^^ kind
 +        None,
 +      //^^^^ docs
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn parameter_hint_heuristics() {
 +        check_params(
 +            r#"
 +fn check(ra_fixture_thing: &str) {}
 +
 +fn map(f: i32) {}
 +fn filter(predicate: i32) {}
 +
 +fn strip_suffix(suffix: &str) {}
 +fn stripsuffix(suffix: &str) {}
 +fn same(same: u32) {}
 +fn same2(_same2: u32) {}
 +
 +fn enum_matches_param_name(completion_kind: CompletionKind) {}
 +
 +fn foo(param: u32) {}
 +fn bar(param_eter: u32) {}
 +
 +enum CompletionKind {
 +    Keyword,
 +}
 +
 +fn non_ident_pat((a, b): (u32, u32)) {}
 +
 +fn main() {
 +    const PARAM: u32 = 0;
 +    foo(PARAM);
 +    foo(!PARAM);
 +     // ^^^^^^ param
 +    check("");
 +
 +    map(0);
 +    filter(0);
 +
 +    strip_suffix("");
 +    stripsuffix("");
 +              //^^ suffix
 +    same(0);
 +    same2(0);
 +
 +    enum_matches_param_name(CompletionKind::Keyword);
 +
 +    let param = 0;
 +    foo(param);
 +    foo(param as _);
 +    let param_end = 0;
 +    foo(param_end);
 +    let start_param = 0;
 +    foo(start_param);
 +    let param2 = 0;
 +    foo(param2);
 +      //^^^^^^ param
 +
 +    macro_rules! param {
 +        () => {};
 +    };
 +    foo(param!());
 +
 +    let param_eter = 0;
 +    bar(param_eter);
 +    let param_eter_end = 0;
 +    bar(param_eter_end);
 +    let start_param_eter = 0;
 +    bar(start_param_eter);
 +    let param_eter2 = 0;
 +    bar(param_eter2);
 +      //^^^^^^^^^^^ param_eter
 +
 +    non_ident_pat((0, 0));
 +}"#,
 +        );
 +    }
 +
 +    // Type-Hint tests
 +
 +    #[test]
 +    fn type_hints_only() {
 +        check_types(
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(4, 4);
 +      //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn type_hints_bindings_after_at() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +fn main() {
 +    let ref foo @ bar @ ref mut baz = 0;
 +          //^^^ &i32
 +                //^^^ i32
 +                              //^^^ &mut i32
 +    let [x @ ..] = [0];
 +       //^ [i32; 1]
 +    if let x @ Some(_) = Some(0) {}
 +         //^ Option<i32>
 +    let foo @ (bar, baz) = (3, 3);
 +      //^^^ (i32, i32)
 +             //^^^ i32
 +                  //^^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn default_generic_types_should_not_be_displayed() {
 +        check(
 +            r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let zz = Test { t: 23u8, k: 33 };
 +      //^^ Test<i32>
 +    let zz_ref = &zz;
 +      //^^^^^^ &Test<i32>
 +    let test = || zz;
 +      //^^^^ || -> Test<i32>
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterators_in_associated_params() {
 +        check_types(
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +pub struct SomeIter<T> {}
 +
 +impl<T> SomeIter<T> {
 +    pub fn new() -> Self { SomeIter {} }
 +    pub fn push(&mut self, t: T) {}
 +}
 +
 +impl<T> Iterator for SomeIter<T> {
 +    type Item = T;
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let mut some_iter = SomeIter::new();
 +          //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
 +      some_iter.push(iter::repeat(2).take(2));
 +    let iter_of_iters = some_iter.take(2);
 +      //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
 +}
 +"#,
 +        );
 +    }
 +
++    #[test]
++    fn iterator_hint_regression_issue_12674() {
++        // Ensure we don't crash while solving the projection type of iterators.
++        check_expect(
++            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
++            r#"
++//- minicore: iterators
++struct S<T>(T);
++impl<T> S<T> {
++    fn iter(&self) -> Iter<'_, T> { loop {} }
++}
++struct Iter<'a, T: 'a>(&'a T);
++impl<'a, T> Iterator for Iter<'a, T> {
++    type Item = &'a T;
++    fn next(&mut self) -> Option<Self::Item> { loop {} }
++}
++struct Container<'a> {
++    elements: S<&'a str>,
++}
++struct SliceIter<'a, T>(&'a T);
++impl<'a, T> Iterator for SliceIter<'a, T> {
++    type Item = &'a T;
++    fn next(&mut self) -> Option<Self::Item> { loop {} }
++}
++
++fn main(a: SliceIter<'_, Container>) {
++    a
++    .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
++    .map(|e| e);
++}
++            "#,
++            expect![[r#"
++                [
++                    InlayHint {
++                        range: 484..554,
++                        kind: ChainingHint,
++                        label: [
++                            "impl Iterator<Item = impl Iterator<Item = &&str>>",
++                        ],
++                        tooltip: Some(
++                            HoverRanged(
++                                FileId(
++                                    0,
++                                ),
++                                484..554,
++                            ),
++                        ),
++                    },
++                    InlayHint {
++                        range: 484..485,
++                        kind: ChainingHint,
++                        label: [
++                            "SliceIter<Container>",
++                        ],
++                        tooltip: Some(
++                            HoverRanged(
++                                FileId(
++                                    0,
++                                ),
++                                484..485,
++                            ),
++                        ),
++                    },
++                ]
++            "#]],
++        );
++    }
++
 +    #[test]
 +    fn infer_call_method_return_associated_types_with_generic() {
 +        check_types(
 +            r#"
 +            pub trait Default {
 +                fn default() -> Self;
 +            }
 +            pub trait Foo {
 +                type Bar: Default;
 +            }
 +
 +            pub fn quux<T: Foo>() -> T::Bar {
 +                let y = Default::default();
 +                  //^ <T as Foo>::Bar
 +
 +                y
 +            }
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fn_hints() {
 +        check_types(
 +            r#"
 +//- minicore: fn, sized
 +fn foo() -> impl Fn() { loop {} }
 +fn foo1() -> impl Fn(f64) { loop {} }
 +fn foo2() -> impl Fn(f64, f64) { loop {} }
 +fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 +fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
 +fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 +fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 +fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 +
 +fn main() {
 +    let foo = foo();
 +     // ^^^ impl Fn()
 +    let foo = foo1();
 +     // ^^^ impl Fn(f64)
 +    let foo = foo2();
 +     // ^^^ impl Fn(f64, f64)
 +    let foo = foo3();
 +     // ^^^ impl Fn(f64, f64) -> u32
 +    let foo = foo4();
 +     // ^^^ &dyn Fn(f64, f64) -> u32
 +    let foo = foo5();
 +     // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
 +    let foo = foo6();
 +     // ^^^ impl Fn(f64, f64) -> u32
 +    let foo = foo7();
 +     // ^^^ *const impl Fn(f64, f64) -> u32
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn check_hint_range_limit() {
 +        let fixture = r#"
 +        //- minicore: fn, sized
 +        fn foo() -> impl Fn() { loop {} }
 +        fn foo1() -> impl Fn(f64) { loop {} }
 +        fn foo2() -> impl Fn(f64, f64) { loop {} }
 +        fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 +        fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
 +        fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 +        fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 +        fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 +
 +        fn main() {
 +            let foo = foo();
 +            let foo = foo1();
 +            let foo = foo2();
 +             // ^^^ impl Fn(f64, f64)
 +            let foo = foo3();
 +             // ^^^ impl Fn(f64, f64) -> u32
 +            let foo = foo4();
 +            let foo = foo5();
 +            let foo = foo6();
 +            let foo = foo7();
 +        }
 +        "#;
 +        let (analysis, file_id) = fixture::file(fixture);
 +        let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
 +        let inlay_hints = analysis
 +            .inlay_hints(
 +                &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
 +                file_id,
 +                Some(FileRange {
 +                    file_id,
 +                    range: TextRange::new(TextSize::from(500), TextSize::from(600)),
 +                }),
 +            )
 +            .unwrap();
 +        let actual =
 +            inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
 +        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
 +    }
 +
 +    #[test]
 +    fn fn_hints_ptr_rpit_fn_parentheses() {
 +        check_types(
 +            r#"
 +//- minicore: fn, sized
 +trait Trait {}
 +
 +fn foo1() -> *const impl Fn() { loop {} }
 +fn foo2() -> *const (impl Fn() + Sized) { loop {} }
 +fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
 +fn foo4() -> *const (impl Sized + Fn()) { loop {} }
 +fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
 +fn foo6() -> *const (impl Fn() + Trait) { loop {} }
 +fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
 +fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
 +fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
 +fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
 +
 +fn main() {
 +    let foo = foo1();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo2();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo3();
 +    //  ^^^ *const (impl Fn() + ?Sized)
 +    let foo = foo4();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo5();
 +    //  ^^^ *const (impl Fn() + ?Sized)
 +    let foo = foo6();
 +    //  ^^^ *const (impl Fn() + Trait)
 +    let foo = foo7();
 +    //  ^^^ *const (impl Fn() + Trait)
 +    let foo = foo8();
 +    //  ^^^ *const (impl Fn() + Trait + ?Sized)
 +    let foo = foo9();
 +    //  ^^^ *const (impl Fn() -> u8 + ?Sized)
 +    let foo = foo10();
 +    //  ^^^ *const impl Fn()
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn unit_structs_have_no_type_hints() {
 +        check_types(
 +            r#"
 +//- minicore: result
 +struct SyntheticSyntax;
 +
 +fn main() {
 +    match Ok(()) {
 +        Ok(_) => (),
 +        Err(SyntheticSyntax) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn let_statement() {
 +        check_types(
 +            r#"
 +#[derive(PartialEq)]
 +enum Option<T> { None, Some(T) }
 +
 +#[derive(PartialEq)]
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    struct InnerStruct {}
 +
 +    let test = 54;
 +      //^^^^ i32
 +    let test: i32 = 33;
 +    let mut test = 33;
 +          //^^^^ i32
 +    let _ = 22;
 +    let test = "test";
 +      //^^^^ &str
 +    let test = InnerStruct {};
 +      //^^^^ InnerStruct
 +
 +    let test = unresolved();
 +
 +    let test = (42, 'a');
 +      //^^^^ (i32, char)
 +    let (a,    (b,     (c,)) = (2, (3, (9.2,));
 +       //^ i32  ^ i32   ^ f64
 +    let &x = &92;
 +       //^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn if_expr() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    let test = Some(Test { a: Some(3), b: 1 });
 +      //^^^^ Option<Test>
 +    if let None = &test {};
 +    if let test = &test {};
 +         //^^^^ &Option<Test>
 +    if let Some(test) = &test {};
 +              //^^^^ &Test
 +    if let Some(Test { a,             b }) = &test {};
 +                     //^ &Option<u32> ^ &u8
 +    if let Some(Test { a: x,             b: y }) = &test {};
 +                        //^ &Option<u32>    ^ &u8
 +    if let Some(Test { a: Some(x),  b: y }) = &test {};
 +                             //^ &u32  ^ &u8
 +    if let Some(Test { a: None,  b: y }) = &test {};
 +                                  //^ &u8
 +    if let Some(Test { b: y, .. }) = &test {};
 +                        //^ &u8
 +    if test == None {}
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn while_expr() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    let test = Some(Test { a: Some(3), b: 1 });
 +      //^^^^ Option<Test>
 +    while let Some(Test { a: Some(x),  b: y }) = &test {};
 +                                //^ &u32  ^ &u8
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_arm_list() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    match Some(Test { a: Some(3), b: 1 }) {
 +        None => (),
 +        test => (),
 +      //^^^^ Option<Test>
 +        Some(Test { a: Some(x), b: y }) => (),
 +                          //^ u32  ^ u8
 +        _ => {}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn complete_for_hint() {
 +        check_types(
 +            r#"
 +//- minicore: iterator
 +pub struct Vec<T> {}
 +
 +impl<T> Vec<T> {
 +    pub fn new() -> Self { Vec {} }
 +    pub fn push(&mut self, t: T) {}
 +}
 +
 +impl<T> IntoIterator for Vec<T> {
 +    type Item=T;
 +}
 +
 +fn main() {
 +    let mut data = Vec::new();
 +          //^^^^ Vec<&str>
 +    data.push("foo");
 +    for i in data {
 +      //^ &str
 +      let z = i;
 +        //^ &str
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn multi_dyn_trait_bounds() {
 +        check_types(
 +            r#"
 +pub struct Vec<T> {}
 +
 +impl<T> Vec<T> {
 +    pub fn new() -> Self { Vec {} }
 +}
 +
 +pub struct Box<T> {}
 +
 +trait Display {}
 +auto trait Sync {}
 +
 +fn main() {
 +    // The block expression wrapping disables the constructor hint hiding logic
 +    let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
 +      //^^ Vec<Box<&(dyn Display + Sync)>>
 +    let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
 +      //^^ Vec<Box<*const (dyn Display + Sync)>>
 +    let _v = { Vec::<Box<dyn Display + Sync>>::new() };
 +      //^^ Vec<Box<dyn Display + Sync>>
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterator_hints() {
 +        check_types(
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +struct MyIter;
 +
 +impl Iterator for MyIter {
 +    type Item = ();
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let _x = MyIter;
 +      //^^ MyIter
 +    let _x = iter::repeat(0);
 +      //^^ impl Iterator<Item = i32>
 +    fn generic<T: Clone>(t: T) {
 +        let _x = iter::repeat(t);
 +          //^^ impl Iterator<Item = T>
 +        let _chained = iter::repeat(t).take(10);
 +          //^^^^^^^^ impl Iterator<Item = T>
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn skip_constructor_and_enum_type_hints() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                type_hints: true,
 +                hide_named_constructor_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +//- minicore: try, option
 +use core::ops::ControlFlow;
 +
 +mod x {
 +    pub mod y { pub struct Foo; }
 +    pub struct Foo;
 +    pub enum AnotherEnum {
 +        Variant()
 +    };
 +}
 +struct Struct;
 +struct TupleStruct();
 +
 +impl Struct {
 +    fn new() -> Self {
 +        Struct
 +    }
 +    fn try_new() -> ControlFlow<(), Self> {
 +        ControlFlow::Continue(Struct)
 +    }
 +}
 +
 +struct Generic<T>(T);
 +impl Generic<i32> {
 +    fn new() -> Self {
 +        Generic(0)
 +    }
 +}
 +
 +enum Enum {
 +    Variant(u32)
 +}
 +
 +fn times2(value: i32) -> i32 {
 +    2 * value
 +}
 +
 +fn main() {
 +    let enumb = Enum::Variant(0);
 +
 +    let strukt = x::Foo;
 +    let strukt = x::y::Foo;
 +    let strukt = Struct;
 +    let strukt = Struct::new();
 +
 +    let tuple_struct = TupleStruct();
 +
 +    let generic0 = Generic::new();
 +    //  ^^^^^^^^ Generic<i32>
 +    let generic1 = Generic(0);
 +    //  ^^^^^^^^ Generic<i32>
 +    let generic2 = Generic::<i32>::new();
 +    let generic3 = <Generic<i32>>::new();
 +    let generic4 = Generic::<i32>(0);
 +
 +
 +    let option = Some(0);
 +    //  ^^^^^^ Option<i32>
 +    let func = times2;
 +    //  ^^^^ fn times2(i32) -> i32
 +    let closure = |x: i32| x * 2;
 +    //  ^^^^^^^ |i32| -> i32
 +}
 +
 +fn fallible() -> ControlFlow<()> {
 +    let strukt = Struct::try_new()?;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shows_constructor_type_hints_when_enabled() {
 +        check_types(
 +            r#"
 +//- minicore: try
 +use core::ops::ControlFlow;
 +
 +struct Struct;
 +struct TupleStruct();
 +
 +impl Struct {
 +    fn new() -> Self {
 +        Struct
 +    }
 +    fn try_new() -> ControlFlow<(), Self> {
 +        ControlFlow::Continue(Struct)
 +    }
 +}
 +
 +struct Generic<T>(T);
 +impl Generic<i32> {
 +    fn new() -> Self {
 +        Generic(0)
 +    }
 +}
 +
 +fn main() {
 +    let strukt = Struct::new();
 +     // ^^^^^^ Struct
 +    let tuple_struct = TupleStruct();
 +     // ^^^^^^^^^^^^ TupleStruct
 +    let generic0 = Generic::new();
 +     // ^^^^^^^^ Generic<i32>
 +    let generic1 = Generic::<i32>::new();
 +     // ^^^^^^^^ Generic<i32>
 +    let generic2 = <Generic<i32>>::new();
 +     // ^^^^^^^^ Generic<i32>
 +}
 +
 +fn fallible() -> ControlFlow<()> {
 +    let strukt = Struct::try_new()?;
 +     // ^^^^^^ Struct
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn closures() {
 +        check(
 +            r#"
 +fn main() {
 +    let mut start = 0;
 +          //^^^^^ i32
 +    (0..2).for_each(|increment      | { start += increment; });
 +                   //^^^^^^^^^ i32
 +
 +    let multiply =
 +      //^^^^^^^^ |i32, i32| -> i32
 +      | a,     b| a * b
 +      //^ i32  ^ i32
 +
 +    ;
 +
 +    let _: i32 = multiply(1,  2);
 +                        //^ a ^ b
 +    let multiply_ref = &multiply;
 +      //^^^^^^^^^^^^ &|i32, i32| -> i32
 +
 +    let return_42 = || 42;
 +      //^^^^^^^^^ || -> i32
 +      || { 42 };
 +    //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_type_hints_for_closure_without_block() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                closure_return_type_hints: ClosureReturnTypeHints::Always,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +fn main() {
 +    let a = || { 0 };
 +          //^^ i32
 +    let b = || 0;
 +          //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn skip_closure_type_hints() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                type_hints: true,
 +                hide_closure_initialization_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +//- minicore: fn
 +fn main() {
 +    let multiple_2 = |x: i32| { x * 2 };
 +
 +    let multiple_2 = |x: i32| x * 2;
 +    //  ^^^^^^^^^^ |i32| -> i32
 +
 +    let (not) = (|x: bool| { !x });
 +    //   ^^^ |bool| -> bool
 +
 +    let (is_zero, _b) = (|x: usize| { x == 0 }, false);
 +    //   ^^^^^^^ |usize| -> bool
 +    //            ^^ bool
 +
 +    let plus_one = |x| { x + 1 };
 +    //              ^ u8
 +    foo(plus_one);
 +
 +    let add_mul = bar(|x: u8| { x + 1 });
 +    //  ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
 +
 +    let closure = if let Some(6) = add_mul(2).checked_sub(1) {
 +    //  ^^^^^^^ fn(i32) -> i32
 +        |x: i32| { x * 2 }
 +    } else {
 +        |x: i32| { x * 3 }
 +    };
 +}
 +
 +fn foo(f: impl FnOnce(u8) -> u8) {}
 +
 +fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
 +    move |x: u8| f(x) * 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hint_truncation() {
 +        check_with_config(
 +            InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
 +            r#"
 +struct Smol<T>(T);
 +
 +struct VeryLongOuterName<T>(T);
 +
 +fn main() {
 +    let a = Smol(0u32);
 +      //^ Smol<u32>
 +    let b = VeryLongOuterName(0usize);
 +      //^ VeryLongOuterName<…>
 +    let c = Smol(Smol(0u32))
 +      //^ Smol<Smol<…>>
 +}"#,
 +        );
 +    }
 +
 +    // Chaining hint tests
 +
 +    #[test]
 +    fn chaining_hints_ignore_comments() {
 +        check_expect(
 +            InlayHintsConfig { type_hints: false, chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A(B);
 +impl A { fn into_b(self) -> B { self.0 } }
 +struct B(C);
 +impl B { fn into_c(self) -> C { self.0 } }
 +struct C;
 +
 +fn main() {
 +    let c = A(B(C))
 +        .into_b() // This is a comment
 +        // This is another comment
 +        .into_c();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 147..172,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "B",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                147..172,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 147..154,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "A",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                147..154,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn chaining_hints_without_newlines() {
 +        check_chains(
 +            r#"
 +struct A(B);
 +impl A { fn into_b(self) -> B { self.0 } }
 +struct B(C);
 +impl B { fn into_c(self) -> C { self.0 } }
 +struct C;
 +
 +fn main() {
 +    let c = A(B(C)).into_b().into_c();
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_access_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A { pub b: B }
 +struct B { pub c: C }
 +struct C(pub bool);
 +struct D;
 +
 +impl D {
 +    fn foo(&self) -> i32 { 42 }
 +}
 +
 +fn main() {
 +    let x = A { b: B { c: C(true) } }
 +        .b
 +        .c
 +        .0;
 +    let x = D
 +        .foo();
 +}"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 143..190,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "C",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                143..190,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 143..179,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "B",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                143..179,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A<T>(T);
 +struct B<T>(T);
 +struct C<T>(T);
 +struct X<T,R>(T, R);
 +
 +impl<T> A<T> {
 +    fn new(t: T) -> Self { A(t) }
 +    fn into_b(self) -> B<T> { B(self.0) }
 +}
 +impl<T> B<T> {
 +    fn into_c(self) -> C<T> { C(self.0) }
 +}
 +fn main() {
 +    let c = A::new(X(42, true))
 +        .into_b()
 +        .into_c();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 246..283,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "B<X<i32, bool>>",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                246..283,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 246..265,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "A<X<i32, bool>>",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                246..265,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterator_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +struct MyIter;
 +
 +impl Iterator for MyIter {
 +    type Item = ();
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let _x = MyIter.by_ref()
 +        .take(5)
 +        .by_ref()
 +        .take(5)
 +        .by_ref();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 174..241,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "impl Iterator<Item = ()>",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..241,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..224,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "impl Iterator<Item = ()>",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..224,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..206,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "impl Iterator<Item = ()>",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..206,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..189,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "&mut MyIter",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..189,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_in_attr_call() {
 +        check_expect(
 +            TEST_CONFIG,
 +            r#"
 +//- proc_macros: identity, input_replace
 +struct Struct;
 +impl Struct {
 +    fn chain(self) -> Self {
 +        self
 +    }
 +}
 +#[proc_macros::identity]
 +fn main() {
 +    let strukt = Struct;
 +    strukt
 +        .chain()
 +        .chain()
 +        .chain();
 +    Struct::chain(strukt);
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 124..130,
 +                        kind: TypeHint,
 +                        label: [
 +                            "Struct",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                124..130,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 145..185,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "Struct",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                145..185,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 145..168,
 +                        kind: ChainingHint,
 +                        label: [
 +                            "Struct",
 +                        ],
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                145..168,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 222..228,
 +                        kind: ParameterHint,
 +                        label: [
 +                            "self",
 +                        ],
 +                        tooltip: Some(
 +                            HoverOffset(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                42,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes() {
 +        check(
 +            r#"
 +fn empty() {}
 +
 +fn no_gpl(a: &()) {}
 + //^^^^^^<'0>
 +          // ^'0
 +fn empty_gpl<>(a: &()) {}
 +      //    ^'0   ^'0
 +fn partial<'b>(a: &(), b: &'b ()) {}
 +//        ^'0, $  ^'0
 +fn partial<'a>(a: &'a (), b: &()) {}
 +//        ^'0, $             ^'0
 +
 +fn single_ret(a: &()) -> &() {}
 +// ^^^^^^^^^^<'0>
 +              // ^'0     ^'0
 +fn full_mul(a: &(), b: &()) {}
 +// ^^^^^^^^<'0, '1>
 +            // ^'0     ^'1
 +
 +fn foo<'c>(a: &'c ()) -> &() {}
 +                      // ^'c
 +
 +fn nested_in(a: &   &X< &()>) {}
 +// ^^^^^^^^^<'0, '1, '2>
 +              //^'0 ^'1 ^'2
 +fn nested_out(a: &()) -> &   &X< &()>{}
 +// ^^^^^^^^^^<'0>
 +               //^'0     ^'0 ^'0 ^'0
 +
 +impl () {
 +    fn foo(&self) {}
 +    // ^^^<'0>
 +        // ^'0
 +    fn foo(&self) -> &() {}
 +    // ^^^<'0>
 +        // ^'0       ^'0
 +    fn foo(&self, a: &()) -> &() {}
 +    // ^^^<'0, '1>
 +        // ^'0       ^'1     ^'0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_named() {
 +        check_with_config(
 +            InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
 +            r#"
 +fn nested_in<'named>(named: &        &X<      &()>) {}
 +//          ^'named1, 'named2, 'named3, $
 +                          //^'named1 ^'named2 ^'named3
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_trivial_skip() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                lifetime_elision_hints: LifetimeElisionHints::SkipTrivial,
 +                ..TEST_CONFIG
 +            },
 +            r#"
 +fn no_gpl(a: &()) {}
 +fn empty_gpl<>(a: &()) {}
 +fn partial<'b>(a: &(), b: &'b ()) {}
 +fn partial<'a>(a: &'a (), b: &()) {}
 +
 +fn single_ret(a: &()) -> &() {}
 +// ^^^^^^^^^^<'0>
 +              // ^'0     ^'0
 +fn full_mul(a: &(), b: &()) {}
 +
 +fn foo<'c>(a: &'c ()) -> &() {}
 +                      // ^'c
 +
 +fn nested_in(a: &   &X< &()>) {}
 +fn nested_out(a: &()) -> &   &X< &()>{}
 +// ^^^^^^^^^^<'0>
 +               //^'0     ^'0 ^'0 ^'0
 +
 +impl () {
 +    fn foo(&self) {}
 +    fn foo(&self) -> &() {}
 +    // ^^^<'0>
 +        // ^'0       ^'0
 +    fn foo(&self, a: &()) -> &() {}
 +    // ^^^<'0, '1>
 +        // ^'0       ^'1     ^'0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_static() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                lifetime_elision_hints: LifetimeElisionHints::Always,
 +                ..TEST_CONFIG
 +            },
 +            r#"
 +trait Trait {}
 +static S: &str = "";
 +//        ^'static
 +const C: &str = "";
 +//       ^'static
 +const C: &dyn Trait = panic!();
 +//       ^'static
 +
 +impl () {
 +    const C: &str = "";
 +    const C: &dyn Trait = panic!();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_implicit_reborrow() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                reborrow_hints: ReborrowHints::Always,
 +                parameter_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +fn __() {
 +    let unique = &mut ();
 +    let r_mov = unique;
 +    let foo: &mut _ = unique;
 +                    //^^^^^^ &mut *
 +    ref_mut_id(unique);
 +             //^^^^^^ mut_ref
 +             //^^^^^^ &mut *
 +    let shared = ref_id(unique);
 +                      //^^^^^^ shared_ref
 +                      //^^^^^^ &*
 +    let mov = shared;
 +    let r_mov: &_ = shared;
 +    ref_id(shared);
 +         //^^^^^^ shared_ref
 +
 +    identity(unique);
 +    identity(shared);
 +}
 +fn identity<T>(t: T) -> T {
 +    t
 +}
 +fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
 +    mut_ref
 +  //^^^^^^^ &mut *
 +}
 +fn ref_id(shared_ref: &()) -> &() {
 +    shared_ref
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_binding_modes() {
 +        check_with_config(
 +            InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +fn __(
 +    (x,): (u32,),
 +    (x,): &(u32,),
 +  //^^^^&
 +   //^ ref
 +    (x,): &mut (u32,)
 +  //^^^^&mut
 +   //^ ref mut
 +) {
 +    let (x,) = (0,);
 +    let (x,) = &(0,);
 +      //^^^^ &
 +       //^ ref
 +    let (x,) = &mut (0,);
 +      //^^^^ &mut
 +       //^ ref mut
 +    let &mut (x,) = &mut (0,);
 +    let (ref mut x,) = &mut (0,);
 +      //^^^^^^^^^^^^ &mut
 +    let &mut (ref mut x,) = &mut (0,);
 +    let (mut x,) = &mut (0,);
 +      //^^^^^^^^ &mut
 +    match (0,) {
 +        (x,) => ()
 +    }
 +    match &(0,) {
 +        (x,) => ()
 +      //^^^^ &
 +       //^ ref
 +    }
 +    match &mut (0,) {
 +        (x,) => ()
 +      //^^^^ &mut
 +       //^ ref mut
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_closing_brace() {
 +        check_with_config(
 +            InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
 +            r#"
 +fn a() {}
 +
 +fn f() {
 +} // no hint unless `}` is the last token on the line
 +
 +fn g() {
 +  }
 +//^ fn g
 +
 +fn h<T>(with: T, arguments: u8, ...) {
 +  }
 +//^ fn h
 +
 +trait Tr {
 +    fn f();
 +    fn g() {
 +    }
 +  //^ fn g
 +  }
 +//^ trait Tr
 +impl Tr for () {
 +  }
 +//^ impl Tr for ()
 +impl dyn Tr {
 +  }
 +//^ impl dyn Tr
 +
 +static S0: () = 0;
 +static S1: () = {};
 +static S2: () = {
 + };
 +//^ static S2
 +const _: () = {
 + };
 +//^ const _
 +
 +mod m {
 +  }
 +//^ mod m
 +
 +m! {}
 +m!();
 +m!(
 + );
 +//^ m!
 +
 +m! {
 +  }
 +//^ m!
 +
 +fn f() {
 +    let v = vec![
 +    ];
 +  }
 +//^ fn f
 +"#,
 +        );
 +    }
 +}
index 0552330814aa4b1bd85762119136531489c20086,0000000000000000000000000000000000000000..c1ef25b592b1be4e2aebc8c3a6b719f7c3c27db3
mode 100644,000000..100644
--- /dev/null
@@@ -1,710 -1,0 +1,710 @@@
-     annotations::{Annotation, AnnotationConfig, AnnotationKind},
 +//! ide crate provides "ide-centric" APIs for the rust-analyzer. That is,
 +//! it generally operates with files and text ranges, and returns results as
 +//! Strings, suitable for displaying to the human.
 +//!
 +//! What powers this API are the `RootDatabase` struct, which defines a `salsa`
 +//! database, and the `hir` crate, where majority of the analysis happens.
 +//! However, IDE specific bits of the analysis (most notably completion) happen
 +//! in this crate.
 +
 +// For proving that RootDatabase is RefUnwindSafe.
 +#![recursion_limit = "128"]
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +#[cfg(test)]
 +mod fixture;
 +
 +mod markup;
 +mod prime_caches;
 +mod navigation_target;
 +
 +mod annotations;
 +mod call_hierarchy;
 +mod signature_help;
 +mod doc_links;
 +mod highlight_related;
 +mod expand_macro;
 +mod extend_selection;
 +mod file_structure;
 +mod fn_references;
 +mod folding_ranges;
 +mod goto_declaration;
 +mod goto_definition;
 +mod goto_implementation;
 +mod goto_type_definition;
 +mod hover;
 +mod inlay_hints;
 +mod join_lines;
 +mod markdown_remove;
 +mod matching_brace;
 +mod moniker;
 +mod move_item;
 +mod parent_module;
 +mod references;
 +mod rename;
 +mod runnables;
 +mod ssr;
 +mod static_index;
 +mod status;
 +mod syntax_highlighting;
 +mod syntax_tree;
 +mod typing;
 +mod view_crate_graph;
 +mod view_hir;
 +mod view_item_tree;
 +mod shuffle_crate_graph;
 +
 +use std::sync::Arc;
 +
 +use cfg::CfgOptions;
 +use ide_db::{
 +    base_db::{
 +        salsa::{self, ParallelDatabase},
 +        CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
 +    },
 +    symbol_index, LineIndexDatabase,
 +};
 +use syntax::SourceFile;
 +
 +use crate::navigation_target::{ToNav, TryToNav};
 +
 +pub use crate::{
++    annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
 +    call_hierarchy::CallItem,
 +    expand_macro::ExpandedMacro,
 +    file_structure::{StructureNode, StructureNodeKind},
 +    folding_ranges::{Fold, FoldKind},
 +    highlight_related::{HighlightRelatedConfig, HighlightedRange},
 +    hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
 +    inlay_hints::{
 +        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
 +        InlayTooltip, LifetimeElisionHints, ReborrowHints,
 +    },
 +    join_lines::JoinLinesConfig,
 +    markup::Markup,
 +    moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation},
 +    move_item::Direction,
 +    navigation_target::NavigationTarget,
 +    prime_caches::ParallelPrimeCachesProgress,
 +    references::ReferenceSearchResult,
 +    rename::RenameError,
 +    runnables::{Runnable, RunnableKind, TestId},
 +    signature_help::SignatureHelp,
 +    static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData},
 +    syntax_highlighting::{
 +        tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
 +        HighlightConfig, HlRange,
 +    },
 +};
 +pub use hir::{Documentation, Semantics};
 +pub use ide_assists::{
 +    Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
 +};
 +pub use ide_completion::{
 +    CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance,
 +    Snippet, SnippetScope,
 +};
 +pub use ide_db::{
 +    base_db::{
 +        Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
 +        SourceRoot, SourceRootId,
 +    },
 +    label::Label,
 +    line_index::{LineCol, LineColUtf16, LineIndex},
 +    search::{ReferenceCategory, SearchScope},
 +    source_change::{FileSystemEdit, SourceChange},
 +    symbol_index::Query,
 +    RootDatabase, SymbolKind,
 +};
 +pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, ExprFillDefaultMode, Severity};
 +pub use ide_ssr::SsrError;
 +pub use syntax::{TextRange, TextSize};
 +pub use text_edit::{Indel, TextEdit};
 +
 +pub type Cancellable<T> = Result<T, Cancelled>;
 +
 +/// Info associated with a text range.
 +#[derive(Debug)]
 +pub struct RangeInfo<T> {
 +    pub range: TextRange,
 +    pub info: T,
 +}
 +
 +impl<T> RangeInfo<T> {
 +    pub fn new(range: TextRange, info: T) -> RangeInfo<T> {
 +        RangeInfo { range, info }
 +    }
 +}
 +
 +/// `AnalysisHost` stores the current state of the world.
 +#[derive(Debug)]
 +pub struct AnalysisHost {
 +    db: RootDatabase,
 +}
 +
 +impl AnalysisHost {
 +    pub fn new(lru_capacity: Option<usize>) -> AnalysisHost {
 +        AnalysisHost { db: RootDatabase::new(lru_capacity) }
 +    }
 +
 +    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
 +        self.db.update_lru_capacity(lru_capacity);
 +    }
 +
 +    /// Returns a snapshot of the current state, which you can query for
 +    /// semantic information.
 +    pub fn analysis(&self) -> Analysis {
 +        Analysis { db: self.db.snapshot() }
 +    }
 +
 +    /// 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) {
 +        self.db.apply_change(change)
 +    }
 +
 +    /// NB: this clears the database
 +    pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> {
 +        self.db.per_query_memory_usage()
 +    }
 +    pub fn request_cancellation(&mut self) {
 +        self.db.request_cancellation();
 +    }
 +    pub fn raw_database(&self) -> &RootDatabase {
 +        &self.db
 +    }
 +    pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
 +        &mut self.db
 +    }
 +
 +    pub fn shuffle_crate_graph(&mut self) {
 +        shuffle_crate_graph::shuffle_crate_graph(&mut self.db);
 +    }
 +}
 +
 +impl Default for AnalysisHost {
 +    fn default() -> AnalysisHost {
 +        AnalysisHost::new(None)
 +    }
 +}
 +
 +/// Analysis is a snapshot of a world state at a moment in time. It is the main
 +/// entry point for asking semantic information about the world. When the world
 +/// state is advanced using `AnalysisHost::apply_change` method, all existing
 +/// `Analysis` are canceled (most method return `Err(Canceled)`).
 +#[derive(Debug)]
 +pub struct Analysis {
 +    db: salsa::Snapshot<RootDatabase>,
 +}
 +
 +// As a general design guideline, `Analysis` API are intended to be independent
 +// from the language server protocol. That is, when exposing some functionality
 +// we should think in terms of "what API makes most sense" and not in terms of
 +// "what types LSP uses". Although currently LSP is the only consumer of the
 +// API, the API should in theory be usable as a library, or via a different
 +// protocol.
 +impl Analysis {
 +    // Creates an analysis instance for a single file, without any external
 +    // dependencies, stdlib support or ability to apply changes. See
 +    // `AnalysisHost` for creating a fully-featured analysis.
 +    pub fn from_single_file(text: String) -> (Analysis, FileId) {
 +        let mut host = AnalysisHost::default();
 +        let file_id = FileId(0);
 +        let mut file_set = FileSet::default();
 +        file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
 +        let source_root = SourceRoot::new_local(file_set);
 +
 +        let mut change = Change::new();
 +        change.set_roots(vec![source_root]);
 +        let mut crate_graph = CrateGraph::default();
 +        // FIXME: cfg options
 +        // Default to enable test for single file.
 +        let mut cfg_options = CfgOptions::default();
 +        cfg_options.insert_atom("test".into());
 +        crate_graph.add_crate_root(
 +            file_id,
 +            Edition::CURRENT,
 +            None,
 +            None,
 +            cfg_options.clone(),
 +            cfg_options,
 +            Env::default(),
 +            Ok(Vec::new()),
 +            false,
 +            CrateOrigin::CratesIo { repo: None },
 +        );
 +        change.change_file(file_id, Some(Arc::new(text)));
 +        change.set_crate_graph(crate_graph);
 +        host.apply_change(change);
 +        (host.analysis(), file_id)
 +    }
 +
 +    /// Debug info about the current state of the analysis.
 +    pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
 +        self.with_db(|db| status::status(&*db, file_id))
 +    }
 +
 +    pub fn parallel_prime_caches<F>(&self, num_worker_threads: u8, cb: F) -> Cancellable<()>
 +    where
 +        F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
 +    {
 +        self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb))
 +    }
 +
 +    /// Gets the text of the source file.
 +    pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<String>> {
 +        self.with_db(|db| db.file_text(file_id))
 +    }
 +
 +    /// Gets the syntax tree of the file.
 +    pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
 +        self.with_db(|db| db.parse(file_id).tree())
 +    }
 +
 +    /// Returns true if this file belongs to an immutable library.
 +    pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
 +        use ide_db::base_db::SourceDatabaseExt;
 +        self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
 +    }
 +
 +    /// Gets the file's `LineIndex`: data structure to convert between absolute
 +    /// offsets and line/column representation.
 +    pub fn file_line_index(&self, file_id: FileId) -> Cancellable<Arc<LineIndex>> {
 +        self.with_db(|db| db.line_index(file_id))
 +    }
 +
 +    /// Selects the next syntactic nodes encompassing the range.
 +    pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
 +        self.with_db(|db| extend_selection::extend_selection(db, frange))
 +    }
 +
 +    /// Returns position of the matching brace (all types of braces are
 +    /// supported).
 +    pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
 +        self.with_db(|db| {
 +            let parse = db.parse(position.file_id);
 +            let file = parse.tree();
 +            matching_brace::matching_brace(&file, position.offset)
 +        })
 +    }
 +
 +    /// Returns a syntax tree represented as `String`, for debug purposes.
 +    // FIXME: use a better name here.
 +    pub fn syntax_tree(
 +        &self,
 +        file_id: FileId,
 +        text_range: Option<TextRange>,
 +    ) -> Cancellable<String> {
 +        self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range))
 +    }
 +
 +    pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> {
 +        self.with_db(|db| view_hir::view_hir(db, position))
 +    }
 +
 +    pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {
 +        self.with_db(|db| view_item_tree::view_item_tree(db, file_id))
 +    }
 +
 +    /// Renders the crate graph to GraphViz "dot" syntax.
 +    pub fn view_crate_graph(&self, full: bool) -> Cancellable<Result<String, String>> {
 +        self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
 +    }
 +
 +    pub fn expand_macro(&self, position: FilePosition) -> Cancellable<Option<ExpandedMacro>> {
 +        self.with_db(|db| expand_macro::expand_macro(db, position))
 +    }
 +
 +    /// Returns an edit to remove all newlines in the range, cleaning up minor
 +    /// stuff like trailing commas.
 +    pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancellable<TextEdit> {
 +        self.with_db(|db| {
 +            let parse = db.parse(frange.file_id);
 +            join_lines::join_lines(config, &parse.tree(), frange.range)
 +        })
 +    }
 +
 +    /// Returns an edit which should be applied when opening a new line, fixing
 +    /// up minor stuff like continuing the comment.
 +    /// The edit will be a snippet (with `$0`).
 +    pub fn on_enter(&self, position: FilePosition) -> Cancellable<Option<TextEdit>> {
 +        self.with_db(|db| typing::on_enter(db, position))
 +    }
 +
 +    /// Returns an edit which should be applied after a character was typed.
 +    ///
 +    /// This is useful for some on-the-fly fixups, like adding `;` to `let =`
 +    /// automatically.
 +    pub fn on_char_typed(
 +        &self,
 +        position: FilePosition,
 +        char_typed: char,
 +        autoclose: bool,
 +    ) -> Cancellable<Option<SourceChange>> {
 +        // Fast path to not even parse the file.
 +        if !typing::TRIGGER_CHARS.contains(char_typed) {
 +            return Ok(None);
 +        }
 +        if char_typed == '<' && !autoclose {
 +            return Ok(None);
 +        }
 +
 +        self.with_db(|db| typing::on_char_typed(db, position, char_typed))
 +    }
 +
 +    /// Returns a tree representation of symbols in the file. Useful to draw a
 +    /// file outline.
 +    pub fn file_structure(&self, file_id: FileId) -> Cancellable<Vec<StructureNode>> {
 +        self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
 +    }
 +
 +    /// Returns a list of the places in the file where type hints can be displayed.
 +    pub fn inlay_hints(
 +        &self,
 +        config: &InlayHintsConfig,
 +        file_id: FileId,
 +        range: Option<FileRange>,
 +    ) -> Cancellable<Vec<InlayHint>> {
 +        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
 +    }
 +
 +    /// Returns the set of folding ranges.
 +    pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
 +        self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree()))
 +    }
 +
 +    /// Fuzzy searches for a symbol.
 +    pub fn symbol_search(&self, query: Query) -> Cancellable<Vec<NavigationTarget>> {
 +        self.with_db(|db| {
 +            symbol_index::world_symbols(db, query)
 +                .into_iter() // xx: should we make this a par iter?
 +                .filter_map(|s| s.try_to_nav(db))
 +                .collect::<Vec<_>>()
 +        })
 +    }
 +
 +    /// Returns the definitions from the symbol at `position`.
 +    pub fn goto_definition(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_definition::goto_definition(db, position))
 +    }
 +
 +    /// Returns the declaration from the symbol at `position`.
 +    pub fn goto_declaration(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_declaration::goto_declaration(db, position))
 +    }
 +
 +    /// Returns the impls from the symbol at `position`.
 +    pub fn goto_implementation(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_implementation::goto_implementation(db, position))
 +    }
 +
 +    /// Returns the type definitions for the symbol at `position`.
 +    pub fn goto_type_definition(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
 +    }
 +
 +    /// Finds all usages of the reference at point.
 +    pub fn find_all_refs(
 +        &self,
 +        position: FilePosition,
 +        search_scope: Option<SearchScope>,
 +    ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
 +        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
 +    }
 +
 +    /// Finds all methods and free functions for the file. Does not return tests!
 +    pub fn find_all_methods(&self, file_id: FileId) -> Cancellable<Vec<FileRange>> {
 +        self.with_db(|db| fn_references::find_all_methods(db, file_id))
 +    }
 +
 +    /// Returns a short text describing element at position.
 +    pub fn hover(
 +        &self,
 +        config: &HoverConfig,
 +        range: FileRange,
 +    ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
 +        self.with_db(|db| hover::hover(db, range, config))
 +    }
 +
 +    /// Returns moniker of symbol at position.
 +    pub fn moniker(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<moniker::MonikerResult>>>> {
 +        self.with_db(|db| moniker::moniker(db, position))
 +    }
 +
 +    /// Return URL(s) for the documentation of the symbol under the cursor.
 +    pub fn external_docs(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<doc_links::DocumentationLink>> {
 +        self.with_db(|db| doc_links::external_docs(db, &position))
 +    }
 +
 +    /// Computes parameter information at the given position.
 +    pub fn signature_help(&self, position: FilePosition) -> Cancellable<Option<SignatureHelp>> {
 +        self.with_db(|db| signature_help::signature_help(db, position))
 +    }
 +
 +    /// Computes call hierarchy candidates for the given file position.
 +    pub fn call_hierarchy(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
 +    }
 +
 +    /// Computes incoming calls for the given file position.
 +    pub fn incoming_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
 +        self.with_db(|db| call_hierarchy::incoming_calls(db, position))
 +    }
 +
 +    /// Computes outgoing calls for the given file position.
 +    pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
 +        self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
 +    }
 +
 +    /// Returns a `mod name;` declaration which created the current module.
 +    pub fn parent_module(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
 +        self.with_db(|db| parent_module::parent_module(db, position))
 +    }
 +
 +    /// Returns crates this file belongs too.
 +    pub fn crate_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
 +        self.with_db(|db| parent_module::crate_for(db, file_id))
 +    }
 +
 +    /// Returns the edition of the given crate.
 +    pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable<Edition> {
 +        self.with_db(|db| db.crate_graph()[crate_id].edition)
 +    }
 +
 +    /// Returns the root file of the given crate.
 +    pub fn crate_root(&self, crate_id: CrateId) -> Cancellable<FileId> {
 +        self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
 +    }
 +
 +    /// Returns the set of possible targets to run for the current file.
 +    pub fn runnables(&self, file_id: FileId) -> Cancellable<Vec<Runnable>> {
 +        self.with_db(|db| runnables::runnables(db, file_id))
 +    }
 +
 +    /// Returns the set of tests for the given file position.
 +    pub fn related_tests(
 +        &self,
 +        position: FilePosition,
 +        search_scope: Option<SearchScope>,
 +    ) -> Cancellable<Vec<Runnable>> {
 +        self.with_db(|db| runnables::related_tests(db, position, search_scope))
 +    }
 +
 +    /// Computes syntax highlighting for the given file
 +    pub fn highlight(
 +        &self,
 +        highlight_config: HighlightConfig,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<HlRange>> {
 +        self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None))
 +    }
 +
 +    /// Computes all ranges to highlight for a given item in a file.
 +    pub fn highlight_related(
 +        &self,
 +        config: HighlightRelatedConfig,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<Vec<HighlightedRange>>> {
 +        self.with_db(|db| {
 +            highlight_related::highlight_related(&Semantics::new(db), config, position)
 +        })
 +    }
 +
 +    /// Computes syntax highlighting for the given file range.
 +    pub fn highlight_range(
 +        &self,
 +        highlight_config: HighlightConfig,
 +        frange: FileRange,
 +    ) -> Cancellable<Vec<HlRange>> {
 +        self.with_db(|db| {
 +            syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range))
 +        })
 +    }
 +
 +    /// Computes syntax highlighting for the given file.
 +    pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
 +        self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
 +    }
 +
 +    /// Computes completions at the given position.
 +    pub fn completions(
 +        &self,
 +        config: &CompletionConfig,
 +        position: FilePosition,
 +        trigger_character: Option<char>,
 +    ) -> Cancellable<Option<Vec<CompletionItem>>> {
 +        self.with_db(|db| {
 +            ide_completion::completions(db, config, position, trigger_character).map(Into::into)
 +        })
 +    }
 +
 +    /// Resolves additional completion data at the position given.
 +    pub fn resolve_completion_edits(
 +        &self,
 +        config: &CompletionConfig,
 +        position: FilePosition,
 +        imports: impl IntoIterator<Item = (String, String)> + std::panic::UnwindSafe,
 +    ) -> Cancellable<Vec<TextEdit>> {
 +        Ok(self
 +            .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
 +            .unwrap_or_default())
 +    }
 +
 +    /// Computes the set of diagnostics for the given file.
 +    pub fn diagnostics(
 +        &self,
 +        config: &DiagnosticsConfig,
 +        resolve: AssistResolveStrategy,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<Diagnostic>> {
 +        self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id))
 +    }
 +
 +    /// Convenience function to return assists + quick fixes for diagnostics
 +    pub fn assists_with_fixes(
 +        &self,
 +        assist_config: &AssistConfig,
 +        diagnostics_config: &DiagnosticsConfig,
 +        resolve: AssistResolveStrategy,
 +        frange: FileRange,
 +    ) -> Cancellable<Vec<Assist>> {
 +        let include_fixes = match &assist_config.allowed {
 +            Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
 +            None => true,
 +        };
 +
 +        self.with_db(|db| {
 +            let diagnostic_assists = if include_fixes {
 +                ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id)
 +                    .into_iter()
 +                    .flat_map(|it| it.fixes.unwrap_or_default())
 +                    .filter(|it| it.target.intersect(frange.range).is_some())
 +                    .collect()
 +            } else {
 +                Vec::new()
 +            };
 +            let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
 +            let assists = ide_assists::assists(db, assist_config, resolve, frange);
 +
 +            let mut res = diagnostic_assists;
 +            res.extend(ssr_assists.into_iter());
 +            res.extend(assists.into_iter());
 +
 +            res
 +        })
 +    }
 +
 +    /// Returns the edit required to rename reference at the position to the new
 +    /// name.
 +    pub fn rename(
 +        &self,
 +        position: FilePosition,
 +        new_name: &str,
 +    ) -> Cancellable<Result<SourceChange, RenameError>> {
 +        self.with_db(|db| rename::rename(db, position, new_name))
 +    }
 +
 +    pub fn prepare_rename(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Result<RangeInfo<()>, RenameError>> {
 +        self.with_db(|db| rename::prepare_rename(db, position))
 +    }
 +
 +    pub fn will_rename_file(
 +        &self,
 +        file_id: FileId,
 +        new_name_stem: &str,
 +    ) -> Cancellable<Option<SourceChange>> {
 +        self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem))
 +    }
 +
 +    pub fn structural_search_replace(
 +        &self,
 +        query: &str,
 +        parse_only: bool,
 +        resolve_context: FilePosition,
 +        selections: Vec<FileRange>,
 +    ) -> Cancellable<Result<SourceChange, SsrError>> {
 +        self.with_db(|db| {
 +            let rule: ide_ssr::SsrRule = query.parse()?;
 +            let mut match_finder =
 +                ide_ssr::MatchFinder::in_context(db, resolve_context, selections)?;
 +            match_finder.add_rule(rule)?;
 +            let edits = if parse_only { Default::default() } else { match_finder.edits() };
 +            Ok(SourceChange::from(edits))
 +        })
 +    }
 +
 +    pub fn annotations(
 +        &self,
 +        config: &AnnotationConfig,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<Annotation>> {
 +        self.with_db(|db| annotations::annotations(db, config, file_id))
 +    }
 +
 +    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
 +        self.with_db(|db| annotations::resolve_annotation(db, annotation))
 +    }
 +
 +    pub fn move_item(
 +        &self,
 +        range: FileRange,
 +        direction: Direction,
 +    ) -> Cancellable<Option<TextEdit>> {
 +        self.with_db(|db| move_item::move_item(db, range, direction))
 +    }
 +
 +    /// Performs an operation on the database that may be canceled.
 +    ///
 +    /// rust-analyzer needs to be able to answer semantic questions about the
 +    /// code while the code is being modified. A common problem is that a
 +    /// long-running query is being calculated when a new change arrives.
 +    ///
 +    /// We can't just apply the change immediately: this will cause the pending
 +    /// query to see inconsistent state (it will observe an absence of
 +    /// repeatable read). So what we do is we **cancel** all pending queries
 +    /// before applying the change.
 +    ///
 +    /// Salsa implements cancellation by unwinding with a special value and
 +    /// catching it on the API boundary.
 +    fn with_db<F, T>(&self, f: F) -> Cancellable<T>
 +    where
 +        F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
 +    {
 +        Cancelled::catch(|| f(&self.db))
 +    }
 +}
 +
 +#[test]
 +fn analysis_is_send() {
 +    fn is_send<T: Send>() {}
 +    is_send::<Analysis>();
 +}
index 99614b645e48ff02160b38fcf377f12bf01b4705,0000000000000000000000000000000000000000..e942413c11057ed40810a518b85eb0dcf641ea7c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1637 -1,0 +1,1637 @@@
-                 FileId(0) 14..17
 +//! This module implements a reference search.
 +//! First, the element at the cursor position must be either an `ast::Name`
 +//! or `ast::NameRef`. If it's an `ast::NameRef`, at the classification step we
 +//! try to resolve the direct tree parent of this element, otherwise we
 +//! already have a definition and just need to get its HIR together with
 +//! some information that is needed for further steps of searching.
 +//! After that, we collect files that might contain references and look
 +//! for text occurrences of the identifier. If there's an `ast::NameRef`
 +//! at the index that the match starts at and its tree parent is
 +//! resolved to the search element definition, we get a reference.
 +
 +use hir::{PathResolution, Semantics};
 +use ide_db::{
 +    base_db::FileId,
 +    defs::{Definition, NameClass, NameRefClass},
 +    search::{ReferenceCategory, SearchScope, UsageSearchResult},
 +    RootDatabase,
 +};
 +use stdx::hash::NoHashHashMap;
 +use syntax::{
 +    algo::find_node_at_offset,
 +    ast::{self, HasName},
 +    match_ast, AstNode,
 +    SyntaxKind::*,
 +    SyntaxNode, TextRange, TextSize, T,
 +};
 +
 +use crate::{FilePosition, NavigationTarget, TryToNav};
 +
 +#[derive(Debug, Clone)]
 +pub struct ReferenceSearchResult {
 +    pub declaration: Option<Declaration>,
 +    pub references: NoHashHashMap<FileId, Vec<(TextRange, Option<ReferenceCategory>)>>,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct Declaration {
 +    pub nav: NavigationTarget,
 +    pub is_mut: bool,
 +}
 +
 +// Feature: Find All References
 +//
 +// Shows all references of the item at the cursor location
 +//
 +// |===
 +// | Editor  | Shortcut
 +//
 +// | VS Code | kbd:[Shift+Alt+F12]
 +// |===
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[]
 +pub(crate) fn find_all_refs(
 +    sema: &Semantics<'_, RootDatabase>,
 +    position: FilePosition,
 +    search_scope: Option<SearchScope>,
 +) -> Option<Vec<ReferenceSearchResult>> {
 +    let _p = profile::span("find_all_refs");
 +    let syntax = sema.parse(position.file_id).syntax().clone();
 +    let make_searcher = |literal_search: bool| {
 +        move |def: Definition| {
 +            let declaration = match def {
 +                Definition::Module(module) => {
 +                    Some(NavigationTarget::from_module_to_decl(sema.db, module))
 +                }
 +                def => def.try_to_nav(sema.db),
 +            }
 +            .map(|nav| {
 +                let decl_range = nav.focus_or_full_range();
 +                Declaration {
 +                    is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
 +                    nav,
 +                }
 +            });
 +            let mut usages =
 +                def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
 +
 +            if literal_search {
 +                retain_adt_literal_usages(&mut usages, def, sema);
 +            }
 +
 +            let references = usages
 +                .into_iter()
 +                .map(|(file_id, refs)| {
 +                    (
 +                        file_id,
 +                        refs.into_iter()
 +                            .map(|file_ref| (file_ref.range, file_ref.category))
 +                            .collect(),
 +                    )
 +                })
 +                .collect();
 +
 +            ReferenceSearchResult { declaration, references }
 +        }
 +    };
 +
 +    match name_for_constructor_search(&syntax, position) {
 +        Some(name) => {
 +            let def = match NameClass::classify(sema, &name)? {
 +                NameClass::Definition(it) | NameClass::ConstReference(it) => it,
 +                NameClass::PatFieldShorthand { local_def: _, field_ref } => {
 +                    Definition::Field(field_ref)
 +                }
 +            };
 +            Some(vec![make_searcher(true)(def)])
 +        }
 +        None => {
 +            let search = make_searcher(false);
 +            Some(find_defs(sema, &syntax, position.offset)?.map(search).collect())
 +        }
 +    }
 +}
 +
 +pub(crate) fn find_defs<'a>(
 +    sema: &'a Semantics<'_, RootDatabase>,
 +    syntax: &SyntaxNode,
 +    offset: TextSize,
 +) -> Option<impl Iterator<Item = Definition> + 'a> {
 +    let token = syntax.token_at_offset(offset).find(|t| {
 +        matches!(
 +            t.kind(),
 +            IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
 +        )
 +    });
 +    token.map(|token| {
 +        sema.descend_into_macros_with_same_text(token)
 +            .into_iter()
 +            .filter_map(|it| ast::NameLike::cast(it.parent()?))
 +            .filter_map(move |name_like| {
 +                let def = match name_like {
 +                    ast::NameLike::NameRef(name_ref) => {
 +                        match NameRefClass::classify(sema, &name_ref)? {
 +                            NameRefClass::Definition(def) => def,
 +                            NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
 +                                Definition::Local(local_ref)
 +                            }
 +                        }
 +                    }
 +                    ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
 +                        NameClass::Definition(it) | NameClass::ConstReference(it) => it,
 +                        NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
 +                            Definition::Local(local_def)
 +                        }
 +                    },
 +                    ast::NameLike::Lifetime(lifetime) => {
 +                        NameRefClass::classify_lifetime(sema, &lifetime)
 +                            .and_then(|class| match class {
 +                                NameRefClass::Definition(it) => Some(it),
 +                                _ => None,
 +                            })
 +                            .or_else(|| {
 +                                NameClass::classify_lifetime(sema, &lifetime)
 +                                    .and_then(NameClass::defined)
 +                            })?
 +                    }
 +                };
 +                Some(def)
 +            })
 +    })
 +}
 +
 +pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool {
 +    match def {
 +        Definition::Local(_) | Definition::Field(_) => {}
 +        _ => return false,
 +    };
 +
 +    match find_node_at_offset::<ast::LetStmt>(syntax, range.start()) {
 +        Some(stmt) if stmt.initializer().is_some() => match stmt.pat() {
 +            Some(ast::Pat::IdentPat(it)) => it.mut_token().is_some(),
 +            _ => false,
 +        },
 +        _ => false,
 +    }
 +}
 +
 +/// Filter out all non-literal usages for adt-defs
 +fn retain_adt_literal_usages(
 +    usages: &mut UsageSearchResult,
 +    def: Definition,
 +    sema: &Semantics<'_, RootDatabase>,
 +) {
 +    let refs = usages.references.values_mut();
 +    match def {
 +        Definition::Adt(hir::Adt::Enum(enum_)) => {
 +            refs.for_each(|it| {
 +                it.retain(|reference| {
 +                    reference
 +                        .name
 +                        .as_name_ref()
 +                        .map_or(false, |name_ref| is_enum_lit_name_ref(sema, enum_, name_ref))
 +                })
 +            });
 +            usages.references.retain(|_, it| !it.is_empty());
 +        }
 +        Definition::Adt(_) | Definition::Variant(_) => {
 +            refs.for_each(|it| {
 +                it.retain(|reference| reference.name.as_name_ref().map_or(false, is_lit_name_ref))
 +            });
 +            usages.references.retain(|_, it| !it.is_empty());
 +        }
 +        _ => {}
 +    }
 +}
 +
 +/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages
 +fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
 +    let token = syntax.token_at_offset(position.offset).right_biased()?;
 +    let token_parent = token.parent()?;
 +    let kind = token.kind();
 +    if kind == T![;] {
 +        ast::Struct::cast(token_parent)
 +            .filter(|struct_| struct_.field_list().is_none())
 +            .and_then(|struct_| struct_.name())
 +    } else if kind == T!['{'] {
 +        match_ast! {
 +            match token_parent {
 +                ast::RecordFieldList(rfl) => match_ast! {
 +                    match (rfl.syntax().parent()?) {
 +                        ast::Variant(it) => it.name(),
 +                        ast::Struct(it) => it.name(),
 +                        ast::Union(it) => it.name(),
 +                        _ => None,
 +                    }
 +                },
 +                ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(),
 +                _ => None,
 +            }
 +        }
 +    } else if kind == T!['('] {
 +        let tfl = ast::TupleFieldList::cast(token_parent)?;
 +        match_ast! {
 +            match (tfl.syntax().parent()?) {
 +                ast::Variant(it) => it.name(),
 +                ast::Struct(it) => it.name(),
 +                _ => None,
 +            }
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +fn is_enum_lit_name_ref(
 +    sema: &Semantics<'_, RootDatabase>,
 +    enum_: hir::Enum,
 +    name_ref: &ast::NameRef,
 +) -> bool {
 +    let path_is_variant_of_enum = |path: ast::Path| {
 +        matches!(
 +            sema.resolve_path(&path),
 +            Some(PathResolution::Def(hir::ModuleDef::Variant(variant)))
 +                if variant.parent_enum(sema.db) == enum_
 +        )
 +    };
 +    name_ref
 +        .syntax()
 +        .ancestors()
 +        .find_map(|ancestor| {
 +            match_ast! {
 +                match ancestor {
 +                    ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum),
 +                    ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum),
 +                    _ => None,
 +                }
 +            }
 +        })
 +        .unwrap_or(false)
 +}
 +
 +fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
 +    path.and_then(|path| path.segment())
 +        .and_then(|segment| segment.name_ref())
 +        .map_or(false, |segment| segment == *name_ref)
 +}
 +
 +fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
 +    name_ref.syntax().ancestors().find_map(|ancestor| {
 +        match_ast! {
 +            match ancestor {
 +                ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)),
 +                ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)),
 +                _ => None,
 +            }
 +        }
 +    }).unwrap_or(false)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +    use ide_db::{base_db::FileId, search::ReferenceCategory};
 +    use stdx::format_to;
 +
 +    use crate::{fixture, SearchScope};
 +
 +    #[test]
 +    fn test_struct_literal_after_space() {
 +        check(
 +            r#"
 +struct Foo $0{
 +    a: i32,
 +}
 +impl Foo {
 +    fn f() -> i32 { 42 }
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo {a: Foo::f()};
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..26 7..10
 +
 +                FileId(0) 101..104
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_struct_literal_before_space() {
 +        check(
 +            r#"
 +struct Foo$0 {}
 +    fn main() {
 +    let f: Foo;
 +    f = Foo {};
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..13 7..10
 +
 +                FileId(0) 41..44
 +                FileId(0) 54..57
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_struct_literal_with_generic_type() {
 +        check(
 +            r#"
 +struct Foo<T> $0{}
 +    fn main() {
 +    let f: Foo::<i32>;
 +    f = Foo {};
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..16 7..10
 +
 +                FileId(0) 64..67
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_struct_literal_for_tuple() {
 +        check(
 +            r#"
 +struct Foo$0(i32);
 +
 +fn main() {
 +    let f: Foo;
 +    f = Foo(1);
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..16 7..10
 +
 +                FileId(0) 54..57
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_struct_literal_for_union() {
 +        check(
 +            r#"
 +union Foo $0{
 +    x: u32
 +}
 +
 +fn main() {
 +    let f: Foo;
 +    f = Foo { x: 1 };
 +}
 +"#,
 +            expect![[r#"
 +                Foo Union FileId(0) 0..24 6..9
 +
 +                FileId(0) 62..65
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_enum_after_space() {
 +        check(
 +            r#"
 +enum Foo $0{
 +    A,
 +    B(),
 +    C{},
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo::A;
 +    f = Foo::B();
 +    f = Foo::C{};
 +}
 +"#,
 +            expect![[r#"
 +                Foo Enum FileId(0) 0..37 5..8
 +
 +                FileId(0) 74..77
 +                FileId(0) 90..93
 +                FileId(0) 108..111
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_variant_record_after_space() {
 +        check(
 +            r#"
 +enum Foo {
 +    A $0{ n: i32 },
 +    B,
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo::B;
 +    f = Foo::A { n: 92 };
 +}
 +"#,
 +            expect![[r#"
 +                A Variant FileId(0) 15..27 15..16
 +
 +                FileId(0) 95..96
 +            "#]],
 +        );
 +    }
 +    #[test]
 +    fn test_variant_tuple_before_paren() {
 +        check(
 +            r#"
 +enum Foo {
 +    A$0(i32),
 +    B,
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo::B;
 +    f = Foo::A(92);
 +}
 +"#,
 +            expect![[r#"
 +                A Variant FileId(0) 15..21 15..16
 +
 +                FileId(0) 89..90
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_enum_before_space() {
 +        check(
 +            r#"
 +enum Foo$0 {
 +    A,
 +    B,
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo::A;
 +}
 +"#,
 +            expect![[r#"
 +                Foo Enum FileId(0) 0..26 5..8
 +
 +                FileId(0) 50..53
 +                FileId(0) 63..66
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_enum_with_generic_type() {
 +        check(
 +            r#"
 +enum Foo<T> $0{
 +    A(T),
 +    B,
 +}
 +fn main() {
 +    let f: Foo<i8>;
 +    f = Foo::A(1);
 +}
 +"#,
 +            expect![[r#"
 +                Foo Enum FileId(0) 0..32 5..8
 +
 +                FileId(0) 73..76
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_enum_for_tuple() {
 +        check(
 +            r#"
 +enum Foo$0{
 +    A(i8),
 +    B(i8),
 +}
 +fn main() {
 +    let f: Foo;
 +    f = Foo::A(1);
 +}
 +"#,
 +            expect![[r#"
 +                Foo Enum FileId(0) 0..33 5..8
 +
 +                FileId(0) 70..73
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_for_local() {
 +        check(
 +            r#"
 +fn main() {
 +    let mut i = 1;
 +    let j = 1;
 +    i = i$0 + j;
 +
 +    {
 +        i = 0;
 +    }
 +
 +    i = 5;
 +}"#,
 +            expect![[r#"
 +                i Local FileId(0) 20..25 24..25 Write
 +
 +                FileId(0) 50..51 Write
 +                FileId(0) 54..55 Read
 +                FileId(0) 76..77 Write
 +                FileId(0) 94..95 Write
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn search_filters_by_range() {
 +        check(
 +            r#"
 +fn foo() {
 +    let spam$0 = 92;
 +    spam + spam
 +}
 +fn bar() {
 +    let spam = 92;
 +    spam + spam
 +}
 +"#,
 +            expect![[r#"
 +                spam Local FileId(0) 19..23 19..23
 +
 +                FileId(0) 34..38 Read
 +                FileId(0) 41..45 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_for_param_inside() {
 +        check(
 +            r#"
 +fn foo(i : u32) -> u32 { i$0 }
 +"#,
 +            expect![[r#"
 +                i ValueParam FileId(0) 7..8 7..8
 +
 +                FileId(0) 25..26 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_for_fn_param() {
 +        check(
 +            r#"
 +fn foo(i$0 : u32) -> u32 { i }
 +"#,
 +            expect![[r#"
 +                i ValueParam FileId(0) 7..8 7..8
 +
 +                FileId(0) 25..26 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_field_name() {
 +        check(
 +            r#"
 +//- /lib.rs
 +struct Foo {
 +    pub spam$0: u32,
 +}
 +
 +fn main(s: Foo) {
 +    let f = s.spam;
 +}
 +"#,
 +            expect![[r#"
 +                spam Field FileId(0) 17..30 21..25
 +
 +                FileId(0) 67..71 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_impl_item_name() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn f$0(&self) {  }
 +}
 +"#,
 +            expect![[r#"
 +                f Function FileId(0) 27..43 30..31
 +
 +                (no references)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_enum_var_name() {
 +        check(
 +            r#"
 +enum Foo {
 +    A,
 +    B$0,
 +    C,
 +}
 +"#,
 +            expect![[r#"
 +                B Variant FileId(0) 22..23 22..23
 +
 +                (no references)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_enum_var_field() {
 +        check(
 +            r#"
 +enum Foo {
 +    A,
 +    B { field$0: u8 },
 +    C,
 +}
 +"#,
 +            expect![[r#"
 +                field Field FileId(0) 26..35 26..31
 +
 +                (no references)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_two_modules() {
 +        check(
 +            r#"
 +//- /lib.rs
 +pub mod foo;
 +pub mod bar;
 +
 +fn f() {
 +    let i = foo::Foo { n: 5 };
 +}
 +
 +//- /foo.rs
 +use crate::bar;
 +
 +pub struct Foo {
 +    pub n: u32,
 +}
 +
 +fn f() {
 +    let i = bar::Bar { n: 5 };
 +}
 +
 +//- /bar.rs
 +use crate::foo;
 +
 +pub struct Bar {
 +    pub n: u32,
 +}
 +
 +fn f() {
 +    let i = foo::Foo$0 { n: 5 };
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(1) 17..51 28..31
 +
 +                FileId(0) 53..56
 +                FileId(2) 79..82
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_decl_module() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo$0;
 +
 +use foo::Foo;
 +
 +fn f() {
 +    let i = Foo { n: 5 };
 +}
 +
 +//- /foo.rs
 +pub struct Foo {
 +    pub n: u32,
 +}
 +"#,
 +            expect![[r#"
 +                foo Module FileId(0) 0..8 4..7
 +
-                 FileId(1) 4..8
++                FileId(0) 14..17 Import
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_decl_module_on_self() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo;
 +
 +//- /foo.rs
 +use self$0;
 +"#,
 +            expect![[r#"
 +                foo Module FileId(0) 0..8 4..7
 +
-                 FileId(0) 4..8
++                FileId(1) 4..8 Import
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_decl_module_on_self_crate_root() {
 +        check(
 +            r#"
 +//- /lib.rs
 +use self$0;
 +"#,
 +            expect![[r#"
 +                Module FileId(0) 0..10
 +
-                 FileId(1) 20..23
++                FileId(0) 4..8 Import
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_super_mod_vis() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo;
 +
 +//- /foo.rs
 +mod some;
 +use some::Foo;
 +
 +fn f() {
 +    let i = Foo { n: 5 };
 +}
 +
 +//- /foo/some.rs
 +pub(super) struct Foo$0 {
 +    pub n: u32,
 +}
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(2) 0..41 18..21
 +
-                 FileId(1) 11..12
++                FileId(1) 20..23 Import
 +                FileId(1) 47..50
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_with_scope() {
 +        let code = r#"
 +            //- /lib.rs
 +            mod foo;
 +            mod bar;
 +
 +            pub fn quux$0() {}
 +
 +            //- /foo.rs
 +            fn f() { super::quux(); }
 +
 +            //- /bar.rs
 +            fn f() { super::quux(); }
 +        "#;
 +
 +        check_with_scope(
 +            code,
 +            None,
 +            expect![[r#"
 +                quux Function FileId(0) 19..35 26..30
 +
 +                FileId(1) 16..20
 +                FileId(2) 16..20
 +            "#]],
 +        );
 +
 +        check_with_scope(
 +            code,
 +            Some(SearchScope::single_file(FileId(2))),
 +            expect![[r#"
 +                quux Function FileId(0) 19..35 26..30
 +
 +                FileId(2) 16..20
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_macro_def() {
 +        check(
 +            r#"
 +#[macro_export]
 +macro_rules! m1$0 { () => (()) }
 +
 +fn foo() {
 +    m1();
 +    m1();
 +}
 +"#,
 +            expect![[r#"
 +                m1 Macro FileId(0) 0..46 29..31
 +
 +                FileId(0) 63..65
 +                FileId(0) 73..75
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_basic_highlight_read_write() {
 +        check(
 +            r#"
 +fn foo() {
 +    let mut i$0 = 0;
 +    i = i + 1;
 +}
 +"#,
 +            expect![[r#"
 +                i Local FileId(0) 19..24 23..24 Write
 +
 +                FileId(0) 34..35 Write
 +                FileId(0) 38..39 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_basic_highlight_field_read_write() {
 +        check(
 +            r#"
 +struct S {
 +    f: u32,
 +}
 +
 +fn foo() {
 +    let mut s = S{f: 0};
 +    s.f$0 = 0;
 +}
 +"#,
 +            expect![[r#"
 +                f Field FileId(0) 15..21 15..16
 +
 +                FileId(0) 55..56 Read
 +                FileId(0) 68..69 Write
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_basic_highlight_decl_no_write() {
 +        check(
 +            r#"
 +fn foo() {
 +    let i$0;
 +    i = 1;
 +}
 +"#,
 +            expect![[r#"
 +                i Local FileId(0) 19..20 19..20
 +
 +                FileId(0) 26..27 Write
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_struct_function_refs_outside_module() {
 +        check(
 +            r#"
 +mod foo {
 +    pub struct Foo;
 +
 +    impl Foo {
 +        pub fn new$0() -> Foo { Foo }
 +    }
 +}
 +
 +fn main() {
 +    let _f = foo::Foo::new();
 +}
 +"#,
 +            expect![[r#"
 +                new Function FileId(0) 54..81 61..64
 +
 +                FileId(0) 126..129
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_nested_module() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo { mod bar; }
 +
 +fn f$0() {}
 +
 +//- /foo/bar.rs
 +use crate::f;
 +
 +fn g() { f(); }
 +"#,
 +            expect![[r#"
 +                f Function FileId(0) 22..31 25..26
 +
-                 FileId(1) 16..19
-                 FileId(2) 16..19
-                 FileId(3) 16..19
++                FileId(1) 11..12 Import
 +                FileId(1) 24..25
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_struct_pat() {
 +        check(
 +            r#"
 +struct S {
 +    field$0: u8,
 +}
 +
 +fn f(s: S) {
 +    match s {
 +        S { field } => {}
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                field Field FileId(0) 15..24 15..20
 +
 +                FileId(0) 68..73 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_enum_var_pat() {
 +        check(
 +            r#"
 +enum En {
 +    Variant {
 +        field$0: u8,
 +    }
 +}
 +
 +fn f(e: En) {
 +    match e {
 +        En::Variant { field } => {}
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                field Field FileId(0) 32..41 32..37
 +
 +                FileId(0) 102..107 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_all_refs_enum_var_privacy() {
 +        check(
 +            r#"
 +mod m {
 +    pub enum En {
 +        Variant {
 +            field$0: u8,
 +        }
 +    }
 +}
 +
 +fn f() -> m::En {
 +    m::En::Variant { field: 0 }
 +}
 +"#,
 +            expect![[r#"
 +                field Field FileId(0) 56..65 56..61
 +
 +                FileId(0) 125..130 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_self_refs() {
 +        check(
 +            r#"
 +struct Foo { bar: i32 }
 +
 +impl Foo {
 +    fn foo(self) {
 +        let x = self$0.bar;
 +        if true {
 +            let _ = match () {
 +                () => self,
 +            };
 +        }
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                self SelfParam FileId(0) 47..51 47..51
 +
 +                FileId(0) 71..75 Read
 +                FileId(0) 152..156 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_self_refs_decl() {
 +        check(
 +            r#"
 +struct Foo { bar: i32 }
 +
 +impl Foo {
 +    fn foo(self$0) {
 +        self;
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                self SelfParam FileId(0) 47..51 47..51
 +
 +                FileId(0) 63..67 Read
 +            "#]],
 +        );
 +    }
 +
 +    fn check(ra_fixture: &str, expect: Expect) {
 +        check_with_scope(ra_fixture, None, expect)
 +    }
 +
 +    fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
 +        let (analysis, pos) = fixture::position(ra_fixture);
 +        let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
 +
 +        let mut actual = String::new();
 +        for refs in refs {
 +            actual += "\n\n";
 +
 +            if let Some(decl) = refs.declaration {
 +                format_to!(actual, "{}", decl.nav.debug_render());
 +                if decl.is_mut {
 +                    format_to!(actual, " {:?}", ReferenceCategory::Write)
 +                }
 +                actual += "\n\n";
 +            }
 +
 +            for (file_id, references) in &refs.references {
 +                for (range, access) in references {
 +                    format_to!(actual, "{:?} {:?}", file_id, range);
 +                    if let Some(access) = access {
 +                        format_to!(actual, " {:?}", access);
 +                    }
 +                    actual += "\n";
 +                }
 +            }
 +
 +            if refs.references.is_empty() {
 +                actual += "(no references)\n";
 +            }
 +        }
 +        expect.assert_eq(actual.trim_start())
 +    }
 +
 +    #[test]
 +    fn test_find_lifetimes_function() {
 +        check(
 +            r#"
 +trait Foo<'a> {}
 +impl<'a> Foo<'a> for &'a () {}
 +fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
 +    fn bar<'a>(_: &'a ()) {}
 +    x
 +}
 +"#,
 +            expect![[r#"
 +                'a LifetimeParam FileId(0) 55..57 55..57
 +
 +                FileId(0) 63..65
 +                FileId(0) 71..73
 +                FileId(0) 82..84
 +                FileId(0) 95..97
 +                FileId(0) 106..108
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_lifetimes_type_alias() {
 +        check(
 +            r#"
 +type Foo<'a, T> where T: 'a$0 = &'a T;
 +"#,
 +            expect![[r#"
 +                'a LifetimeParam FileId(0) 9..11 9..11
 +
 +                FileId(0) 25..27
 +                FileId(0) 31..33
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_lifetimes_trait_impl() {
 +        check(
 +            r#"
 +trait Foo<'a> {
 +    fn foo() -> &'a ();
 +}
 +impl<'a> Foo<'a> for &'a () {
 +    fn foo() -> &'a$0 () {
 +        unimplemented!()
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                'a LifetimeParam FileId(0) 47..49 47..49
 +
 +                FileId(0) 55..57
 +                FileId(0) 64..66
 +                FileId(0) 89..91
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_map_range_to_original() {
 +        check(
 +            r#"
 +macro_rules! foo {($i:ident) => {$i} }
 +fn main() {
 +    let a$0 = "test";
 +    foo!(a);
 +}
 +"#,
 +            expect![[r#"
 +                a Local FileId(0) 59..60 59..60
 +
 +                FileId(0) 80..81 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_map_range_to_original_ref() {
 +        check(
 +            r#"
 +macro_rules! foo {($i:ident) => {$i} }
 +fn main() {
 +    let a = "test";
 +    foo!(a$0);
 +}
 +"#,
 +            expect![[r#"
 +                a Local FileId(0) 59..60 59..60
 +
 +                FileId(0) 80..81 Read
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_labels() {
 +        check(
 +            r#"
 +fn foo<'a>() -> &'a () {
 +    'a: loop {
 +        'b: loop {
 +            continue 'a$0;
 +        }
 +        break 'a;
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                'a Label FileId(0) 29..32 29..31
 +
 +                FileId(0) 80..82
 +                FileId(0) 108..110
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_find_const_param() {
 +        check(
 +            r#"
 +fn foo<const FOO$0: usize>() -> usize {
 +    FOO
 +}
 +"#,
 +            expect![[r#"
 +                FOO ConstParam FileId(0) 7..23 13..16
 +
 +                FileId(0) 42..45
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_trait() {
 +        check(
 +            r#"
 +trait Foo$0 where Self: {}
 +
 +impl Foo for () {}
 +"#,
 +            expect![[r#"
 +                Foo Trait FileId(0) 0..24 6..9
 +
 +                FileId(0) 31..34
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_trait_self() {
 +        check(
 +            r#"
 +trait Foo where Self$0 {
 +    fn f() -> Self;
 +}
 +
 +impl Foo for () {}
 +"#,
 +            expect![[r#"
 +                Self TypeParam FileId(0) 6..9 6..9
 +
 +                FileId(0) 16..20
 +                FileId(0) 37..41
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_self_ty() {
 +        check(
 +            r#"
 +        struct $0Foo;
 +
 +        impl Foo where Self: {
 +            fn f() -> Self;
 +        }
 +        "#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..11 7..10
 +
 +                FileId(0) 18..21
 +                FileId(0) 28..32
 +                FileId(0) 50..54
 +            "#]],
 +        );
 +        check(
 +            r#"
 +struct Foo;
 +
 +impl Foo where Self: {
 +    fn f() -> Self$0;
 +}
 +"#,
 +            expect![[r#"
 +                impl Impl FileId(0) 13..57 18..21
 +
 +                FileId(0) 18..21
 +                FileId(0) 28..32
 +                FileId(0) 50..54
 +            "#]],
 +        );
 +    }
 +    #[test]
 +    fn test_self_variant_with_payload() {
 +        check(
 +            r#"
 +enum Foo { Bar() }
 +
 +impl Foo {
 +    fn foo(self) {
 +        match self {
 +            Self::Bar$0() => (),
 +        }
 +    }
 +}
 +
 +"#,
 +            expect![[r#"
 +                Bar Variant FileId(0) 11..16 11..14
 +
 +                FileId(0) 89..92
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_attr_differs_from_fn_with_same_name() {
 +        check(
 +            r#"
 +#[test]
 +fn test$0() {
 +    test();
 +}
 +"#,
 +            expect![[r#"
 +                test Function FileId(0) 0..33 11..15
 +
 +                FileId(0) 24..28
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_const_in_pattern() {
 +        check(
 +            r#"
 +const A$0: i32 = 42;
 +
 +fn main() {
 +    match A {
 +        A => (),
 +        _ => (),
 +    }
 +    if let A = A {}
 +}
 +"#,
 +            expect![[r#"
 +                A Const FileId(0) 0..18 6..7
 +
 +                FileId(0) 42..43
 +                FileId(0) 54..55
 +                FileId(0) 97..98
 +                FileId(0) 101..102
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_primitives() {
 +        check(
 +            r#"
 +fn foo(_: bool) -> bo$0ol { true }
 +"#,
 +            expect![[r#"
 +                FileId(0) 10..14
 +                FileId(0) 19..23
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_transitive() {
 +        check(
 +            r#"
 +//- /level3.rs new_source_root:local crate:level3
 +pub struct Fo$0o;
 +//- /level2.rs new_source_root:local crate:level2 deps:level3
 +pub use level3::Foo;
 +//- /level1.rs new_source_root:local crate:level1 deps:level2
 +pub use level2::Foo;
 +//- /level0.rs new_source_root:local crate:level0 deps:level1
 +pub use level1::Foo;
 +"#,
 +            expect![[r#"
 +                Foo Struct FileId(0) 0..15 11..14
 +
-                 FileId(0) 46..49
++                FileId(1) 16..19 Import
++                FileId(2) 16..19 Import
++                FileId(3) 16..19 Import
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_decl_macro_references() {
 +        check(
 +            r#"
 +//- /lib.rs crate:lib
 +#[macro_use]
 +mod qux;
 +mod bar;
 +
 +pub use self::foo;
 +//- /qux.rs
 +#[macro_export]
 +macro_rules! foo$0 {
 +    () => {struct Foo;};
 +}
 +//- /bar.rs
 +foo!();
 +//- /other.rs crate:other deps:lib new_source_root:local
 +lib::foo!();
 +"#,
 +            expect![[r#"
 +                foo Macro FileId(1) 0..61 29..32
 +
-                 FileId(0) 17..31
++                FileId(0) 46..49 Import
 +                FileId(2) 0..3
 +                FileId(3) 5..8
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_doesnt_reference_attribute_on_call() {
 +        check(
 +            r#"
 +macro_rules! m {
 +    () => {};
 +}
 +
 +#[proc_macro_test::attr_noop]
 +m$0!();
 +
 +"#,
 +            expect![[r#"
 +                m Macro FileId(0) 0..32 13..14
 +
 +                FileId(0) 64..65
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multi_def() {
 +        check(
 +            r#"
 +macro_rules! m {
 +    ($name:ident) => {
 +        mod module {
 +            pub fn $name() {}
 +        }
 +
 +        pub fn $name() {}
 +    }
 +}
 +
 +m!(func$0);
 +
 +fn f() {
 +    func();
 +    module::func();
 +}
 +            "#,
 +            expect![[r#"
 +                func Function FileId(0) 137..146 140..144
 +
 +                FileId(0) 161..165
 +
 +
 +                func Function FileId(0) 137..146 140..144
 +
 +                FileId(0) 181..185
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn attr_expanded() {
 +        check(
 +            r#"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +fn func$0() {
 +    func();
 +}
 +"#,
 +            expect![[r#"
 +                func Function FileId(0) 25..50 28..32
 +
 +                FileId(0) 41..45
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn attr_assoc_item() {
 +        check(
 +            r#"
 +//- proc_macros: identity
 +
 +trait Trait {
 +    #[proc_macros::identity]
 +    fn func() {
 +        Self::func$0();
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                func Function FileId(0) 48..87 51..55
 +
 +                FileId(0) 74..78
 +            "#]],
 +        )
 +    }
 +
 +    // FIXME: import is classified as function
 +    #[test]
 +    fn attr() {
 +        check(
 +            r#"
 +//- proc_macros: identity
 +use proc_macros::identity;
 +
 +#[proc_macros::$0identity]
 +fn func() {}
 +"#,
 +            expect![[r#"
 +                identity Attribute FileId(1) 1..107 32..40
 +
 +                FileId(0) 43..51
 +            "#]],
 +        );
 +        check(
 +            r#"
 +#![crate_type="proc-macro"]
 +#[proc_macro_attribute]
 +fn func$0() {}
 +"#,
 +            expect![[r#"
 +                func Attribute FileId(0) 28..64 55..59
 +
 +                (no references)
 +            "#]],
 +        );
 +    }
 +
 +    // FIXME: import is classified as function
 +    #[test]
 +    fn proc_macro() {
 +        check(
 +            r#"
 +//- proc_macros: mirror
 +use proc_macros::mirror;
 +
 +mirror$0! {}
 +"#,
 +            expect![[r#"
 +                mirror Macro FileId(1) 1..77 22..28
 +
 +                FileId(0) 26..32
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn derive() {
 +        check(
 +            r#"
 +//- proc_macros: derive_identity
 +//- minicore: derive
 +use proc_macros::DeriveIdentity;
 +
 +#[derive(proc_macros::DeriveIdentity$0)]
 +struct Foo;
 +"#,
 +            expect![[r#"
 +                derive_identity Derive FileId(2) 1..107 45..60
 +
++                FileId(0) 17..31 Import
 +                FileId(0) 56..70
 +            "#]],
 +        );
 +        check(
 +            r#"
 +#![crate_type="proc-macro"]
 +#[proc_macro_derive(Derive, attributes(x))]
 +pub fn deri$0ve(_stream: TokenStream) -> TokenStream {}
 +"#,
 +            expect![[r#"
 +                derive Derive FileId(0) 28..125 79..85
 +
 +                (no references)
 +            "#]],
 +        );
 +    }
 +}
index c1aa14d6b7e74d715920d9a2dea2992bd0cbf4e3,0000000000000000000000000000000000000000..139a8cb8cbe589b9e586cdf6c8c0f94c36126e54
mode 100644,000000..100644
--- /dev/null
@@@ -1,914 -1,0 +1,905 @@@
-         let mut bindings = Bindings::default();
-         self.build_inner(&mut bindings, &self.nodes[idx.0]);
-         bindings
 +//! An NFA-based parser, which is porting from rustc mbe parsing code
 +//!
 +//! See <https://github.com/rust-lang/rust/blob/70b18bc2cbac4712020019f5bf57c00905373205/compiler/rustc_expand/src/mbe/macro_parser.rs>
 +//! Here is a quick intro to how the parser works, copied from rustc:
 +//!
 +//! A 'position' is a dot in the middle of a matcher, usually represented as a
 +//! dot. For example `· a $( a )* a b` is a position, as is `a $( · a )* a b`.
 +//!
 +//! The parser walks through the input a character at a time, maintaining a list
 +//! of threads consistent with the current position in the input string: `cur_items`.
 +//!
 +//! As it processes them, it fills up `eof_items` with threads that would be valid if
 +//! the macro invocation is now over, `bb_items` with threads that are waiting on
 +//! a Rust non-terminal like `$e:expr`, and `next_items` with threads that are waiting
 +//! on a particular token. Most of the logic concerns moving the · through the
 +//! repetitions indicated by Kleene stars. The rules for moving the · without
 +//! consuming any input are called epsilon transitions. It only advances or calls
 +//! out to the real Rust parser when no `cur_items` threads remain.
 +//!
 +//! Example:
 +//!
 +//! ```text, ignore
 +//! Start parsing a a a a b against [· a $( a )* a b].
 +//!
 +//! Remaining input: a a a a b
 +//! next: [· a $( a )* a b]
 +//!
 +//! - - - Advance over an a. - - -
 +//!
 +//! Remaining input: a a a b
 +//! cur: [a · $( a )* a b]
 +//! Descend/Skip (first item).
 +//! next: [a $( · a )* a b]  [a $( a )* · a b].
 +//!
 +//! - - - Advance over an a. - - -
 +//!
 +//! Remaining input: a a b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over an a. - - - (this looks exactly like the last step)
 +//!
 +//! Remaining input: a b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over an a. - - - (this looks exactly like the last step)
 +//!
 +//! Remaining input: b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over a b. - - -
 +//!
 +//! Remaining input: ''
 +//! eof: [a $( a )* a b ·]
 +//! ```
 +
 +use std::rc::Rc;
 +
 +use smallvec::{smallvec, SmallVec};
 +use syntax::SmolStr;
 +
 +use crate::{
 +    expander::{Binding, Bindings, ExpandResult, Fragment},
 +    parser::{Op, RepeatKind, Separator},
 +    tt_iter::TtIter,
 +    ExpandError, MetaTemplate,
 +};
 +
 +impl Bindings {
 +    fn push_optional(&mut self, name: &SmolStr) {
 +        // FIXME: Do we have a better way to represent an empty token ?
 +        // Insert an empty subtree for empty token
 +        let tt = tt::Subtree::default().into();
 +        self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
 +    }
 +
 +    fn push_empty(&mut self, name: &SmolStr) {
 +        self.inner.insert(name.clone(), Binding::Empty);
 +    }
 +
 +    fn bindings(&self) -> impl Iterator<Item = &Binding> {
 +        self.inner.values()
 +    }
 +}
 +
 +#[derive(Clone, Debug, Default, PartialEq, Eq)]
 +pub(super) struct Match {
 +    pub(super) bindings: Bindings,
 +    /// We currently just keep the first error and count the rest to compare matches.
 +    pub(super) err: Option<ExpandError>,
 +    pub(super) err_count: usize,
 +    /// How many top-level token trees were left to match.
 +    pub(super) unmatched_tts: usize,
 +    /// The number of bound variables
 +    pub(super) bound_count: usize,
 +}
 +
 +impl Match {
 +    fn add_err(&mut self, err: ExpandError) {
 +        let prev_err = self.err.take();
 +        self.err = prev_err.or(Some(err));
 +        self.err_count += 1;
 +    }
 +}
 +
 +/// Matching errors are added to the `Match`.
 +pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match {
 +    let mut res = match_loop(pattern, input);
 +    res.bound_count = count(res.bindings.bindings());
 +    return res;
 +
 +    fn count<'a>(bindings: impl Iterator<Item = &'a Binding>) -> usize {
 +        bindings
 +            .map(|it| match it {
 +                Binding::Fragment(_) => 1,
 +                Binding::Empty => 1,
 +                Binding::Nested(it) => count(it.iter()),
 +            })
 +            .sum()
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +enum BindingKind {
 +    Empty(SmolStr),
 +    Optional(SmolStr),
 +    Fragment(SmolStr, Fragment),
 +    Nested(usize, usize),
 +}
 +
 +#[derive(Debug, Clone)]
 +struct BindingsIdx(usize, usize);
 +
 +#[derive(Debug, Clone)]
 +enum LinkNode<T> {
 +    Node(T),
 +    Parent { idx: usize, len: usize },
 +}
 +
 +#[derive(Default)]
 +struct BindingsBuilder {
 +    nodes: Vec<Vec<LinkNode<Rc<BindingKind>>>>,
 +    nested: Vec<Vec<LinkNode<usize>>>,
 +}
 +
 +impl BindingsBuilder {
 +    fn alloc(&mut self) -> BindingsIdx {
 +        let idx = self.nodes.len();
 +        self.nodes.push(Vec::new());
 +        let nidx = self.nested.len();
 +        self.nested.push(Vec::new());
 +        BindingsIdx(idx, nidx)
 +    }
 +
 +    fn copy(&mut self, bindings: &BindingsIdx) -> BindingsIdx {
 +        let idx = copy_parent(bindings.0, &mut self.nodes);
 +        let nidx = copy_parent(bindings.1, &mut self.nested);
 +        return BindingsIdx(idx, nidx);
 +
 +        fn copy_parent<T>(idx: usize, target: &mut Vec<Vec<LinkNode<T>>>) -> usize
 +        where
 +            T: Clone,
 +        {
 +            let new_idx = target.len();
 +            let len = target[idx].len();
 +            if len < 4 {
 +                target.push(target[idx].clone())
 +            } else {
 +                target.push(vec![LinkNode::Parent { idx, len }]);
 +            }
 +            new_idx
 +        }
 +    }
 +
 +    fn push_empty(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
 +        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Empty(var.clone()))));
 +    }
 +
 +    fn push_optional(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
 +        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone()))));
 +    }
 +
 +    fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) {
 +        self.nodes[idx.0]
 +            .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
 +    }
 +
 +    fn push_nested(&mut self, parent: &mut BindingsIdx, child: &BindingsIdx) {
 +        let BindingsIdx(idx, nidx) = self.copy(child);
 +        self.nodes[parent.0].push(LinkNode::Node(Rc::new(BindingKind::Nested(idx, nidx))));
 +    }
 +
 +    fn push_default(&mut self, idx: &mut BindingsIdx) {
 +        self.nested[idx.1].push(LinkNode::Node(idx.0));
 +        let new_idx = self.nodes.len();
 +        self.nodes.push(Vec::new());
 +        idx.0 = new_idx;
 +    }
 +
 +    fn build(self, idx: &BindingsIdx) -> Bindings {
-     fn build_inner(&self, bindings: &mut Bindings, link_nodes: &[LinkNode<Rc<BindingKind>>]) {
++        self.build_inner(&self.nodes[idx.0])
 +    }
 +
-             match &**cmd {
++    fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind>>]) -> Bindings {
++        let mut bindings = Bindings::default();
 +        let mut nodes = Vec::new();
 +        self.collect_nodes(link_nodes, &mut nodes);
 +
 +        for cmd in nodes {
-         nested_refs: &mut Vec<&'a Vec<LinkNode<Rc<BindingKind>>>>,
++            match cmd {
 +                BindingKind::Empty(name) => {
 +                    bindings.push_empty(name);
 +                }
 +                BindingKind::Optional(name) => {
 +                    bindings.push_optional(name);
 +                }
 +                BindingKind::Fragment(name, fragment) => {
 +                    bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone()));
 +                }
 +                BindingKind::Nested(idx, nested_idx) => {
 +                    let mut nested_nodes = Vec::new();
 +                    self.collect_nested(*idx, *nested_idx, &mut nested_nodes);
 +
 +                    for (idx, iter) in nested_nodes.into_iter().enumerate() {
 +                        for (key, value) in &iter.inner {
 +                            let bindings = bindings
 +                                .inner
 +                                .entry(key.clone())
 +                                .or_insert_with(|| Binding::Nested(Vec::new()));
 +
 +                            if let Binding::Nested(it) = bindings {
 +                                // insert empty nested bindings before this one
 +                                while it.len() < idx {
 +                                    it.push(Binding::Nested(Vec::new()));
 +                                }
 +                                it.push(value.clone());
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
++
++        bindings
 +    }
 +
 +    fn collect_nested_ref<'a>(
 +        &'a self,
 +        id: usize,
 +        len: usize,
-         let mut nested_refs = Vec::new();
++        nested_refs: &mut Vec<&'a [LinkNode<Rc<BindingKind>>]>,
 +    ) {
 +        self.nested[id].iter().take(len).for_each(|it| match it {
 +            LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]),
 +            LinkNode::Parent { idx, len } => self.collect_nested_ref(*idx, *len, nested_refs),
 +        });
 +    }
 +
 +    fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings>) {
 +        let last = &self.nodes[idx];
-         nested_refs.into_iter().for_each(|iter| {
-             let mut child_bindings = Bindings::default();
-             self.build_inner(&mut child_bindings, iter);
-             nested.push(child_bindings)
-         })
++        let mut nested_refs: Vec<&[_]> = Vec::new();
 +        self.nested[nested_idx].iter().for_each(|it| match *it {
 +            LinkNode::Node(idx) => nested_refs.push(&self.nodes[idx]),
 +            LinkNode::Parent { idx, len } => self.collect_nested_ref(idx, len, &mut nested_refs),
 +        });
 +        nested_refs.push(last);
-     fn collect_nodes_ref<'a>(
-         &'a self,
-         id: usize,
-         len: usize,
-         nodes: &mut Vec<&'a Rc<BindingKind>>,
-     ) {
++        nested.extend(nested_refs.into_iter().map(|iter| self.build_inner(iter)));
 +    }
 +
-         nodes: &mut Vec<&'a Rc<BindingKind>>,
++    fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind>) {
 +        self.nodes[id].iter().take(len).for_each(|it| match it {
 +            LinkNode::Node(it) => nodes.push(it),
 +            LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
 +        });
 +    }
 +
 +    fn collect_nodes<'a>(
 +        &'a self,
 +        link_nodes: &'a [LinkNode<Rc<BindingKind>>],
-                 if item.up.is_some() {
++        nodes: &mut Vec<&'a BindingKind>,
 +    ) {
 +        link_nodes.iter().for_each(|it| match it {
 +            LinkNode::Node(it) => nodes.push(it),
 +            LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
 +        });
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +struct MatchState<'t> {
 +    /// The position of the "dot" in this matcher
 +    dot: OpDelimitedIter<'t>,
 +
 +    /// Token subtree stack
 +    /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. )
 +    /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
 +    /// that where the bottom of the stack is the outermost matcher.
 +    stack: SmallVec<[OpDelimitedIter<'t>; 4]>,
 +
 +    /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
 +    /// before we enter the repetition.
 +    up: Option<Box<MatchState<'t>>>,
 +
 +    /// The separator if we are in a repetition.
 +    sep: Option<Separator>,
 +
 +    /// The KleeneOp of this sequence if we are in a repetition.
 +    sep_kind: Option<RepeatKind>,
 +
 +    /// Number of tokens of separator parsed
 +    sep_parsed: Option<usize>,
 +
 +    /// Matched meta variables bindings
 +    bindings: BindingsIdx,
 +
 +    /// Cached result of meta variable parsing
 +    meta_result: Option<(TtIter<'t>, ExpandResult<Option<Fragment>>)>,
 +
 +    /// Is error occuried in this state, will `poised` to "parent"
 +    is_error: bool,
 +}
 +
 +/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
 +/// produce more items in `next_items`, `eof_items`, and `bb_items`.
 +///
 +/// For more info about the how this happens, see the module-level doc comments and the inline
 +/// comments of this function.
 +///
 +/// # Parameters
 +///
 +/// - `src`: the current token of the parser.
 +/// - `stack`: the "parent" frames of the token tree
 +/// - `res`: the match result to store errors
 +/// - `cur_items`: the set of current items to be processed. This should be empty by the end of a
 +///   successful execution of this function.
 +/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
 +///   the function `parse`.
 +/// - `eof_items`: the set of items that would be valid if this was the EOF.
 +/// - `bb_items`: the set of items that are waiting for the black-box parser.
 +/// - `error_items`: the set of items in errors, used for error-resilient parsing
 +fn match_loop_inner<'t>(
 +    src: TtIter<'t>,
 +    stack: &[TtIter<'t>],
 +    res: &mut Match,
 +    bindings_builder: &mut BindingsBuilder,
 +    cur_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    bb_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    next_items: &mut Vec<MatchState<'t>>,
 +    eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    error_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +) {
 +    macro_rules! try_push {
 +        ($items: expr, $it:expr) => {
 +            if $it.is_error {
 +                error_items.push($it);
 +            } else {
 +                $items.push($it);
 +            }
 +        };
 +    }
 +
 +    while let Some(mut item) = cur_items.pop() {
 +        while item.dot.is_eof() {
 +            match item.stack.pop() {
 +                Some(frame) => {
 +                    item.dot = frame;
 +                    item.dot.next();
 +                }
 +                None => break,
 +            }
 +        }
 +        let op = match item.dot.peek() {
 +            None => {
 +                // We are at or past the end of the matcher of `item`.
-                         let mut new_pos = *item.up.clone().unwrap();
++                if let Some(up) = &item.up {
 +                    if item.sep_parsed.is_none() {
 +                        // Get the `up` matcher
-                     let sep_idx = *item.sep_parsed.as_ref().unwrap_or(&0);
++                        let mut new_pos = (**up).clone();
 +                        new_pos.bindings = bindings_builder.copy(&new_pos.bindings);
 +                        // Add matches from this repetition to the `matches` of `up`
 +                        bindings_builder.push_nested(&mut new_pos.bindings, &item.bindings);
 +
 +                        // Move the "dot" past the repetition in `up`
 +                        new_pos.dot.next();
 +                        new_pos.is_error = new_pos.is_error || item.is_error;
 +                        cur_items.push(new_pos);
 +                    }
 +
 +                    // Check if we need a separator.
 +                    // We check the separator one by one
++                    let sep_idx = item.sep_parsed.unwrap_or(0);
 +                    let sep_len = item.sep.as_ref().map_or(0, Separator::tt_count);
 +                    if item.sep.is_some() && sep_idx != sep_len {
 +                        let sep = item.sep.as_ref().unwrap();
 +                        if src.clone().expect_separator(sep, sep_idx) {
 +                            item.dot.next();
 +                            item.sep_parsed = Some(sep_idx + 1);
 +                            try_push!(next_items, item);
 +                        }
 +                    }
 +                    // We don't need a separator. Move the "dot" back to the beginning of the matcher
 +                    // and try to match again UNLESS we are only allowed to have _one_ repetition.
 +                    else if item.sep_kind != Some(RepeatKind::ZeroOrOne) {
 +                        item.dot = item.dot.reset();
 +                        item.sep_parsed = None;
 +                        bindings_builder.push_default(&mut item.bindings);
 +                        cur_items.push(item);
 +                    }
 +                } else {
 +                    // If we are not in a repetition, then being at the end of a matcher means that we have
 +                    // reached the potential end of the input.
 +                    try_push!(eof_items, item);
 +                }
 +                continue;
 +            }
 +            Some(it) => it,
 +        };
 +
 +        // We are in the middle of a matcher.
 +        match op {
 +            OpDelimited::Op(Op::Repeat { tokens, kind, separator }) => {
 +                if matches!(kind, RepeatKind::ZeroOrMore | RepeatKind::ZeroOrOne) {
 +                    let mut new_item = item.clone();
 +                    new_item.bindings = bindings_builder.copy(&new_item.bindings);
 +                    new_item.dot.next();
 +                    collect_vars(
 +                        &mut |s| {
 +                            bindings_builder.push_empty(&mut new_item.bindings, &s);
 +                        },
 +                        tokens,
 +                    );
 +                    cur_items.push(new_item);
 +                }
 +                cur_items.push(MatchState {
 +                    dot: tokens.iter_delimited(None),
 +                    stack: Default::default(),
 +                    up: Some(Box::new(item)),
 +                    sep: separator.clone(),
 +                    sep_kind: Some(*kind),
 +                    sep_parsed: None,
 +                    bindings: bindings_builder.alloc(),
 +                    meta_result: None,
 +                    is_error: false,
 +                })
 +            }
 +            OpDelimited::Op(Op::Subtree { tokens, delimiter }) => {
 +                if let Ok(subtree) = src.clone().expect_subtree() {
 +                    if subtree.delimiter_kind() == delimiter.map(|it| it.kind) {
 +                        item.stack.push(item.dot);
 +                        item.dot = tokens.iter_delimited(delimiter.as_ref());
 +                        cur_items.push(item);
 +                    }
 +                }
 +            }
 +            OpDelimited::Op(Op::Var { kind, name, .. }) => {
 +                if let Some(kind) = kind {
 +                    let mut fork = src.clone();
 +                    let match_res = match_meta_var(kind.as_str(), &mut fork);
 +                    match match_res.err {
 +                        None => {
 +                            // Some meta variables are optional (e.g. vis)
 +                            if match_res.value.is_some() {
 +                                item.meta_result = Some((fork, match_res));
 +                                try_push!(bb_items, item);
 +                            } else {
 +                                bindings_builder.push_optional(&mut item.bindings, name);
 +                                item.dot.next();
 +                                cur_items.push(item);
 +                            }
 +                        }
 +                        Some(err) => {
 +                            res.add_err(err);
 +                            if let Some(fragment) = match_res.value {
 +                                bindings_builder.push_fragment(&mut item.bindings, name, fragment);
 +                            }
 +                            item.is_error = true;
 +                            error_items.push(item);
 +                        }
 +                    }
 +                }
 +            }
 +            OpDelimited::Op(Op::Leaf(leaf)) => {
 +                if let Err(err) = match_leaf(leaf, &mut src.clone()) {
 +                    res.add_err(err);
 +                    item.is_error = true;
 +                } else {
 +                    item.dot.next();
 +                }
 +                try_push!(next_items, item);
 +            }
 +            OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. }) => {}
 +            OpDelimited::Open => {
 +                if matches!(src.clone().next(), Some(tt::TokenTree::Subtree(..))) {
 +                    item.dot.next();
 +                    try_push!(next_items, item);
 +                }
 +            }
 +            OpDelimited::Close => {
 +                let is_delim_closed = src.peek_n(0).is_none() && !stack.is_empty();
 +                if is_delim_closed {
 +                    item.dot.next();
 +                    try_push!(next_items, item);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
 +    let mut src = TtIter::new(src);
 +    let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new();
 +    let mut res = Match::default();
 +    let mut error_recover_item = None;
 +
 +    let mut bindings_builder = BindingsBuilder::default();
 +
 +    let mut cur_items = smallvec![MatchState {
 +        dot: pattern.iter_delimited(None),
 +        stack: Default::default(),
 +        up: None,
 +        sep: None,
 +        sep_kind: None,
 +        sep_parsed: None,
 +        bindings: bindings_builder.alloc(),
 +        is_error: false,
 +        meta_result: None,
 +    }];
 +
 +    let mut next_items = vec![];
 +
 +    loop {
 +        let mut bb_items = SmallVec::new();
 +        let mut eof_items = SmallVec::new();
 +        let mut error_items = SmallVec::new();
 +
 +        stdx::always!(next_items.is_empty());
 +
 +        match_loop_inner(
 +            src.clone(),
 +            &stack,
 +            &mut res,
 +            &mut bindings_builder,
 +            &mut cur_items,
 +            &mut bb_items,
 +            &mut next_items,
 +            &mut eof_items,
 +            &mut error_items,
 +        );
 +        stdx::always!(cur_items.is_empty());
 +
 +        if !error_items.is_empty() {
 +            error_recover_item = error_items.pop().map(|it| it.bindings);
 +        } else if let [state, ..] = &*eof_items {
 +            error_recover_item = Some(state.bindings.clone());
 +        }
 +
 +        // We need to do some post processing after the `match_loop_inner`.
 +        // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
 +        // either the parse is ambiguous (which should never happen) or there is a syntax error.
 +        if src.peek_n(0).is_none() && stack.is_empty() {
 +            if let [state] = &*eof_items {
 +                // remove all errors, because it is the correct answer !
 +                res = Match::default();
 +                res.bindings = bindings_builder.build(&state.bindings);
 +            } else {
 +                // Error recovery
 +                if let Some(item) = error_recover_item {
 +                    res.bindings = bindings_builder.build(&item);
 +                }
 +                res.add_err(ExpandError::UnexpectedToken);
 +            }
 +            return res;
 +        }
 +
 +        // If there are no possible next positions AND we aren't waiting for the black-box parser,
 +        // then there is a syntax error.
 +        //
 +        // Another possibility is that we need to call out to parse some rust nonterminal
 +        // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong.
 +        let has_leftover_tokens = (bb_items.is_empty() && next_items.is_empty())
 +            || !(bb_items.is_empty() || next_items.is_empty())
 +            || bb_items.len() > 1;
 +        if has_leftover_tokens {
 +            res.unmatched_tts += src.len();
 +            while let Some(it) = stack.pop() {
 +                src = it;
 +                res.unmatched_tts += src.len();
 +            }
 +            res.add_err(ExpandError::LeftoverTokens);
 +
 +            if let Some(error_reover_item) = error_recover_item {
 +                res.bindings = bindings_builder.build(&error_reover_item);
 +            }
 +            return res;
 +        }
 +        // Dump all possible `next_items` into `cur_items` for the next iteration.
 +        else if !next_items.is_empty() {
 +            // Now process the next token
 +            cur_items.extend(next_items.drain(..));
 +
 +            match src.next() {
 +                Some(tt::TokenTree::Subtree(subtree)) => {
 +                    stack.push(src.clone());
 +                    src = TtIter::new(subtree);
 +                }
 +                None => {
 +                    if let Some(iter) = stack.pop() {
 +                        src = iter;
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
 +        // Finally, we have the case where we need to call the black-box parser to get some
 +        // nonterminal.
 +        else {
 +            stdx::always!(bb_items.len() == 1);
 +            let mut item = bb_items.pop().unwrap();
 +
 +            if let Some(OpDelimited::Op(Op::Var { name, .. })) = item.dot.peek() {
 +                let (iter, match_res) = item.meta_result.take().unwrap();
 +                match match_res.value {
 +                    Some(fragment) => {
 +                        bindings_builder.push_fragment(&mut item.bindings, name, fragment);
 +                    }
 +                    None if match_res.err.is_none() => {
 +                        bindings_builder.push_optional(&mut item.bindings, name);
 +                    }
 +                    None => {}
 +                }
 +                if let Some(err) = match_res.err {
 +                    res.add_err(err);
 +                }
 +                src = iter.clone();
 +                item.dot.next();
 +            } else {
 +                unreachable!()
 +            }
 +            cur_items.push(item);
 +        }
 +        stdx::always!(!cur_items.is_empty());
 +    }
 +}
 +
 +fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter<'_>) -> Result<(), ExpandError> {
 +    let rhs = src
 +        .expect_leaf()
 +        .map_err(|()| ExpandError::binding_error(format!("expected leaf: `{lhs}`")))?;
 +    match (lhs, rhs) {
 +        (
 +            tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
 +            tt::Leaf::Punct(tt::Punct { char: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        (
 +            tt::Leaf::Ident(tt::Ident { text: lhs, .. }),
 +            tt::Leaf::Ident(tt::Ident { text: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        (
 +            tt::Leaf::Literal(tt::Literal { text: lhs, .. }),
 +            tt::Leaf::Literal(tt::Literal { text: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        _ => Err(ExpandError::UnexpectedToken),
 +    }
 +}
 +
 +fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
 +    let fragment = match kind {
 +        "path" => parser::PrefixEntryPoint::Path,
 +        "ty" => parser::PrefixEntryPoint::Ty,
 +        // FIXME: These two should actually behave differently depending on the edition.
 +        //
 +        // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html
 +        "pat" | "pat_param" => parser::PrefixEntryPoint::Pat,
 +        "stmt" => parser::PrefixEntryPoint::Stmt,
 +        "block" => parser::PrefixEntryPoint::Block,
 +        "meta" => parser::PrefixEntryPoint::MetaItem,
 +        "item" => parser::PrefixEntryPoint::Item,
 +        "vis" => parser::PrefixEntryPoint::Vis,
 +        "expr" => {
 +            // `expr` should not match underscores.
 +            // HACK: Macro expansion should not be done using "rollback and try another alternative".
 +            // rustc [explicitly checks the next token][0].
 +            // [0]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576
 +            match input.peek_n(0) {
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) if it.text == "_" => {
 +                    return ExpandResult::only_err(ExpandError::NoMatchingRule)
 +                }
 +                _ => {}
 +            };
 +            return input
 +                .expect_fragment(parser::PrefixEntryPoint::Expr)
 +                .map(|tt| tt.map(Fragment::Expr));
 +        }
 +        _ => {
 +            let tt_result = match kind {
 +                "ident" => input
 +                    .expect_ident()
 +                    .map(|ident| tt::Leaf::from(ident.clone()).into())
 +                    .map_err(|()| ExpandError::binding_error("expected ident")),
 +                "tt" => input
 +                    .expect_tt()
 +                    .map_err(|()| ExpandError::binding_error("expected token tree")),
 +                "lifetime" => input
 +                    .expect_lifetime()
 +                    .map_err(|()| ExpandError::binding_error("expected lifetime")),
 +                "literal" => {
 +                    let neg = input.eat_char('-');
 +                    input
 +                        .expect_literal()
 +                        .map(|literal| {
 +                            let lit = literal.clone();
 +                            match neg {
 +                                None => lit.into(),
 +                                Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
 +                                    delimiter: None,
 +                                    token_trees: vec![neg, lit.into()],
 +                                }),
 +                            }
 +                        })
 +                        .map_err(|()| ExpandError::binding_error("expected literal"))
 +                }
 +                _ => Err(ExpandError::UnexpectedToken),
 +            };
 +            return tt_result.map(|it| Some(Fragment::Tokens(it))).into();
 +        }
 +    };
 +    input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens))
 +}
 +
 +fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) {
 +    for op in pattern.iter() {
 +        match op {
 +            Op::Var { name, .. } => collector_fun(name.clone()),
 +            Op::Leaf(_) => (),
 +            Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
 +            Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
 +            Op::Ignore { .. } | Op::Index { .. } => {}
 +        }
 +    }
 +}
 +impl MetaTemplate {
 +    fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> {
 +        OpDelimitedIter { inner: &self.0, idx: 0, delimited }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +enum OpDelimited<'a> {
 +    Op(&'a Op),
 +    Open,
 +    Close,
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +struct OpDelimitedIter<'a> {
 +    inner: &'a [Op],
 +    delimited: Option<&'a tt::Delimiter>,
 +    idx: usize,
 +}
 +
 +impl<'a> OpDelimitedIter<'a> {
 +    fn is_eof(&self) -> bool {
 +        let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
 +        self.idx >= len
 +    }
 +
 +    fn peek(&self) -> Option<OpDelimited<'a>> {
 +        match self.delimited {
 +            None => self.inner.get(self.idx).map(OpDelimited::Op),
 +            Some(_) => match self.idx {
 +                0 => Some(OpDelimited::Open),
 +                i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
 +                i => self.inner.get(i - 1).map(OpDelimited::Op),
 +            },
 +        }
 +    }
 +
 +    fn reset(&self) -> Self {
 +        Self { inner: self.inner, idx: 0, delimited: self.delimited }
 +    }
 +}
 +
 +impl<'a> Iterator for OpDelimitedIter<'a> {
 +    type Item = OpDelimited<'a>;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        let res = self.peek();
 +        self.idx += 1;
 +        res
 +    }
 +
 +    fn size_hint(&self) -> (usize, Option<usize>) {
 +        let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
 +        let remain = len.saturating_sub(self.idx);
 +        (remain, Some(remain))
 +    }
 +}
 +
 +impl<'a> TtIter<'a> {
 +    fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
 +        let mut fork = self.clone();
 +        let ok = match separator {
 +            Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
 +                Ok(rhs) => rhs.text == lhs.text,
 +                Err(_) => false,
 +            },
 +            Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() {
 +                Ok(rhs) => match rhs {
 +                    tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
 +                    tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
 +                    tt::Leaf::Punct(_) => false,
 +                },
 +                Err(_) => false,
 +            },
 +            Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_punct() {
 +                Ok(rhs) => rhs.char == lhss[idx].char,
 +                Err(_) => false,
 +            },
 +            _ => false,
 +        };
 +        if ok {
 +            *self = fork;
 +        }
 +        ok
 +    }
 +
 +    fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
 +        match self.peek_n(0) {
 +            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => {
 +                return self.expect_lifetime();
 +            }
 +            _ => (),
 +        }
 +
 +        let tt = self.next().ok_or(())?.clone();
 +        let punct = match tt {
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
 +                punct
 +            }
 +            _ => return Ok(tt),
 +        };
 +
 +        let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
 +            (
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
 +            ) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)),
 +            (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None),
 +            _ => return Ok(tt),
 +        };
 +
 +        match (punct.char, second, third) {
 +            ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
 +                let tt2 = self.next().unwrap().clone();
 +                let tt3 = self.next().unwrap().clone();
 +                Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
 +            }
 +            ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
 +            | ('-' | '=' | '>', '>', _)
 +            | (':', ':', _)
 +            | ('.', '.', _)
 +            | ('&', '&', _)
 +            | ('<', '<', _)
 +            | ('|', '|', _) => {
 +                let tt2 = self.next().unwrap().clone();
 +                Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
 +            }
 +            _ => Ok(tt),
 +        }
 +    }
 +
 +    fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> {
 +        let punct = self.expect_punct()?;
 +        if punct.char != '\'' {
 +            return Err(());
 +        }
 +        let ident = self.expect_ident_or_underscore()?;
 +
 +        Ok(tt::Subtree {
 +            delimiter: None,
 +            token_trees: vec![
 +                tt::Leaf::Punct(*punct).into(),
 +                tt::Leaf::Ident(ident.clone()).into(),
 +            ],
 +        }
 +        .into())
 +    }
 +
 +    fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> {
 +        let mut fork = self.clone();
 +        match fork.expect_char(c) {
 +            Ok(_) => {
 +                let tt = self.next().cloned();
 +                *self = fork;
 +                tt
 +            }
 +            Err(_) => None,
 +        }
 +    }
 +}
index 84e772d1684a18e8c47bf85d56cd164fd60f416d,0000000000000000000000000000000000000000..837ea016193cdc4f6f22f80c65a27ebcd7bbc7d9
mode 100644,000000..100644
--- /dev/null
@@@ -1,262 -1,0 +1,264 @@@
 +//! Workspace information we get from cargo consists of two pieces. The first is
 +//! the output of `cargo metadata`. The second is the output of running
 +//! `build.rs` files (`OUT_DIR` env var, extra cfg flags) and compiling proc
 +//! macro.
 +//!
 +//! This module implements this second part. We use "build script" terminology
 +//! here, but it covers procedural macros as well.
 +
 +use std::{cell::RefCell, io, path::PathBuf, process::Command};
 +
 +use cargo_metadata::{camino::Utf8Path, Message};
 +use la_arena::ArenaMap;
 +use paths::AbsPathBuf;
 +use rustc_hash::FxHashMap;
 +use semver::Version;
 +use serde::Deserialize;
 +
 +use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package};
 +
 +#[derive(Debug, Default, Clone, PartialEq, Eq)]
 +pub struct WorkspaceBuildScripts {
 +    outputs: ArenaMap<Package, Option<BuildScriptOutput>>,
 +    error: Option<String>,
 +}
 +
 +#[derive(Debug, Clone, Default, PartialEq, Eq)]
 +pub(crate) struct BuildScriptOutput {
 +    /// List of config flags defined by this package's build script.
 +    pub(crate) cfgs: Vec<CfgFlag>,
 +    /// List of cargo-related environment variables with their value.
 +    ///
 +    /// If the package has a build script which defines environment variables,
 +    /// they can also be found here.
 +    pub(crate) envs: Vec<(String, String)>,
 +    /// Directory where a build script might place its output.
 +    pub(crate) out_dir: Option<AbsPathBuf>,
 +    /// Path to the proc-macro library file if this package exposes proc-macros.
 +    pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
 +}
 +
 +impl WorkspaceBuildScripts {
 +    fn build_command(config: &CargoConfig) -> Command {
 +        if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() {
 +            let mut cmd = Command::new(program);
 +            cmd.args(args);
++            cmd.envs(&config.extra_env);
 +            return cmd;
 +        }
 +
 +        let mut cmd = Command::new(toolchain::cargo());
++        cmd.envs(&config.extra_env);
 +
 +        cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 +
 +        // --all-targets includes tests, benches and examples in addition to the
 +        // default lib and bins. This is an independent concept from the --targets
 +        // flag below.
 +        cmd.arg("--all-targets");
 +
 +        if let Some(target) = &config.target {
 +            cmd.args(&["--target", target]);
 +        }
 +
 +        if config.all_features {
 +            cmd.arg("--all-features");
 +        } else {
 +            if config.no_default_features {
 +                cmd.arg("--no-default-features");
 +            }
 +            if !config.features.is_empty() {
 +                cmd.arg("--features");
 +                cmd.arg(config.features.join(" "));
 +            }
 +        }
 +
 +        cmd
 +    }
 +
 +    pub(crate) fn run(
 +        config: &CargoConfig,
 +        workspace: &CargoWorkspace,
 +        progress: &dyn Fn(String),
 +        toolchain: &Option<Version>,
 +    ) -> io::Result<WorkspaceBuildScripts> {
 +        const RUST_1_62: Version = Version::new(1, 62, 0);
 +
 +        match Self::run_(Self::build_command(config), config, workspace, progress) {
 +            Ok(WorkspaceBuildScripts { error: Some(error), .. })
 +                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
 +            {
 +                // building build scripts failed, attempt to build with --keep-going so
 +                // that we potentially get more build data
 +                let mut cmd = Self::build_command(config);
 +                cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
 +                let mut res = Self::run_(cmd, config, workspace, progress)?;
 +                res.error = Some(error);
 +                Ok(res)
 +            }
 +            res => res,
 +        }
 +    }
 +
 +    fn run_(
 +        mut cmd: Command,
 +        config: &CargoConfig,
 +        workspace: &CargoWorkspace,
 +        progress: &dyn Fn(String),
 +    ) -> io::Result<WorkspaceBuildScripts> {
 +        if config.wrap_rustc_in_build_scripts {
 +            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
 +            // that to compile only proc macros and build scripts during the initial
 +            // `cargo check`.
 +            let myself = std::env::current_exe()?;
 +            cmd.env("RUSTC_WRAPPER", myself);
 +            cmd.env("RA_RUSTC_WRAPPER", "1");
 +        }
 +
 +        cmd.current_dir(workspace.workspace_root());
 +
 +        let mut res = WorkspaceBuildScripts::default();
 +        let outputs = &mut res.outputs;
 +        // NB: Cargo.toml could have been modified between `cargo metadata` and
 +        // `cargo check`. We shouldn't assume that package ids we see here are
 +        // exactly those from `config`.
 +        let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
 +        for package in workspace.packages() {
 +            outputs.insert(package, None);
 +            by_id.insert(workspace[package].id.clone(), package);
 +        }
 +
 +        let errors = RefCell::new(String::new());
 +        let push_err = |err: &str| {
 +            let mut e = errors.borrow_mut();
 +            e.push_str(err);
 +            e.push('\n');
 +        };
 +
 +        tracing::info!("Running build scripts: {:?}", cmd);
 +        let output = stdx::process::spawn_with_streaming_output(
 +            cmd,
 +            &mut |line| {
 +                // Copy-pasted from existing cargo_metadata. It seems like we
 +                // should be using serde_stacker here?
 +                let mut deserializer = serde_json::Deserializer::from_str(line);
 +                deserializer.disable_recursion_limit();
 +                let message = Message::deserialize(&mut deserializer)
 +                    .unwrap_or_else(|_| Message::TextLine(line.to_string()));
 +
 +                match message {
 +                    Message::BuildScriptExecuted(message) => {
 +                        let package = match by_id.get(&message.package_id.repr) {
 +                            Some(&it) => it,
 +                            None => return,
 +                        };
 +                        let cfgs = {
 +                            let mut acc = Vec::new();
 +                            for cfg in message.cfgs {
 +                                match cfg.parse::<CfgFlag>() {
 +                                    Ok(it) => acc.push(it),
 +                                    Err(err) => {
 +                                        push_err(&format!(
 +                                            "invalid cfg from cargo-metadata: {}",
 +                                            err
 +                                        ));
 +                                        return;
 +                                    }
 +                                };
 +                            }
 +                            acc
 +                        };
 +                        // cargo_metadata crate returns default (empty) path for
 +                        // older cargos, which is not absolute, so work around that.
 +                        let out_dir = message.out_dir.into_os_string();
 +                        if !out_dir.is_empty() {
 +                            let data = outputs[package].get_or_insert_with(Default::default);
 +                            data.out_dir = Some(AbsPathBuf::assert(PathBuf::from(out_dir)));
 +                            data.cfgs = cfgs;
 +                        }
 +                        if !message.env.is_empty() {
 +                            outputs[package].get_or_insert_with(Default::default).envs =
 +                                message.env;
 +                        }
 +                    }
 +                    Message::CompilerArtifact(message) => {
 +                        let package = match by_id.get(&message.package_id.repr) {
 +                            Some(it) => *it,
 +                            None => return,
 +                        };
 +
 +                        progress(format!("metadata {}", message.target.name));
 +
 +                        if message.target.kind.iter().any(|k| k == "proc-macro") {
 +                            // Skip rmeta file
 +                            if let Some(filename) =
 +                                message.filenames.iter().find(|name| is_dylib(name))
 +                            {
 +                                let filename = AbsPathBuf::assert(PathBuf::from(&filename));
 +                                outputs[package]
 +                                    .get_or_insert_with(Default::default)
 +                                    .proc_macro_dylib_path = Some(filename);
 +                            }
 +                        }
 +                    }
 +                    Message::CompilerMessage(message) => {
 +                        progress(message.target.name);
 +
 +                        if let Some(diag) = message.message.rendered.as_deref() {
 +                            push_err(diag);
 +                        }
 +                    }
 +                    Message::BuildFinished(_) => {}
 +                    Message::TextLine(_) => {}
 +                    _ => {}
 +                }
 +            },
 +            &mut |line| {
 +                push_err(line);
 +            },
 +        )?;
 +
 +        for package in workspace.packages() {
 +            if let Some(package_build_data) = &mut outputs[package] {
 +                tracing::info!(
 +                    "{}: {:?}",
 +                    workspace[package].manifest.parent().display(),
 +                    package_build_data,
 +                );
 +                // inject_cargo_env(package, package_build_data);
 +                if let Some(out_dir) = &package_build_data.out_dir {
 +                    // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
 +                    if let Some(out_dir) = out_dir.as_os_str().to_str().map(|s| s.to_owned()) {
 +                        package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
 +                    }
 +                }
 +            }
 +        }
 +
 +        let mut errors = errors.into_inner();
 +        if !output.status.success() {
 +            if errors.is_empty() {
 +                errors = "cargo check failed".to_string();
 +            }
 +            res.error = Some(errors);
 +        }
 +
 +        Ok(res)
 +    }
 +
 +    pub fn error(&self) -> Option<&str> {
 +        self.error.as_deref()
 +    }
 +
 +    pub(crate) fn get_output(&self, idx: Package) -> Option<&BuildScriptOutput> {
 +        self.outputs.get(idx)?.as_ref()
 +    }
 +}
 +
 +// FIXME: File a better way to know if it is a dylib.
 +fn is_dylib(path: &Utf8Path) -> bool {
 +    match path.extension().map(|e| e.to_string().to_lowercase()) {
 +        None => false,
 +        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
 +    }
 +}
index eed955b42daae9816c97951a8250571257cd68cd,0000000000000000000000000000000000000000..736d80041bd5115ac5bc3701f6549ea6feb35e52
mode 100644,000000..100644
--- /dev/null
@@@ -1,504 -1,0 +1,528 @@@
-             .or_else(|| cargo_config_build_target(cargo_toml))
-             .or_else(|| rustc_discover_host_triple(cargo_toml));
 +//! See [`CargoWorkspace`].
 +
 +use std::iter;
 +use std::path::PathBuf;
++use std::str::from_utf8;
 +use std::{ops, process::Command};
 +
 +use anyhow::{Context, Result};
 +use base_db::Edition;
 +use cargo_metadata::{CargoOpt, MetadataCommand};
 +use la_arena::{Arena, Idx};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::FxHashMap;
 +use serde::Deserialize;
 +use serde_json::from_value;
 +
 +use crate::CfgOverrides;
 +use crate::{utf8_stdout, ManifestPath};
 +
 +/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 +/// workspace. It pretty closely mirrors `cargo metadata` output.
 +///
 +/// Note that internally, rust-analyzer uses a different structure:
 +/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
 +/// while this knows about `Packages` & `Targets`: purely cargo-related
 +/// concepts.
 +///
 +/// We use absolute paths here, `cargo metadata` guarantees to always produce
 +/// abs paths.
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct CargoWorkspace {
 +    packages: Arena<PackageData>,
 +    targets: Arena<TargetData>,
 +    workspace_root: AbsPathBuf,
 +}
 +
 +impl ops::Index<Package> for CargoWorkspace {
 +    type Output = PackageData;
 +    fn index(&self, index: Package) -> &PackageData {
 +        &self.packages[index]
 +    }
 +}
 +
 +impl ops::Index<Target> for CargoWorkspace {
 +    type Output = TargetData;
 +    fn index(&self, index: Target) -> &TargetData {
 +        &self.targets[index]
 +    }
 +}
 +
 +/// Describes how to set the rustc source directory.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum RustcSource {
 +    /// Explicit path for the rustc source directory.
 +    Path(AbsPathBuf),
 +    /// Try to automatically detect where the rustc source directory is.
 +    Discover,
 +}
 +
 +/// Crates to disable `#[cfg(test)]` on.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum UnsetTestCrates {
 +    None,
 +    Only(Vec<String>),
 +    All,
 +}
 +
 +impl Default for UnsetTestCrates {
 +    fn default() -> Self {
 +        Self::None
 +    }
 +}
 +
 +#[derive(Default, Clone, Debug, PartialEq, Eq)]
 +pub struct CargoConfig {
 +    /// Do not activate the `default` feature.
 +    pub no_default_features: bool,
 +
 +    /// Activate all available features
 +    pub all_features: bool,
 +
 +    /// List of features to activate.
 +    /// This will be ignored if `cargo_all_features` is true.
 +    pub features: Vec<String>,
 +
 +    /// rustc target
 +    pub target: Option<String>,
 +
 +    /// Don't load sysroot crates (`std`, `core` & friends). Might be useful
 +    /// when debugging isolated issues.
 +    pub no_sysroot: bool,
 +
 +    /// rustc private crate source
 +    pub rustc_source: Option<RustcSource>,
 +
 +    /// crates to disable `#[cfg(test)]` on
 +    pub unset_test_crates: UnsetTestCrates,
 +
 +    pub wrap_rustc_in_build_scripts: bool,
 +
 +    pub run_build_script_command: Option<Vec<String>>,
++
++    pub extra_env: FxHashMap<String, String>,
 +}
 +
 +impl CargoConfig {
 +    pub fn cfg_overrides(&self) -> CfgOverrides {
 +        match &self.unset_test_crates {
 +            UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()),
 +            UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective(
 +                unset_test_crates
 +                    .iter()
 +                    .cloned()
 +                    .zip(iter::repeat_with(|| {
 +                        cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())])
 +                            .unwrap()
 +                    }))
 +                    .collect(),
 +            ),
 +            UnsetTestCrates::All => CfgOverrides::Wildcard(
 +                cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(),
 +            ),
 +        }
 +    }
 +}
 +
 +pub type Package = Idx<PackageData>;
 +
 +pub type Target = Idx<TargetData>;
 +
 +/// Information associated with a cargo crate
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct PackageData {
 +    /// Version given in the `Cargo.toml`
 +    pub version: semver::Version,
 +    /// Name as given in the `Cargo.toml`
 +    pub name: String,
 +    /// Repository as given in the `Cargo.toml`
 +    pub repository: Option<String>,
 +    /// Path containing the `Cargo.toml`
 +    pub manifest: ManifestPath,
 +    /// Targets provided by the crate (lib, bin, example, test, ...)
 +    pub targets: Vec<Target>,
 +    /// Does this package come from the local filesystem (and is editable)?
 +    pub is_local: bool,
 +    // Whether this package is a member of the workspace
 +    pub is_member: bool,
 +    /// List of packages this package depends on
 +    pub dependencies: Vec<PackageDependency>,
 +    /// Rust edition for this package
 +    pub edition: Edition,
 +    /// Features provided by the crate, mapped to the features required by that feature.
 +    pub features: FxHashMap<String, Vec<String>>,
 +    /// List of features enabled on this package
 +    pub active_features: Vec<String>,
 +    /// String representation of package id
 +    pub id: String,
 +    /// The contents of [package.metadata.rust-analyzer]
 +    pub metadata: RustAnalyzerPackageMetaData,
 +}
 +
 +#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
 +pub struct RustAnalyzerPackageMetaData {
 +    pub rustc_private: bool,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct PackageDependency {
 +    pub pkg: Package,
 +    pub name: String,
 +    pub kind: DepKind,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
 +pub enum DepKind {
 +    /// Available to the library, binary, and dev targets in the package (but not the build script).
 +    Normal,
 +    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
 +    Dev,
 +    /// Available only to the build script target.
 +    Build,
 +}
 +
 +impl DepKind {
 +    fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
 +        let mut dep_kinds = Vec::new();
 +        if list.is_empty() {
 +            dep_kinds.push(Self::Normal);
 +        }
 +        for info in list {
 +            let kind = match info.kind {
 +                cargo_metadata::DependencyKind::Normal => Self::Normal,
 +                cargo_metadata::DependencyKind::Development => Self::Dev,
 +                cargo_metadata::DependencyKind::Build => Self::Build,
 +                cargo_metadata::DependencyKind::Unknown => continue,
 +            };
 +            dep_kinds.push(kind);
 +        }
 +        dep_kinds.sort_unstable();
 +        dep_kinds.dedup();
 +        dep_kinds.into_iter()
 +    }
 +}
 +
 +/// Information associated with a package's target
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct TargetData {
 +    /// Package that provided this target
 +    pub package: Package,
 +    /// Name as given in the `Cargo.toml` or generated from the file name
 +    pub name: String,
 +    /// Path to the main source file of the target
 +    pub root: AbsPathBuf,
 +    /// Kind of target
 +    pub kind: TargetKind,
 +    /// Is this target a proc-macro
 +    pub is_proc_macro: bool,
 +    /// Required features of the target without which it won't build
 +    pub required_features: Vec<String>,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum TargetKind {
 +    Bin,
 +    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
 +    Lib,
 +    Example,
 +    Test,
 +    Bench,
 +    BuildScript,
 +    Other,
 +}
 +
 +impl TargetKind {
 +    fn new(kinds: &[String]) -> TargetKind {
 +        for kind in kinds {
 +            return match kind.as_str() {
 +                "bin" => TargetKind::Bin,
 +                "test" => TargetKind::Test,
 +                "bench" => TargetKind::Bench,
 +                "example" => TargetKind::Example,
 +                "custom-build" => TargetKind::BuildScript,
 +                "proc-macro" => TargetKind::Lib,
 +                _ if kind.contains("lib") => TargetKind::Lib,
 +                _ => continue,
 +            };
 +        }
 +        TargetKind::Other
 +    }
 +}
 +
 +#[derive(Deserialize, Default)]
 +// Deserialise helper for the cargo metadata
 +struct PackageMetadata {
 +    #[serde(rename = "rust-analyzer")]
 +    rust_analyzer: Option<RustAnalyzerPackageMetaData>,
 +}
 +
 +impl CargoWorkspace {
 +    pub fn fetch_metadata(
 +        cargo_toml: &ManifestPath,
 +        current_dir: &AbsPath,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<cargo_metadata::Metadata> {
 +        let target = config
 +            .target
 +            .clone()
-         let meta =
-             meta.exec().with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?;
++            .or_else(|| cargo_config_build_target(cargo_toml, config))
++            .or_else(|| rustc_discover_host_triple(cargo_toml, config));
 +
 +        let mut meta = MetadataCommand::new();
 +        meta.cargo_path(toolchain::cargo());
 +        meta.manifest_path(cargo_toml.to_path_buf());
 +        if config.all_features {
 +            meta.features(CargoOpt::AllFeatures);
 +        } else {
 +            if config.no_default_features {
 +                // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
 +                // https://github.com/oli-obk/cargo_metadata/issues/79
 +                meta.features(CargoOpt::NoDefaultFeatures);
 +            }
 +            if !config.features.is_empty() {
 +                meta.features(CargoOpt::SomeFeatures(config.features.clone()));
 +            }
 +        }
 +        meta.current_dir(current_dir.as_os_str());
 +
 +        if let Some(target) = target {
 +            meta.other_options(vec![String::from("--filter-platform"), target]);
 +        }
 +
 +        // FIXME: Fetching metadata is a slow process, as it might require
 +        // calling crates.io. We should be reporting progress here, but it's
 +        // unclear whether cargo itself supports it.
 +        progress("metadata".to_string());
 +
- fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> {
++        fn exec_with_env(
++            command: &cargo_metadata::MetadataCommand,
++            extra_env: &FxHashMap<String, String>,
++        ) -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
++            let mut command = command.cargo_command();
++            command.envs(extra_env);
++            let output = command.output()?;
++            if !output.status.success() {
++                return Err(cargo_metadata::Error::CargoMetadata {
++                    stderr: String::from_utf8(output.stderr)?,
++                });
++            }
++            let stdout = from_utf8(&output.stdout)?
++                .lines()
++                .find(|line| line.starts_with('{'))
++                .ok_or(cargo_metadata::Error::NoJson)?;
++            cargo_metadata::MetadataCommand::parse(stdout)
++        }
++
++        let meta = exec_with_env(&meta, &config.extra_env)
++            .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?;
 +
 +        Ok(meta)
 +    }
 +
 +    pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
 +        let mut pkg_by_id = FxHashMap::default();
 +        let mut packages = Arena::default();
 +        let mut targets = Arena::default();
 +
 +        let ws_members = &meta.workspace_members;
 +
 +        meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
 +        for meta_pkg in &meta.packages {
 +            let cargo_metadata::Package {
 +                id,
 +                edition,
 +                name,
 +                manifest_path,
 +                version,
 +                metadata,
 +                repository,
 +                ..
 +            } = meta_pkg;
 +            let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
 +            let edition = match edition {
 +                cargo_metadata::Edition::E2015 => Edition::Edition2015,
 +                cargo_metadata::Edition::E2018 => Edition::Edition2018,
 +                cargo_metadata::Edition::E2021 => Edition::Edition2021,
 +                _ => {
 +                    tracing::error!("Unsupported edition `{:?}`", edition);
 +                    Edition::CURRENT
 +                }
 +            };
 +            // We treat packages without source as "local" packages. That includes all members of
 +            // the current workspace, as well as any path dependency outside the workspace.
 +            let is_local = meta_pkg.source.is_none();
 +            let is_member = ws_members.contains(id);
 +
 +            let pkg = packages.alloc(PackageData {
 +                id: id.repr.clone(),
 +                name: name.clone(),
 +                version: version.clone(),
 +                manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
 +                targets: Vec::new(),
 +                is_local,
 +                is_member,
 +                edition,
 +                repository: repository.clone(),
 +                dependencies: Vec::new(),
 +                features: meta_pkg.features.clone().into_iter().collect(),
 +                active_features: Vec::new(),
 +                metadata: meta.rust_analyzer.unwrap_or_default(),
 +            });
 +            let pkg_data = &mut packages[pkg];
 +            pkg_by_id.insert(id, pkg);
 +            for meta_tgt in &meta_pkg.targets {
 +                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
 +                let tgt = targets.alloc(TargetData {
 +                    package: pkg,
 +                    name: meta_tgt.name.clone(),
 +                    root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)),
 +                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
 +                    is_proc_macro,
 +                    required_features: meta_tgt.required_features.clone(),
 +                });
 +                pkg_data.targets.push(tgt);
 +            }
 +        }
 +        let resolve = meta.resolve.expect("metadata executed with deps");
 +        for mut node in resolve.nodes {
 +            let source = match pkg_by_id.get(&node.id) {
 +                Some(&src) => src,
 +                // FIXME: replace this and a similar branch below with `.unwrap`, once
 +                // https://github.com/rust-lang/cargo/issues/7841
 +                // is fixed and hits stable (around 1.43-is probably?).
 +                None => {
 +                    tracing::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
 +                    continue;
 +                }
 +            };
 +            node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
 +            for (dep_node, kind) in node
 +                .deps
 +                .iter()
 +                .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)))
 +            {
 +                let pkg = match pkg_by_id.get(&dep_node.pkg) {
 +                    Some(&pkg) => pkg,
 +                    None => {
 +                        tracing::error!(
 +                            "Dep node id do not match in cargo metadata, ignoring {}",
 +                            dep_node.pkg
 +                        );
 +                        continue;
 +                    }
 +                };
 +                let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind };
 +                packages[source].dependencies.push(dep);
 +            }
 +            packages[source].active_features.extend(node.features);
 +        }
 +
 +        let workspace_root =
 +            AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
 +
 +        CargoWorkspace { packages, targets, workspace_root }
 +    }
 +
 +    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
 +        self.packages.iter().map(|(id, _pkg)| id)
 +    }
 +
 +    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
 +        self.packages()
 +            .filter(|&pkg| self[pkg].is_member)
 +            .find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
 +            .copied()
 +    }
 +
 +    pub fn workspace_root(&self) -> &AbsPath {
 +        &self.workspace_root
 +    }
 +
 +    pub fn package_flag(&self, package: &PackageData) -> String {
 +        if self.is_unique(&*package.name) {
 +            package.name.clone()
 +        } else {
 +            format!("{}:{}", package.name, package.version)
 +        }
 +    }
 +
 +    pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option<Vec<ManifestPath>> {
 +        let mut found = false;
 +        let parent_manifests = self
 +            .packages()
 +            .filter_map(|pkg| {
 +                if !found && &self[pkg].manifest == manifest_path {
 +                    found = true
 +                }
 +                self[pkg].dependencies.iter().find_map(|dep| {
 +                    if &self[dep.pkg].manifest == manifest_path {
 +                        return Some(self[pkg].manifest.clone());
 +                    }
 +                    None
 +                })
 +            })
 +            .collect::<Vec<ManifestPath>>();
 +
 +        // some packages has this pkg as dep. return their manifests
 +        if parent_manifests.len() > 0 {
 +            return Some(parent_manifests);
 +        }
 +
 +        // this pkg is inside this cargo workspace, fallback to workspace root
 +        if found {
 +            return Some(vec![
 +                ManifestPath::try_from(self.workspace_root().join("Cargo.toml")).ok()?
 +            ]);
 +        }
 +
 +        // not in this workspace
 +        None
 +    }
 +
 +    fn is_unique(&self, name: &str) -> bool {
 +        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
 +    }
 +}
 +
- fn cargo_config_build_target(cargo_toml: &ManifestPath) -> Option<String> {
++fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
 +    let mut rustc = Command::new(toolchain::rustc());
++    rustc.envs(&config.extra_env);
 +    rustc.current_dir(cargo_toml.parent()).arg("-vV");
 +    tracing::debug!("Discovering host platform by {:?}", rustc);
 +    match utf8_stdout(rustc) {
 +        Ok(stdout) => {
 +            let field = "host: ";
 +            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
 +            if let Some(target) = target {
 +                Some(target.to_string())
 +            } else {
 +                // If we fail to resolve the host platform, it's not the end of the world.
 +                tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
 +                None
 +            }
 +        }
 +        Err(e) => {
 +            tracing::warn!("Failed to discover host platform: {}", e);
 +            None
 +        }
 +    }
 +}
 +
++fn cargo_config_build_target(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
 +    let mut cargo_config = Command::new(toolchain::cargo());
++    cargo_config.envs(&config.extra_env);
 +    cargo_config
 +        .current_dir(cargo_toml.parent())
 +        .args(&["-Z", "unstable-options", "config", "get", "build.target"])
 +        .env("RUSTC_BOOTSTRAP", "1");
 +    // if successful we receive `build.target = "target-triple"`
 +    tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
 +    match utf8_stdout(cargo_config) {
 +        Ok(stdout) => stdout
 +            .strip_prefix("build.target = \"")
 +            .and_then(|stdout| stdout.strip_suffix('"'))
 +            .map(ToOwned::to_owned),
 +        Err(_) => None,
 +    }
 +}
index 17e244d0649eddf073a9bf65e39fade35226ae4f,0000000000000000000000000000000000000000..486cb143b80bd22678fa584a6aedacd14529e9d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,60 -1,0 +1,70 @@@
- use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
 +//! Runs `rustc --print cfg` to get built-in cfg flags.
 +
 +use std::process::Command;
 +
 +use anyhow::Result;
 +
- pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Vec<CfgFlag> {
++use crate::{cfg_flag::CfgFlag, utf8_stdout, CargoConfig, ManifestPath};
 +
-     match get_rust_cfgs(cargo_toml, target) {
++pub(crate) fn get(
++    cargo_toml: Option<&ManifestPath>,
++    target: Option<&str>,
++    config: &CargoConfig,
++) -> Vec<CfgFlag> {
 +    let _p = profile::span("rustc_cfg::get");
 +    let mut res = Vec::with_capacity(6 * 2 + 1);
 +
 +    // Some nightly-only cfgs, which are required for stdlib
 +    res.push(CfgFlag::Atom("target_thread_local".into()));
 +    for ty in ["8", "16", "32", "64", "cas", "ptr"] {
 +        for key in ["target_has_atomic", "target_has_atomic_load_store"] {
 +            res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
 +        }
 +    }
 +
- fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Result<String> {
++    match get_rust_cfgs(cargo_toml, target, config) {
 +        Ok(rustc_cfgs) => {
 +            tracing::debug!(
 +                "rustc cfgs found: {:?}",
 +                rustc_cfgs
 +                    .lines()
 +                    .map(|it| it.parse::<CfgFlag>().map(|it| it.to_string()))
 +                    .collect::<Vec<_>>()
 +            );
 +            res.extend(rustc_cfgs.lines().filter_map(|it| it.parse().ok()));
 +        }
 +        Err(e) => tracing::error!("failed to get rustc cfgs: {e:?}"),
 +    }
 +
 +    res
 +}
 +
++fn get_rust_cfgs(
++    cargo_toml: Option<&ManifestPath>,
++    target: Option<&str>,
++    config: &CargoConfig,
++) -> Result<String> {
 +    if let Some(cargo_toml) = cargo_toml {
 +        let mut cargo_config = Command::new(toolchain::cargo());
++        cargo_config.envs(&config.extra_env);
 +        cargo_config
 +            .current_dir(cargo_toml.parent())
 +            .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
 +            .env("RUSTC_BOOTSTRAP", "1");
 +        if let Some(target) = target {
 +            cargo_config.args(&["--target", target]);
 +        }
 +        match utf8_stdout(cargo_config) {
 +            Ok(it) => return Ok(it),
 +            Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"),
 +        }
 +    }
 +    // using unstable cargo features failed, fall back to using plain rustc
 +    let mut cmd = Command::new(toolchain::rustc());
++    cmd.envs(&config.extra_env);
 +    cmd.args(&["--print", "cfg", "-O"]);
 +    if let Some(target) = target {
 +        cmd.args(&["--target", target]);
 +    }
 +    utf8_stdout(cmd)
 +}
index 362bb0f5e79cdb8fea2bb68e7a0591f978c81c90,0000000000000000000000000000000000000000..3282719fef3d7a3d0b1c188487797cb384b24817
mode 100644,000000..100644
--- /dev/null
@@@ -1,232 -1,0 +1,237 @@@
- use crate::{utf8_stdout, ManifestPath};
 +//! Loads "sysroot" crate.
 +//!
 +//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
 +//! but we can't process `.rlib` and need source code instead. The source code
 +//! is typically installed with `rustup component add rust-src` command.
 +
 +use std::{env, fs, iter, ops, path::PathBuf, process::Command};
 +
 +use anyhow::{format_err, Result};
 +use la_arena::{Arena, Idx};
 +use paths::{AbsPath, AbsPathBuf};
 +
-     pub fn discover(dir: &AbsPath) -> Result<Sysroot> {
++use crate::{utf8_stdout, CargoConfig, ManifestPath};
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct Sysroot {
 +    root: AbsPathBuf,
 +    src_root: AbsPathBuf,
 +    crates: Arena<SysrootCrateData>,
 +}
 +
 +pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct SysrootCrateData {
 +    pub name: String,
 +    pub root: ManifestPath,
 +    pub deps: Vec<SysrootCrate>,
 +}
 +
 +impl ops::Index<SysrootCrate> for Sysroot {
 +    type Output = SysrootCrateData;
 +    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
 +        &self.crates[index]
 +    }
 +}
 +
 +impl Sysroot {
 +    /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/`
 +    /// subfolder live, like:
 +    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu`
 +    pub fn root(&self) -> &AbsPath {
 +        &self.root
 +    }
 +
 +    /// Returns the sysroot "source" directory, where stdlib sources are located, like:
 +    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
 +    pub fn src_root(&self) -> &AbsPath {
 +        &self.src_root
 +    }
 +
 +    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate, bool)> + '_ {
 +        // core is added as a dependency before std in order to
 +        // mimic rustcs dependency order
 +        ["core", "alloc", "std"]
 +            .into_iter()
 +            .zip(iter::repeat(true))
 +            .chain(iter::once(("test", false)))
 +            .filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude)))
 +    }
 +
 +    pub fn proc_macro(&self) -> Option<SysrootCrate> {
 +        self.by_name("proc_macro")
 +    }
 +
 +    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
 +        self.crates.iter().map(|(id, _data)| id)
 +    }
 +
-         let sysroot_dir = discover_sysroot_dir(dir)?;
-         let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?;
++    pub fn discover(dir: &AbsPath, config: &CargoConfig) -> Result<Sysroot> {
 +        tracing::debug!("Discovering sysroot for {}", dir.display());
-     pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option<ManifestPath> {
++        let sysroot_dir = discover_sysroot_dir(dir, config)?;
++        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, config)?;
 +        let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
 +        Ok(res)
 +    }
 +
-         discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
++    pub fn discover_rustc(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<ManifestPath> {
 +        tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
 +        let current_dir = cargo_toml.parent();
- fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
++        discover_sysroot_dir(current_dir, config)
++            .ok()
++            .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
 +    }
 +
 +    pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
 +        let mut sysroot =
 +            Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
 +
 +        for path in SYSROOT_CRATES.trim().lines() {
 +            let name = path.split('/').last().unwrap();
 +            let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
 +                .into_iter()
 +                .map(|it| sysroot.src_root.join(it))
 +                .filter_map(|it| ManifestPath::try_from(it).ok())
 +                .find(|it| fs::metadata(it).is_ok());
 +
 +            if let Some(root) = root {
 +                sysroot.crates.alloc(SysrootCrateData {
 +                    name: name.into(),
 +                    root,
 +                    deps: Vec::new(),
 +                });
 +            }
 +        }
 +
 +        if let Some(std) = sysroot.by_name("std") {
 +            for dep in STD_DEPS.trim().lines() {
 +                if let Some(dep) = sysroot.by_name(dep) {
 +                    sysroot.crates[std].deps.push(dep)
 +                }
 +            }
 +        }
 +
 +        if let Some(alloc) = sysroot.by_name("alloc") {
 +            if let Some(core) = sysroot.by_name("core") {
 +                sysroot.crates[alloc].deps.push(core);
 +            }
 +        }
 +
 +        if let Some(proc_macro) = sysroot.by_name("proc_macro") {
 +            if let Some(std) = sysroot.by_name("std") {
 +                sysroot.crates[proc_macro].deps.push(std);
 +            }
 +        }
 +
 +        if sysroot.by_name("core").is_none() {
 +            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
 +                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
 +            } else {
 +                ""
 +            };
 +            anyhow::bail!(
 +                "could not find libcore in sysroot path `{}`{}",
 +                sysroot.src_root.as_path().display(),
 +                var_note,
 +            );
 +        }
 +
 +        Ok(sysroot)
 +    }
 +
 +    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
 +        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
 +        Some(id)
 +    }
 +}
 +
++fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result<AbsPathBuf> {
 +    let mut rustc = Command::new(toolchain::rustc());
++    rustc.envs(&config.extra_env);
 +    rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
 +    tracing::debug!("Discovering sysroot by {:?}", rustc);
 +    let stdout = utf8_stdout(rustc)?;
 +    Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
 +}
 +
 +fn discover_sysroot_src_dir(
 +    sysroot_path: &AbsPathBuf,
 +    current_dir: &AbsPath,
++    config: &CargoConfig,
 +) -> Result<AbsPathBuf> {
 +    if let Ok(path) = env::var("RUST_SRC_PATH") {
 +        let path = AbsPathBuf::try_from(path.as_str())
 +            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
 +        let core = path.join("core");
 +        if fs::metadata(&core).is_ok() {
 +            tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
 +            return Ok(path);
 +        }
 +        tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
 +    }
 +
 +    get_rust_src(sysroot_path)
 +        .or_else(|| {
 +            let mut rustup = Command::new(toolchain::rustup());
++            rustup.envs(&config.extra_env);
 +            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
 +            utf8_stdout(rustup).ok()?;
 +            get_rust_src(sysroot_path)
 +        })
 +        .ok_or_else(|| {
 +            format_err!(
 +                "\
 +can't load standard library from sysroot
 +{}
 +(discovered via `rustc --print sysroot`)
 +try installing the Rust source the same way you installed rustc",
 +                sysroot_path.display(),
 +            )
 +        })
 +}
 +
 +fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
 +    let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
 +    let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
 +    tracing::debug!("Checking for rustc source code: {}", rustc_src.display());
 +    if fs::metadata(&rustc_src).is_ok() {
 +        Some(rustc_src)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
 +    let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
 +    tracing::debug!("Checking sysroot: {}", rust_src.display());
 +    if fs::metadata(&rust_src).is_ok() {
 +        Some(rust_src)
 +    } else {
 +        None
 +    }
 +}
 +
 +const SYSROOT_CRATES: &str = "
 +alloc
 +core
 +panic_abort
 +panic_unwind
 +proc_macro
 +profiler_builtins
 +std
 +stdarch/crates/std_detect
 +term
 +test
 +unwind";
 +
 +const STD_DEPS: &str = "
 +alloc
 +core
 +panic_abort
 +panic_unwind
 +profiler_builtins
 +std_detect
 +term
 +test
 +unwind";
index 9ccb6e9101ef440c4604350b1901060375df66ae,0000000000000000000000000000000000000000..bea624bd54195e73651a0539919a4e80b03a4932
mode 100644,000000..100644
--- /dev/null
@@@ -1,1821 -1,0 +1,1825 @@@
-     CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
-     WorkspaceBuildScripts,
 +use std::{
 +    ops::Deref,
 +    path::{Path, PathBuf},
 +};
 +
 +use base_db::{CrateGraph, FileId};
 +use cfg::{CfgAtom, CfgDiff};
 +use expect_test::{expect, Expect};
 +use paths::{AbsPath, AbsPathBuf};
 +use serde::de::DeserializeOwned;
 +
 +use crate::{
-     project_workspace.to_crate_graph(&mut |_, _| Ok(Vec::new()), &mut {
-         let mut counter = 0;
-         move |_path| {
-             counter += 1;
-             Some(FileId(counter))
-         }
-     })
++    CargoConfig, CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace,
++    Sysroot, WorkspaceBuildScripts,
 +};
 +
 +fn load_cargo(file: &str) -> CrateGraph {
 +    load_cargo_with_overrides(file, CfgOverrides::default())
 +}
 +
 +fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGraph {
 +    let meta = get_test_json_file(file);
 +    let cargo_workspace = CargoWorkspace::new(meta);
 +    let project_workspace = ProjectWorkspace::Cargo {
 +        cargo: cargo_workspace,
 +        build_scripts: WorkspaceBuildScripts::default(),
 +        sysroot: None,
 +        rustc: None,
 +        rustc_cfg: Vec::new(),
 +        cfg_overrides,
 +        toolchain: None,
 +    };
 +    to_crate_graph(project_workspace)
 +}
 +
 +fn load_rust_project(file: &str) -> CrateGraph {
 +    let data = get_test_json_file(file);
 +    let project = rooted_project_json(data);
 +    let sysroot = Some(get_fake_sysroot());
 +    let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() };
 +    to_crate_graph(project_workspace)
 +}
 +
 +fn get_test_json_file<T: DeserializeOwned>(file: &str) -> T {
 +    let file = get_test_path(file);
 +    let data = std::fs::read_to_string(file).unwrap();
 +    let mut json = data.parse::<serde_json::Value>().unwrap();
 +    fixup_paths(&mut json);
 +    return serde_json::from_value(json).unwrap();
 +
 +    fn fixup_paths(val: &mut serde_json::Value) {
 +        match val {
 +            serde_json::Value::String(s) => replace_root(s, true),
 +            serde_json::Value::Array(vals) => vals.iter_mut().for_each(fixup_paths),
 +            serde_json::Value::Object(kvals) => kvals.values_mut().for_each(fixup_paths),
 +            serde_json::Value::Null | serde_json::Value::Bool(_) | serde_json::Value::Number(_) => {
 +            }
 +        }
 +    }
 +}
 +
 +fn replace_root(s: &mut String, direction: bool) {
 +    if direction {
 +        let root = if cfg!(windows) { r#"C:\\ROOT\"# } else { "/ROOT/" };
 +        *s = s.replace("$ROOT$", root)
 +    } else {
 +        let root = if cfg!(windows) { r#"C:\\\\ROOT\\"# } else { "/ROOT/" };
 +        *s = s.replace(root, "$ROOT$")
 +    }
 +}
 +
 +fn get_test_path(file: &str) -> PathBuf {
 +    let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 +    base.join("test_data").join(file)
 +}
 +
 +fn get_fake_sysroot() -> Sysroot {
 +    let sysroot_path = get_test_path("fake-sysroot");
 +    // there's no `libexec/` directory with a `proc-macro-srv` binary in that
 +    // fake sysroot, so we give them both the same path:
 +    let sysroot_dir = AbsPathBuf::assert(sysroot_path);
 +    let sysroot_src_dir = sysroot_dir.clone();
 +    Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap()
 +}
 +
 +fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
 +    let mut root = "$ROOT$".to_string();
 +    replace_root(&mut root, true);
 +    let path = Path::new(&root);
 +    let base = AbsPath::assert(path);
 +    ProjectJson::new(base, data)
 +}
 +
 +fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
++    project_workspace.to_crate_graph(
++        &mut |_, _| Ok(Vec::new()),
++        &mut {
++            let mut counter = 0;
++            move |_path| {
++                counter += 1;
++                Some(FileId(counter))
++            }
++        },
++        &CargoConfig::default(),
++    )
 +}
 +
 +fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) {
 +    let mut crate_graph = format!("{:#?}", crate_graph);
 +    replace_root(&mut crate_graph, false);
 +    expect.assert_eq(&crate_graph);
 +}
 +
 +#[test]
 +fn cargo_hello_world_project_model_with_wildcard_overrides() {
 +    let cfg_overrides = CfgOverrides::Wildcard(
 +        CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
 +    );
 +    let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
 +    check_crate_graph(
 +        crate_graph,
 +        expect![[r#"
 +            CrateGraph {
 +                arena: {
 +                    CrateId(
 +                        0,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            1,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        1,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            2,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        2,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            3,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "an_example",
 +                                ),
 +                                canonical_name: "an-example",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        3,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            4,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "it",
 +                                ),
 +                                canonical_name: "it",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        4,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            5,
 +                        ),
 +                        edition: Edition2015,
 +                        version: Some(
 +                            "0.2.98",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "libc",
 +                                ),
 +                                canonical_name: "libc",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=default",
 +                                "feature=std",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=align",
 +                                "feature=const-extern-fn",
 +                                "feature=default",
 +                                "feature=extra_traits",
 +                                "feature=rustc-dep-of-std",
 +                                "feature=std",
 +                                "feature=use_std",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
 +                                "CARGO_PKG_VERSION": "0.2.98",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "libc",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "libc",
 +                                "CARGO_PKG_VERSION_PATCH": "98",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "2",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: Some(
 +                                "https://github.com/rust-lang/libc",
 +                            ),
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[test]
 +fn cargo_hello_world_project_model_with_selective_overrides() {
 +    let cfg_overrides = {
 +        CfgOverrides::Selective(
 +            std::iter::once((
 +                "libc".to_owned(),
 +                CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
 +            ))
 +            .collect(),
 +        )
 +    };
 +    let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
 +    check_crate_graph(
 +        crate_graph,
 +        expect![[r#"
 +            CrateGraph {
 +                arena: {
 +                    CrateId(
 +                        0,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            1,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        1,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            2,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        2,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            3,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "an_example",
 +                                ),
 +                                canonical_name: "an-example",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        3,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            4,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "it",
 +                                ),
 +                                canonical_name: "it",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        4,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            5,
 +                        ),
 +                        edition: Edition2015,
 +                        version: Some(
 +                            "0.2.98",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "libc",
 +                                ),
 +                                canonical_name: "libc",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=default",
 +                                "feature=std",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=align",
 +                                "feature=const-extern-fn",
 +                                "feature=default",
 +                                "feature=extra_traits",
 +                                "feature=rustc-dep-of-std",
 +                                "feature=std",
 +                                "feature=use_std",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
 +                                "CARGO_PKG_VERSION": "0.2.98",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "libc",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "libc",
 +                                "CARGO_PKG_VERSION_PATCH": "98",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "2",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: Some(
 +                                "https://github.com/rust-lang/libc",
 +                            ),
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[test]
 +fn cargo_hello_world_project_model() {
 +    let crate_graph = load_cargo("hello-world-metadata.json");
 +    check_crate_graph(
 +        crate_graph,
 +        expect![[r#"
 +            CrateGraph {
 +                arena: {
 +                    CrateId(
 +                        0,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            1,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        1,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            2,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello-world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        2,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            3,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "an_example",
 +                                ),
 +                                canonical_name: "an-example",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        3,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            4,
 +                        ),
 +                        edition: Edition2018,
 +                        version: Some(
 +                            "0.1.0",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "it",
 +                                ),
 +                                canonical_name: "it",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "test",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
 +                                "CARGO_PKG_VERSION": "0.1.0",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "hello_world",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "hello-world",
 +                                "CARGO_PKG_VERSION_PATCH": "0",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "1",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    4,
 +                                ),
 +                                name: CrateName(
 +                                    "libc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        4,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            5,
 +                        ),
 +                        edition: Edition2015,
 +                        version: Some(
 +                            "0.2.98",
 +                        ),
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "libc",
 +                                ),
 +                                canonical_name: "libc",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=default",
 +                                "feature=std",
 +                            ],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [
 +                                "debug_assertions",
 +                                "feature=align",
 +                                "feature=const-extern-fn",
 +                                "feature=default",
 +                                "feature=extra_traits",
 +                                "feature=rustc-dep-of-std",
 +                                "feature=std",
 +                                "feature=use_std",
 +                            ],
 +                        ),
 +                        env: Env {
 +                            entries: {
 +                                "CARGO_PKG_LICENSE": "",
 +                                "CARGO_PKG_VERSION_MAJOR": "0",
 +                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
 +                                "CARGO_PKG_VERSION": "0.2.98",
 +                                "CARGO_PKG_AUTHORS": "",
 +                                "CARGO_CRATE_NAME": "libc",
 +                                "CARGO_PKG_LICENSE_FILE": "",
 +                                "CARGO_PKG_HOMEPAGE": "",
 +                                "CARGO_PKG_DESCRIPTION": "",
 +                                "CARGO_PKG_NAME": "libc",
 +                                "CARGO_PKG_VERSION_PATCH": "98",
 +                                "CARGO": "cargo",
 +                                "CARGO_PKG_REPOSITORY": "",
 +                                "CARGO_PKG_VERSION_MINOR": "2",
 +                                "CARGO_PKG_VERSION_PRE": "",
 +                            },
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "crate has not (yet) been built",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: Some(
 +                                "https://github.com/rust-lang/libc",
 +                            ),
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[test]
 +fn rust_project_hello_world_project_model() {
 +    let crate_graph = load_rust_project("hello-world-project.json");
 +    check_crate_graph(
 +        crate_graph,
 +        expect![[r#"
 +            CrateGraph {
 +                arena: {
 +                    CrateId(
 +                        0,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            1,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "alloc",
 +                                ),
 +                                canonical_name: "alloc",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    1,
 +                                ),
 +                                name: CrateName(
 +                                    "core",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Alloc,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        1,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            2,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "core",
 +                                ),
 +                                canonical_name: "core",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Core,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        2,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            3,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "panic_abort",
 +                                ),
 +                                canonical_name: "panic_abort",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        3,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            4,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "panic_unwind",
 +                                ),
 +                                canonical_name: "panic_unwind",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        4,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            5,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "proc_macro",
 +                                ),
 +                                canonical_name: "proc_macro",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    6,
 +                                ),
 +                                name: CrateName(
 +                                    "std",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        5,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            6,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "profiler_builtins",
 +                                ),
 +                                canonical_name: "profiler_builtins",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        6,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            7,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "std",
 +                                ),
 +                                canonical_name: "std",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "alloc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    1,
 +                                ),
 +                                name: CrateName(
 +                                    "core",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    2,
 +                                ),
 +                                name: CrateName(
 +                                    "panic_abort",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    3,
 +                                ),
 +                                name: CrateName(
 +                                    "panic_unwind",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    5,
 +                                ),
 +                                name: CrateName(
 +                                    "profiler_builtins",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    7,
 +                                ),
 +                                name: CrateName(
 +                                    "std_detect",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    8,
 +                                ),
 +                                name: CrateName(
 +                                    "term",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    9,
 +                                ),
 +                                name: CrateName(
 +                                    "test",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    10,
 +                                ),
 +                                name: CrateName(
 +                                    "unwind",
 +                                ),
 +                                prelude: true,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Std,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        7,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            8,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "std_detect",
 +                                ),
 +                                canonical_name: "std_detect",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        8,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            9,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "term",
 +                                ),
 +                                canonical_name: "term",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        9,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            10,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "test",
 +                                ),
 +                                canonical_name: "test",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Test,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        10,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            11,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "unwind",
 +                                ),
 +                                canonical_name: "unwind",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [],
 +                        proc_macro: Err(
 +                            "no proc macro loaded for sysroot crate",
 +                        ),
 +                        origin: Lang(
 +                            Other,
 +                        ),
 +                        is_proc_macro: false,
 +                    },
 +                    CrateId(
 +                        11,
 +                    ): CrateData {
 +                        root_file_id: FileId(
 +                            12,
 +                        ),
 +                        edition: Edition2018,
 +                        version: None,
 +                        display_name: Some(
 +                            CrateDisplayName {
 +                                crate_name: CrateName(
 +                                    "hello_world",
 +                                ),
 +                                canonical_name: "hello_world",
 +                            },
 +                        ),
 +                        cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        potential_cfg_options: CfgOptions(
 +                            [],
 +                        ),
 +                        env: Env {
 +                            entries: {},
 +                        },
 +                        dependencies: [
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    1,
 +                                ),
 +                                name: CrateName(
 +                                    "core",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    0,
 +                                ),
 +                                name: CrateName(
 +                                    "alloc",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    6,
 +                                ),
 +                                name: CrateName(
 +                                    "std",
 +                                ),
 +                                prelude: true,
 +                            },
 +                            Dependency {
 +                                crate_id: CrateId(
 +                                    9,
 +                                ),
 +                                name: CrateName(
 +                                    "test",
 +                                ),
 +                                prelude: false,
 +                            },
 +                        ],
 +                        proc_macro: Err(
 +                            "no proc macro dylib present",
 +                        ),
 +                        origin: CratesIo {
 +                            repo: None,
 +                        },
 +                        is_proc_macro: false,
 +                    },
 +                },
 +            }"#]],
 +    );
 +}
 +
 +#[test]
 +fn rust_project_is_proc_macro_has_proc_macro_dep() {
 +    let crate_graph = load_rust_project("is-proc-macro-project.json");
 +    // Since the project only defines one crate (outside the sysroot crates),
 +    // it should be the one with the biggest Id.
 +    let crate_id = crate_graph.iter().max().unwrap();
 +    let crate_data = &crate_graph[crate_id];
 +    // Assert that the project crate with `is_proc_macro` has a dependency
 +    // on the proc_macro sysroot crate.
 +    crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap();
 +}
index 818bbed6af2ec73600d2bde661d2f420d48969f7,0000000000000000000000000000000000000000..bc4ab45daeffc80a418711f3f0f03a4c7e8f73c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,1042 -1,0 +1,1048 @@@
-                 ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
 +//! Handles lowering of build-system specific workspace information (`cargo
 +//! metadata` or `rust-project.json`) into representation stored in the salsa
 +//! database -- `CrateGraph`.
 +
 +use std::{collections::VecDeque, fmt, fs, process::Command};
 +
 +use anyhow::{format_err, Context, Result};
 +use base_db::{
 +    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
 +    FileId, LangCrateOrigin, ProcMacroLoadResult,
 +};
 +use cfg::{CfgDiff, CfgOptions};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use semver::Version;
 +use stdx::{always, hash::NoHashHashMap};
 +
 +use crate::{
 +    build_scripts::BuildScriptOutput,
 +    cargo_workspace::{DepKind, PackageData, RustcSource},
 +    cfg_flag::CfgFlag,
 +    rustc_cfg,
 +    sysroot::SysrootCrate,
 +    utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, ProjectJson, ProjectManifest, Sysroot,
 +    TargetKind, WorkspaceBuildScripts,
 +};
 +
 +/// A set of cfg-overrides per crate.
 +///
 +/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates,
 +/// without having to first obtain a list of all crates.
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum CfgOverrides {
 +    /// A single global set of overrides matching all crates.
 +    Wildcard(CfgDiff),
 +    /// A set of overrides matching specific crates.
 +    Selective(FxHashMap<String, CfgDiff>),
 +}
 +
 +impl Default for CfgOverrides {
 +    fn default() -> Self {
 +        Self::Selective(FxHashMap::default())
 +    }
 +}
 +
 +impl CfgOverrides {
 +    pub fn len(&self) -> usize {
 +        match self {
 +            CfgOverrides::Wildcard(_) => 1,
 +            CfgOverrides::Selective(hash_map) => hash_map.len(),
 +        }
 +    }
 +}
 +
 +/// `PackageRoot` describes a package root folder.
 +/// Which may be an external dependency, or a member of
 +/// the current workspace.
 +#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 +pub struct PackageRoot {
 +    /// Is from the local filesystem and may be edited
 +    pub is_local: bool,
 +    pub include: Vec<AbsPathBuf>,
 +    pub exclude: Vec<AbsPathBuf>,
 +}
 +
 +#[derive(Clone, Eq, PartialEq)]
 +pub enum ProjectWorkspace {
 +    /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
 +    Cargo {
 +        cargo: CargoWorkspace,
 +        build_scripts: WorkspaceBuildScripts,
 +        sysroot: Option<Sysroot>,
 +        rustc: Option<CargoWorkspace>,
 +        /// Holds cfg flags for the current target. We get those by running
 +        /// `rustc --print cfg`.
 +        ///
 +        /// FIXME: make this a per-crate map, as, eg, build.rs might have a
 +        /// different target.
 +        rustc_cfg: Vec<CfgFlag>,
 +        cfg_overrides: CfgOverrides,
 +        toolchain: Option<Version>,
 +    },
 +    /// Project workspace was manually specified using a `rust-project.json` file.
 +    Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
 +
 +    // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
 +    // That's not the end user experience we should strive for.
 +    // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
 +    // That needs some changes on the salsa-level though.
 +    // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability).
 +    // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results.
 +    // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files.
 +    // //
 +    /// Project with a set of disjoint files, not belonging to any particular workspace.
 +    /// Backed by basic sysroot crates for basic completion and highlighting.
 +    DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Sysroot, rustc_cfg: Vec<CfgFlag> },
 +}
 +
 +impl fmt::Debug for ProjectWorkspace {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        // Make sure this isn't too verbose.
 +        match self {
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                build_scripts: _,
 +                sysroot,
 +                rustc,
 +                rustc_cfg,
 +                cfg_overrides,
 +                toolchain,
 +            } => f
 +                .debug_struct("Cargo")
 +                .field("root", &cargo.workspace_root().file_name())
 +                .field("n_packages", &cargo.packages().len())
 +                .field("sysroot", &sysroot.is_some())
 +                .field(
 +                    "n_rustc_compiler_crates",
 +                    &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
 +                )
 +                .field("n_rustc_cfg", &rustc_cfg.len())
 +                .field("n_cfg_overrides", &cfg_overrides.len())
 +                .field("toolchain", &toolchain)
 +                .finish(),
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
 +                let mut debug_struct = f.debug_struct("Json");
 +                debug_struct.field("n_crates", &project.n_crates());
 +                if let Some(sysroot) = sysroot {
 +                    debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
 +                }
 +                debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
 +                debug_struct.finish()
 +            }
 +            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
 +                .debug_struct("DetachedFiles")
 +                .field("n_files", &files.len())
 +                .field("n_sysroot_crates", &sysroot.crates().len())
 +                .field("n_rustc_cfg", &rustc_cfg.len())
 +                .finish(),
 +        }
 +    }
 +}
 +
 +impl ProjectWorkspace {
 +    pub fn load(
 +        manifest: ProjectManifest,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<ProjectWorkspace> {
 +        let res = match manifest {
 +            ProjectManifest::ProjectJson(project_json) => {
 +                let file = fs::read_to_string(&project_json).with_context(|| {
 +                    format!("Failed to read json file {}", project_json.display())
 +                })?;
 +                let data = serde_json::from_str(&file).with_context(|| {
 +                    format!("Failed to deserialize json file {}", project_json.display())
 +                })?;
 +                let project_location = project_json.parent().to_path_buf();
 +                let project_json = ProjectJson::new(&project_location, data);
-                     Some(Sysroot::discover(cargo_toml.parent()).with_context(|| {
++                ProjectWorkspace::load_inline(project_json, config.target.as_deref(), config)?
 +            }
 +            ProjectManifest::CargoToml(cargo_toml) => {
 +                let cargo_version = utf8_stdout({
 +                    let mut cmd = Command::new(toolchain::cargo());
++                    cmd.envs(&config.extra_env);
 +                    cmd.arg("--version");
 +                    cmd
 +                })?;
 +                let toolchain = cargo_version
 +                    .get("cargo ".len()..)
 +                    .and_then(|it| Version::parse(it.split_whitespace().next()?).ok());
 +
 +                let meta = CargoWorkspace::fetch_metadata(
 +                    &cargo_toml,
 +                    cargo_toml.parent(),
 +                    config,
 +                    progress,
 +                )
 +                .with_context(|| {
 +                    format!(
 +                        "Failed to read Cargo metadata from Cargo.toml file {}, {:?}",
 +                        cargo_toml.display(),
 +                        toolchain
 +                    )
 +                })?;
 +                let cargo = CargoWorkspace::new(meta);
 +
 +                let sysroot = if config.no_sysroot {
 +                    None
 +                } else {
-                     Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml),
++                    Some(Sysroot::discover(cargo_toml.parent(), config).with_context(|| {
 +                        format!(
 +                            "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
 +                            cargo_toml.display()
 +                        )
 +                    })?)
 +                };
 +
 +                let rustc_dir = match &config.rustc_source {
 +                    Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
-                 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
++                    Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml, config),
 +                    None => None,
 +                };
 +
 +                let rustc = match rustc_dir {
 +                    Some(rustc_dir) => Some({
 +                        let meta = CargoWorkspace::fetch_metadata(
 +                            &rustc_dir,
 +                            cargo_toml.parent(),
 +                            config,
 +                            progress,
 +                        )
 +                        .with_context(|| {
 +                            "Failed to read Cargo metadata for Rust sources".to_string()
 +                        })?;
 +                        CargoWorkspace::new(meta)
 +                    }),
 +                    None => None,
 +                };
 +
-         let rustc_cfg = rustc_cfg::get(None, target);
++                let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), config);
 +
 +                let cfg_overrides = config.cfg_overrides();
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    build_scripts: WorkspaceBuildScripts::default(),
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +                    toolchain,
 +                }
 +            }
 +        };
 +
 +        Ok(res)
 +    }
 +
 +    pub fn load_inline(
 +        project_json: ProjectJson,
 +        target: Option<&str>,
++        config: &CargoConfig,
 +    ) -> Result<ProjectWorkspace> {
 +        let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
 +            (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
 +            (Some(sysroot), None) => {
 +                // assume sysroot is structured like rustup's and guess `sysroot_src`
 +                let sysroot_src =
 +                    sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
 +
 +                Some(Sysroot::load(sysroot, sysroot_src)?)
 +            }
 +            (None, Some(sysroot_src)) => {
 +                // assume sysroot is structured like rustup's and guess `sysroot`
 +                let mut sysroot = sysroot_src.clone();
 +                for _ in 0..5 {
 +                    sysroot.pop();
 +                }
 +                Some(Sysroot::load(sysroot, sysroot_src)?)
 +            }
 +            (None, None) => None,
 +        };
 +
-         let rustc_cfg = rustc_cfg::get(None, None);
++        let rustc_cfg = rustc_cfg::get(None, target, config);
 +        Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
 +    }
 +
 +    pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> {
 +        let sysroot = Sysroot::discover(
 +            detached_files
 +                .first()
 +                .and_then(|it| it.parent())
 +                .ok_or_else(|| format_err!("No detached files to load"))?,
++            &CargoConfig::default(),
 +        )?;
-                 Some(target) => {
-                     cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
-                 }
++        let rustc_cfg = rustc_cfg::get(None, None, &CargoConfig::default());
 +        Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
 +    }
 +
 +    pub fn run_build_scripts(
 +        &self,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<WorkspaceBuildScripts> {
 +        match self {
 +            ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
 +                WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
 +                    format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
 +                })
 +            }
 +            ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
 +                Ok(WorkspaceBuildScripts::default())
 +            }
 +        }
 +    }
 +
 +    pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
 +        match self {
 +            ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
 +            _ => {
 +                always!(bs == WorkspaceBuildScripts::default());
 +            }
 +        }
 +    }
 +
 +    /// Returns the roots for the current `ProjectWorkspace`
 +    /// The return type contains the path and whether or not
 +    /// the root is a member of the current workspace
 +    pub fn to_roots(&self) -> Vec<PackageRoot> {
 +        match self {
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
 +                .crates()
 +                .map(|(_, krate)| PackageRoot {
 +                    is_local: krate.is_workspace_member,
 +                    include: krate.include.clone(),
 +                    exclude: krate.exclude.clone(),
 +                })
 +                .collect::<FxHashSet<_>>()
 +                .into_iter()
 +                .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| {
 +                    sysroot.crates().map(move |krate| PackageRoot {
 +                        is_local: false,
 +                        include: vec![sysroot[krate].root.parent().to_path_buf()],
 +                        exclude: Vec::new(),
 +                    })
 +                }))
 +                .collect::<Vec<_>>(),
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                sysroot,
 +                rustc,
 +                rustc_cfg: _,
 +                cfg_overrides: _,
 +                build_scripts,
 +                toolchain: _,
 +            } => {
 +                cargo
 +                    .packages()
 +                    .map(|pkg| {
 +                        let is_local = cargo[pkg].is_local;
 +                        let pkg_root = cargo[pkg].manifest.parent().to_path_buf();
 +
 +                        let mut include = vec![pkg_root.clone()];
 +                        let out_dir =
 +                            build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone());
 +                        include.extend(out_dir);
 +
 +                        // In case target's path is manually set in Cargo.toml to be
 +                        // outside the package root, add its parent as an extra include.
 +                        // An example of this situation would look like this:
 +                        //
 +                        // ```toml
 +                        // [lib]
 +                        // path = "../../src/lib.rs"
 +                        // ```
 +                        let extra_targets = cargo[pkg]
 +                            .targets
 +                            .iter()
 +                            .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib)
 +                            .filter_map(|&tgt| cargo[tgt].root.parent())
 +                            .map(|tgt| tgt.normalize().to_path_buf())
 +                            .filter(|path| !path.starts_with(&pkg_root));
 +                        include.extend(extra_targets);
 +
 +                        let mut exclude = vec![pkg_root.join(".git")];
 +                        if is_local {
 +                            exclude.push(pkg_root.join("target"));
 +                        } else {
 +                            exclude.push(pkg_root.join("tests"));
 +                            exclude.push(pkg_root.join("examples"));
 +                            exclude.push(pkg_root.join("benches"));
 +                        }
 +                        PackageRoot { is_local, include, exclude }
 +                    })
 +                    .chain(sysroot.iter().map(|sysroot| PackageRoot {
 +                        is_local: false,
 +                        include: vec![sysroot.src_root().to_path_buf()],
 +                        exclude: Vec::new(),
 +                    }))
 +                    .chain(rustc.iter().flat_map(|rustc| {
 +                        rustc.packages().map(move |krate| PackageRoot {
 +                            is_local: false,
 +                            include: vec![rustc[krate].manifest.parent().to_path_buf()],
 +                            exclude: Vec::new(),
 +                        })
 +                    }))
 +                    .collect()
 +            }
 +            ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
 +                .iter()
 +                .map(|detached_file| PackageRoot {
 +                    is_local: true,
 +                    include: vec![detached_file.clone()],
 +                    exclude: Vec::new(),
 +                })
 +                .chain(sysroot.crates().map(|krate| PackageRoot {
 +                    is_local: false,
 +                    include: vec![sysroot[krate].root.parent().to_path_buf()],
 +                    exclude: Vec::new(),
 +                }))
 +                .collect(),
 +        }
 +    }
 +
 +    pub fn n_packages(&self) -> usize {
 +        match self {
 +            ProjectWorkspace::Json { project, .. } => project.n_crates(),
 +            ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
 +                let rustc_package_len = rustc.as_ref().map_or(0, |it| it.packages().len());
 +                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
 +                cargo.packages().len() + sysroot_package_len + rustc_package_len
 +            }
 +            ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
 +                sysroot.crates().len() + files.len()
 +            }
 +        }
 +    }
 +
 +    pub fn to_crate_graph(
 +        &self,
 +        load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +        load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
++        config: &CargoConfig,
 +    ) -> CrateGraph {
 +        let _p = profile::span("ProjectWorkspace::to_crate_graph");
 +
 +        let mut crate_graph = match self {
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
 +                rustc_cfg.clone(),
 +                load_proc_macro,
 +                load,
 +                project,
 +                sysroot,
++                config,
 +            ),
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                sysroot,
 +                rustc,
 +                rustc_cfg,
 +                cfg_overrides,
 +                build_scripts,
 +                toolchain: _,
 +            } => cargo_to_crate_graph(
 +                rustc_cfg.clone(),
 +                cfg_overrides,
 +                load_proc_macro,
 +                load,
 +                cargo,
 +                build_scripts,
 +                sysroot.as_ref(),
 +                rustc,
 +            ),
 +            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
 +                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
 +            }
 +        };
 +        if crate_graph.patch_cfg_if() {
 +            tracing::debug!("Patched std to depend on cfg-if")
 +        } else {
 +            tracing::debug!("Did not patch std to depend on cfg-if")
 +        }
 +        crate_graph
 +    }
 +}
 +
 +fn project_json_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    project: &ProjectJson,
 +    sysroot: &Option<Sysroot>,
++    config: &CargoConfig,
 +) -> CrateGraph {
 +    let mut crate_graph = CrateGraph::default();
 +    let sysroot_deps = sysroot
 +        .as_ref()
 +        .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
 +
 +    let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
 +    let crates: NoHashHashMap<CrateId, CrateId> = project
 +        .crates()
 +        .filter_map(|(crate_id, krate)| {
 +            let file_path = &krate.root_module;
 +            let file_id = load(file_path)?;
 +            Some((crate_id, krate, file_id))
 +        })
 +        .map(|(crate_id, krate, file_id)| {
 +            let env = krate.env.clone().into_iter().collect();
 +            let proc_macro = match krate.proc_macro_dylib_path.clone() {
 +                Some(it) => load_proc_macro(
 +                    krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""),
 +                    &it,
 +                ),
 +                None => Err("no proc macro dylib present".into()),
 +            };
 +
 +            let target_cfgs = match krate.target.as_deref() {
++                Some(target) => cfg_cache
++                    .entry(target)
++                    .or_insert_with(|| rustc_cfg::get(None, Some(target), config)),
 +                None => &rustc_cfg,
 +            };
 +
 +            let mut cfg_options = CfgOptions::default();
 +            cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
 +            (
 +                crate_id,
 +                crate_graph.add_crate_root(
 +                    file_id,
 +                    krate.edition,
 +                    krate.display_name.clone(),
 +                    krate.version.clone(),
 +                    cfg_options.clone(),
 +                    cfg_options,
 +                    env,
 +                    proc_macro,
 +                    krate.is_proc_macro,
 +                    if krate.display_name.is_some() {
 +                        CrateOrigin::CratesIo { repo: krate.repository.clone() }
 +                    } else {
 +                        CrateOrigin::CratesIo { repo: None }
 +                    },
 +                ),
 +            )
 +        })
 +        .collect();
 +
 +    for (from, krate) in project.crates() {
 +        if let Some(&from) = crates.get(&from) {
 +            if let Some((public_deps, libproc_macro)) = &sysroot_deps {
 +                public_deps.add(from, &mut crate_graph);
 +                if krate.is_proc_macro {
 +                    if let Some(proc_macro) = libproc_macro {
 +                        add_dep(
 +                            &mut crate_graph,
 +                            from,
 +                            CrateName::new("proc_macro").unwrap(),
 +                            *proc_macro,
 +                        );
 +                    }
 +                }
 +            }
 +
 +            for dep in &krate.deps {
 +                if let Some(&to) = crates.get(&dep.crate_id) {
 +                    add_dep(&mut crate_graph, from, dep.name.clone(), to)
 +                }
 +            }
 +        }
 +    }
 +    crate_graph
 +}
 +
 +fn cargo_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    override_cfg: &CfgOverrides,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    cargo: &CargoWorkspace,
 +    build_scripts: &WorkspaceBuildScripts,
 +    sysroot: Option<&Sysroot>,
 +    rustc: &Option<CargoWorkspace>,
 +) -> CrateGraph {
 +    let _p = profile::span("cargo_to_crate_graph");
 +    let mut crate_graph = CrateGraph::default();
 +    let (public_deps, libproc_macro) = match sysroot {
 +        Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
 +        None => (SysrootPublicDeps::default(), None),
 +    };
 +
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +
 +    let mut pkg_to_lib_crate = FxHashMap::default();
 +
 +    cfg_options.insert_atom("debug_assertions".into());
 +
 +    let mut pkg_crates = FxHashMap::default();
 +    // Does any crate signal to rust-analyzer that they need the rustc_private crates?
 +    let mut has_private = false;
 +    // Next, create crates for each package, target pair
 +    for pkg in cargo.packages() {
 +        let mut cfg_options = cfg_options.clone();
 +
 +        let overrides = match override_cfg {
 +            CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
 +            CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
 +        };
 +
 +        // Add test cfg for local crates
 +        if cargo[pkg].is_local {
 +            cfg_options.insert_atom("test".into());
 +        }
 +
 +        if let Some(overrides) = overrides {
 +            // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
 +            // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
 +            // working on rust-lang/rust as that's the only time it appears outside sysroot).
 +            //
 +            // A more ideal solution might be to reanalyze crates based on where the cursor is and
 +            // figure out the set of cfgs that would have to apply to make it active.
 +
 +            cfg_options.apply_diff(overrides.clone());
 +        };
 +
 +        has_private |= cargo[pkg].metadata.rustc_private;
 +        let mut lib_tgt = None;
 +        for &tgt in cargo[pkg].targets.iter() {
 +            if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member {
 +                // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't
 +                // add any targets except the library target, since those will not work correctly if
 +                // they use dev-dependencies.
 +                // In fact, they can break quite badly if multiple client workspaces get merged:
 +                // https://github.com/rust-lang/rust-analyzer/issues/11300
 +                continue;
 +            }
 +
 +            if let Some(file_id) = load(&cargo[tgt].root) {
 +                let crate_id = add_target_crate_root(
 +                    &mut crate_graph,
 +                    &cargo[pkg],
 +                    build_scripts.get_output(pkg),
 +                    cfg_options.clone(),
 +                    &mut |path| load_proc_macro(&cargo[tgt].name, path),
 +                    file_id,
 +                    &cargo[tgt].name,
 +                    cargo[tgt].is_proc_macro,
 +                );
 +                if cargo[tgt].kind == TargetKind::Lib {
 +                    lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
 +                    pkg_to_lib_crate.insert(pkg, crate_id);
 +                }
 +                if let Some(proc_macro) = libproc_macro {
 +                    add_dep_with_prelude(
 +                        &mut crate_graph,
 +                        crate_id,
 +                        CrateName::new("proc_macro").unwrap(),
 +                        proc_macro,
 +                        cargo[tgt].is_proc_macro,
 +                    );
 +                }
 +
 +                pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
 +            }
 +        }
 +
 +        // Set deps to the core, std and to the lib target of the current package
 +        for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
 +            // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
 +            public_deps.add(*from, &mut crate_graph);
 +
 +            if let Some((to, name)) = lib_tgt.clone() {
 +                if to != *from && *kind != TargetKind::BuildScript {
 +                    // (build script can not depend on its library target)
 +
 +                    // For root projects with dashes in their name,
 +                    // cargo metadata does not do any normalization,
 +                    // so we do it ourselves currently
 +                    let name = CrateName::normalize_dashes(&name);
 +                    add_dep(&mut crate_graph, *from, name, to);
 +                }
 +            }
 +        }
 +    }
 +
 +    // Now add a dep edge from all targets of upstream to the lib
 +    // target of downstream.
 +    for pkg in cargo.packages() {
 +        for dep in cargo[pkg].dependencies.iter() {
 +            let name = CrateName::new(&dep.name).unwrap();
 +            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
 +                for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
 +                    if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
 +                        // Only build scripts may depend on build dependencies.
 +                        continue;
 +                    }
 +                    if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
 +                        // Build scripts may only depend on build dependencies.
 +                        continue;
 +                    }
 +
 +                    add_dep(&mut crate_graph, *from, name.clone(), to)
 +                }
 +            }
 +        }
 +    }
 +
 +    if has_private {
 +        // If the user provided a path to rustc sources, we add all the rustc_private crates
 +        // and create dependencies on them for the crates which opt-in to that
 +        if let Some(rustc_workspace) = rustc {
 +            handle_rustc_crates(
 +                rustc_workspace,
 +                load,
 +                &mut crate_graph,
 +                &cfg_options,
 +                override_cfg,
 +                load_proc_macro,
 +                &mut pkg_to_lib_crate,
 +                &public_deps,
 +                cargo,
 +                &pkg_crates,
 +                build_scripts,
 +            );
 +        }
 +    }
 +    crate_graph
 +}
 +
 +fn detached_files_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    detached_files: &[AbsPathBuf],
 +    sysroot: &Sysroot,
 +) -> CrateGraph {
 +    let _p = profile::span("detached_files_to_crate_graph");
 +    let mut crate_graph = CrateGraph::default();
 +    let (public_deps, _libproc_macro) =
 +        sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
 +
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +
 +    for detached_file in detached_files {
 +        let file_id = match load(detached_file) {
 +            Some(file_id) => file_id,
 +            None => {
 +                tracing::error!("Failed to load detached file {:?}", detached_file);
 +                continue;
 +            }
 +        };
 +        let display_name = detached_file
 +            .file_stem()
 +            .and_then(|os_str| os_str.to_str())
 +            .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
 +        let detached_file_crate = crate_graph.add_crate_root(
 +            file_id,
 +            Edition::CURRENT,
 +            display_name,
 +            None,
 +            cfg_options.clone(),
 +            cfg_options.clone(),
 +            Env::default(),
 +            Ok(Vec::new()),
 +            false,
 +            CrateOrigin::CratesIo { repo: None },
 +        );
 +
 +        public_deps.add(detached_file_crate, &mut crate_graph);
 +    }
 +    crate_graph
 +}
 +
 +fn handle_rustc_crates(
 +    rustc_workspace: &CargoWorkspace,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    crate_graph: &mut CrateGraph,
 +    cfg_options: &CfgOptions,
 +    override_cfg: &CfgOverrides,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
 +    public_deps: &SysrootPublicDeps,
 +    cargo: &CargoWorkspace,
 +    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
 +    build_scripts: &WorkspaceBuildScripts,
 +) {
 +    let mut rustc_pkg_crates = FxHashMap::default();
 +    // The root package of the rustc-dev component is rustc_driver, so we match that
 +    let root_pkg =
 +        rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
 +    // The rustc workspace might be incomplete (such as if rustc-dev is not
 +    // installed for the current toolchain) and `rustc_source` is set to discover.
 +    if let Some(root_pkg) = root_pkg {
 +        // Iterate through every crate in the dependency subtree of rustc_driver using BFS
 +        let mut queue = VecDeque::new();
 +        queue.push_back(root_pkg);
 +        while let Some(pkg) = queue.pop_front() {
 +            // Don't duplicate packages if they are dependended on a diamond pattern
 +            // N.B. if this line is omitted, we try to analyse over 4_800_000 crates
 +            // which is not ideal
 +            if rustc_pkg_crates.contains_key(&pkg) {
 +                continue;
 +            }
 +            for dep in &rustc_workspace[pkg].dependencies {
 +                queue.push_back(dep.pkg);
 +            }
 +
 +            let mut cfg_options = cfg_options.clone();
 +
 +            let overrides = match override_cfg {
 +                CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
 +                CfgOverrides::Selective(cfg_overrides) => {
 +                    cfg_overrides.get(&rustc_workspace[pkg].name)
 +                }
 +            };
 +
 +            if let Some(overrides) = overrides {
 +                // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
 +                // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
 +                // working on rust-lang/rust as that's the only time it appears outside sysroot).
 +                //
 +                // A more ideal solution might be to reanalyze crates based on where the cursor is and
 +                // figure out the set of cfgs that would have to apply to make it active.
 +
 +                cfg_options.apply_diff(overrides.clone());
 +            };
 +
 +            for &tgt in rustc_workspace[pkg].targets.iter() {
 +                if rustc_workspace[tgt].kind != TargetKind::Lib {
 +                    continue;
 +                }
 +                if let Some(file_id) = load(&rustc_workspace[tgt].root) {
 +                    let crate_id = add_target_crate_root(
 +                        crate_graph,
 +                        &rustc_workspace[pkg],
 +                        build_scripts.get_output(pkg),
 +                        cfg_options.clone(),
 +                        &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
 +                        file_id,
 +                        &rustc_workspace[tgt].name,
 +                        rustc_workspace[tgt].is_proc_macro,
 +                    );
 +                    pkg_to_lib_crate.insert(pkg, crate_id);
 +                    // Add dependencies on core / std / alloc for this crate
 +                    public_deps.add(crate_id, crate_graph);
 +                    rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
 +                }
 +            }
 +        }
 +    }
 +    // Now add a dep edge from all targets of upstream to the lib
 +    // target of downstream.
 +    for pkg in rustc_pkg_crates.keys().copied() {
 +        for dep in rustc_workspace[pkg].dependencies.iter() {
 +            let name = CrateName::new(&dep.name).unwrap();
 +            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
 +                for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
 +                    add_dep(crate_graph, from, name.clone(), to);
 +                }
 +            }
 +        }
 +    }
 +    // Add a dependency on the rustc_private crates for all targets of each package
 +    // which opts in
 +    for dep in rustc_workspace.packages() {
 +        let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
 +
 +        if let Some(&to) = pkg_to_lib_crate.get(&dep) {
 +            for pkg in cargo.packages() {
 +                let package = &cargo[pkg];
 +                if !package.metadata.rustc_private {
 +                    continue;
 +                }
 +                for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
 +                    // Avoid creating duplicate dependencies
 +                    // This avoids the situation where `from` depends on e.g. `arrayvec`, but
 +                    // `rust_analyzer` thinks that it should use the one from the `rustc_source`
 +                    // instead of the one from `crates.io`
 +                    if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
 +                        add_dep(crate_graph, *from, name.clone(), to);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn add_target_crate_root(
 +    crate_graph: &mut CrateGraph,
 +    pkg: &PackageData,
 +    build_data: Option<&BuildScriptOutput>,
 +    cfg_options: CfgOptions,
 +    load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult,
 +    file_id: FileId,
 +    cargo_name: &str,
 +    is_proc_macro: bool,
 +) -> CrateId {
 +    let edition = pkg.edition;
 +    let mut potential_cfg_options = cfg_options.clone();
 +    potential_cfg_options.extend(
 +        pkg.features
 +            .iter()
 +            .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
 +    );
 +    let cfg_options = {
 +        let mut opts = cfg_options;
 +        for feature in pkg.active_features.iter() {
 +            opts.insert_key_value("feature".into(), feature.into());
 +        }
 +        if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
 +            opts.extend(cfgs.iter().cloned());
 +        }
 +        opts
 +    };
 +
 +    let mut env = Env::default();
 +    inject_cargo_env(pkg, &mut env);
 +
 +    if let Some(envs) = build_data.map(|it| &it.envs) {
 +        for (k, v) in envs {
 +            env.set(k, v.clone());
 +        }
 +    }
 +
 +    let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
 +        Some(Some(it)) => load_proc_macro(it),
 +        Some(None) => Err("no proc macro dylib present".into()),
 +        None => Err("crate has not (yet) been built".into()),
 +    };
 +
 +    let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
 +    crate_graph.add_crate_root(
 +        file_id,
 +        edition,
 +        Some(display_name),
 +        Some(pkg.version.to_string()),
 +        cfg_options,
 +        potential_cfg_options,
 +        env,
 +        proc_macro,
 +        is_proc_macro,
 +        CrateOrigin::CratesIo { repo: pkg.repository.clone() },
 +    )
 +}
 +
 +#[derive(Default)]
 +struct SysrootPublicDeps {
 +    deps: Vec<(CrateName, CrateId, bool)>,
 +}
 +
 +impl SysrootPublicDeps {
 +    /// Makes `from` depend on the public sysroot crates.
 +    fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) {
 +        for (name, krate, prelude) in &self.deps {
 +            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
 +        }
 +    }
 +}
 +
 +fn sysroot_to_crate_graph(
 +    crate_graph: &mut CrateGraph,
 +    sysroot: &Sysroot,
 +    rustc_cfg: Vec<CfgFlag>,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +) -> (SysrootPublicDeps, Option<CrateId>) {
 +    let _p = profile::span("sysroot_to_crate_graph");
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +    let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
 +        .crates()
 +        .filter_map(|krate| {
 +            let file_id = load(&sysroot[krate].root)?;
 +
 +            let env = Env::default();
 +            let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
 +            let crate_id = crate_graph.add_crate_root(
 +                file_id,
 +                Edition::CURRENT,
 +                Some(display_name),
 +                None,
 +                cfg_options.clone(),
 +                cfg_options.clone(),
 +                env,
 +                Err("no proc macro loaded for sysroot crate".into()),
 +                false,
 +                CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
 +            );
 +            Some((krate, crate_id))
 +        })
 +        .collect();
 +
 +    for from in sysroot.crates() {
 +        for &to in sysroot[from].deps.iter() {
 +            let name = CrateName::new(&sysroot[to].name).unwrap();
 +            if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
 +                add_dep(crate_graph, from, name, to);
 +            }
 +        }
 +    }
 +
 +    let public_deps = SysrootPublicDeps {
 +        deps: sysroot
 +            .public_deps()
 +            .map(|(name, idx, prelude)| {
 +                (CrateName::new(name).unwrap(), sysroot_crates[&idx], prelude)
 +            })
 +            .collect::<Vec<_>>(),
 +    };
 +
 +    let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
 +    (public_deps, libproc_macro)
 +}
 +
 +fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
 +    add_dep_inner(graph, from, Dependency::new(name, to))
 +}
 +
 +fn add_dep_with_prelude(
 +    graph: &mut CrateGraph,
 +    from: CrateId,
 +    name: CrateName,
 +    to: CrateId,
 +    prelude: bool,
 +) {
 +    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
 +}
 +
 +fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
 +    if let Err(err) = graph.add_dep(from, dep) {
 +        tracing::error!("{}", err)
 +    }
 +}
 +
 +/// Recreates the compile-time environment variables that Cargo sets.
 +///
 +/// Should be synced with
 +/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
 +///
 +/// FIXME: ask Cargo to provide this data instead of re-deriving.
 +fn inject_cargo_env(package: &PackageData, env: &mut Env) {
 +    // FIXME: Missing variables:
 +    // CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
 +
 +    let manifest_dir = package.manifest.parent();
 +    env.set("CARGO_MANIFEST_DIR", manifest_dir.as_os_str().to_string_lossy().into_owned());
 +
 +    // Not always right, but works for common cases.
 +    env.set("CARGO", "cargo".into());
 +
 +    env.set("CARGO_PKG_VERSION", package.version.to_string());
 +    env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
 +    env.set("CARGO_PKG_VERSION_MINOR", package.version.minor.to_string());
 +    env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string());
 +    env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string());
 +
 +    env.set("CARGO_PKG_AUTHORS", String::new());
 +
 +    env.set("CARGO_PKG_NAME", package.name.clone());
 +    // FIXME: This isn't really correct (a package can have many crates with different names), but
 +    // it's better than leaving the variable unset.
 +    env.set("CARGO_CRATE_NAME", CrateName::normalize_dashes(&package.name).to_string());
 +    env.set("CARGO_PKG_DESCRIPTION", String::new());
 +    env.set("CARGO_PKG_HOMEPAGE", String::new());
 +    env.set("CARGO_PKG_REPOSITORY", String::new());
 +    env.set("CARGO_PKG_LICENSE", String::new());
 +
 +    env.set("CARGO_PKG_LICENSE_FILE", String::new());
 +}
index f52e1e7512788d7828d4bba26d09d6b58c8df422,0000000000000000000000000000000000000000..80128e43fd3c50f6be8ce8aec7190ff8a4fe9df6
mode 100644,000000..100644
--- /dev/null
@@@ -1,447 -1,0 +1,448 @@@
-         let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
 +//! Fully type-check project and print various stats, like the number of type
 +//! errors.
 +
 +use std::{
 +    env,
 +    time::{SystemTime, UNIX_EPOCH},
 +};
 +
 +use hir::{
 +    db::{AstDatabase, DefDatabase, HirDatabase},
 +    AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
 +};
 +use hir_def::{
 +    body::{BodySourceMap, SyntheticSyntax},
 +    expr::ExprId,
 +    FunctionId,
 +};
 +use hir_ty::{TyExt, TypeWalk};
 +use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
 +use ide_db::base_db::{
 +    salsa::{self, debug::DebugQueryTable, ParallelDatabase},
 +    SourceDatabase, SourceDatabaseExt,
 +};
 +use itertools::Itertools;
 +use oorandom::Rand32;
 +use profile::{Bytes, StopWatch};
 +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 +use rayon::prelude::*;
 +use rustc_hash::FxHashSet;
 +use stdx::format_to;
 +use syntax::{AstNode, SyntaxNode};
 +use vfs::{AbsPathBuf, Vfs, VfsPath};
 +
 +use crate::cli::{
 +    flags::{self, OutputFormat},
 +    load_cargo::{load_workspace, LoadCargoConfig},
 +    print_memory_usage,
 +    progress_report::ProgressReport,
 +    report_metric, Result, Verbosity,
 +};
 +
 +/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
 +struct Snap<DB>(DB);
 +impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
 +    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
 +        Snap(self.0.snapshot())
 +    }
 +}
 +
 +impl flags::AnalysisStats {
 +    pub fn run(self, verbosity: Verbosity) -> Result<()> {
 +        let mut rng = {
 +            let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
 +            Rand32::new(seed)
 +        };
 +
 +        let mut cargo_config = CargoConfig::default();
 +        cargo_config.no_sysroot = self.no_sysroot;
 +        let load_cargo_config = LoadCargoConfig {
 +            load_out_dirs_from_check: !self.disable_build_scripts,
 +            with_proc_macro: !self.disable_proc_macros,
 +            prefill_caches: false,
 +        };
 +        let no_progress = &|_| ();
 +
 +        let mut db_load_sw = self.stop_watch();
 +
 +        let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
 +        let manifest = ProjectManifest::discover_single(&path)?;
 +
 +        let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 +        let metadata_time = db_load_sw.elapsed();
 +
 +        let build_scripts_time = if self.disable_build_scripts {
 +            None
 +        } else {
 +            let mut build_scripts_sw = self.stop_watch();
 +            let bs = workspace.run_build_scripts(&cargo_config, no_progress)?;
 +            workspace.set_build_scripts(bs);
 +            Some(build_scripts_sw.elapsed())
 +        };
 +
++        let (host, vfs, _proc_macro) =
++            load_workspace(workspace, &cargo_config, &load_cargo_config)?;
 +        let db = host.raw_database();
 +        eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed());
 +        eprint!(" (metadata {}", metadata_time);
 +        if let Some(build_scripts_time) = build_scripts_time {
 +            eprint!("; build {}", build_scripts_time);
 +        }
 +        eprintln!(")");
 +
 +        let mut analysis_sw = self.stop_watch();
 +        let mut num_crates = 0;
 +        let mut visited_modules = FxHashSet::default();
 +        let mut visit_queue = Vec::new();
 +
 +        let mut krates = Crate::all(db);
 +        if self.randomize {
 +            shuffle(&mut rng, &mut krates);
 +        }
 +        for krate in krates {
 +            let module = krate.root_module(db);
 +            let file_id = module.definition_source(db).file_id;
 +            let file_id = file_id.original_file(db);
 +            let source_root = db.file_source_root(file_id);
 +            let source_root = db.source_root(source_root);
 +            if !source_root.is_library || self.with_deps {
 +                num_crates += 1;
 +                visit_queue.push(module);
 +            }
 +        }
 +
 +        if self.randomize {
 +            shuffle(&mut rng, &mut visit_queue);
 +        }
 +
 +        eprint!("  crates: {}", num_crates);
 +        let mut num_decls = 0;
 +        let mut funcs = Vec::new();
 +        while let Some(module) = visit_queue.pop() {
 +            if visited_modules.insert(module) {
 +                visit_queue.extend(module.children(db));
 +
 +                for decl in module.declarations(db) {
 +                    num_decls += 1;
 +                    if let ModuleDef::Function(f) = decl {
 +                        funcs.push(f);
 +                    }
 +                }
 +
 +                for impl_def in module.impl_defs(db) {
 +                    for item in impl_def.items(db) {
 +                        num_decls += 1;
 +                        if let AssocItem::Function(f) = item {
 +                            funcs.push(f);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +        eprintln!(", mods: {}, decls: {}, fns: {}", visited_modules.len(), num_decls, funcs.len());
 +        eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed());
 +
 +        if self.randomize {
 +            shuffle(&mut rng, &mut funcs);
 +        }
 +
 +        if !self.skip_inference {
 +            self.run_inference(&host, db, &vfs, &funcs, verbosity);
 +        }
 +
 +        let total_span = analysis_sw.elapsed();
 +        eprintln!("{:<20} {}", "Total:", total_span);
 +        report_metric("total time", total_span.time.as_millis() as u64, "ms");
 +        if let Some(instructions) = total_span.instructions {
 +            report_metric("total instructions", instructions, "#instr");
 +        }
 +        if let Some(memory) = total_span.memory {
 +            report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
 +        }
 +
 +        if env::var("RA_COUNT").is_ok() {
 +            eprintln!("{}", profile::countme::get_all());
 +        }
 +
 +        if self.source_stats {
 +            let mut total_file_size = Bytes::default();
 +            for e in ide_db::base_db::ParseQuery.in_db(db).entries::<Vec<_>>() {
 +                total_file_size += syntax_len(db.parse(e.key).syntax_node())
 +            }
 +
 +            let mut total_macro_file_size = Bytes::default();
 +            for e in hir::db::ParseMacroExpansionQuery.in_db(db).entries::<Vec<_>>() {
 +                if let Some((val, _)) = db.parse_macro_expansion(e.key).value {
 +                    total_macro_file_size += syntax_len(val.syntax_node())
 +                }
 +            }
 +            eprintln!("source files: {}, macro files: {}", total_file_size, total_macro_file_size);
 +        }
 +
 +        if self.memory_usage && verbosity.is_verbose() {
 +            print_memory_usage(host, vfs);
 +        }
 +
 +        Ok(())
 +    }
 +
 +    fn run_inference(
 +        &self,
 +        host: &AnalysisHost,
 +        db: &RootDatabase,
 +        vfs: &Vfs,
 +        funcs: &[Function],
 +        verbosity: Verbosity,
 +    ) {
 +        let mut bar = match verbosity {
 +            Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
 +            _ if self.parallel || self.output.is_some() => ProgressReport::hidden(),
 +            _ => ProgressReport::new(funcs.len() as u64),
 +        };
 +
 +        if self.parallel {
 +            let mut inference_sw = self.stop_watch();
 +            let snap = Snap(db.snapshot());
 +            funcs
 +                .par_iter()
 +                .map_with(snap, |snap, &f| {
 +                    let f_id = FunctionId::from(f);
 +                    snap.0.body(f_id.into());
 +                    snap.0.infer(f_id.into());
 +                })
 +                .count();
 +            eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed());
 +        }
 +
 +        let mut inference_sw = self.stop_watch();
 +        bar.tick();
 +        let mut num_exprs = 0;
 +        let mut num_exprs_unknown = 0;
 +        let mut num_exprs_partially_unknown = 0;
 +        let mut num_type_mismatches = 0;
 +        let analysis = host.analysis();
 +        for f in funcs.iter().copied() {
 +            let name = f.name(db);
 +            let full_name = f
 +                .module(db)
 +                .path_to_root(db)
 +                .into_iter()
 +                .rev()
 +                .filter_map(|it| it.name(db))
 +                .chain(Some(f.name(db)))
 +                .join("::");
 +            if let Some(only_name) = self.only.as_deref() {
 +                if name.to_string() != only_name && full_name != only_name {
 +                    continue;
 +                }
 +            }
 +            let mut msg = format!("processing: {}", full_name);
 +            if verbosity.is_verbose() {
 +                if let Some(src) = f.source(db) {
 +                    let original_file = src.file_id.original_file(db);
 +                    let path = vfs.file_path(original_file);
 +                    let syntax_range = src.value.syntax().text_range();
 +                    format_to!(msg, " ({} {:?})", path, syntax_range);
 +                }
 +            }
 +            if verbosity.is_spammy() {
 +                bar.println(msg.to_string());
 +            }
 +            bar.set_message(&msg);
 +            let f_id = FunctionId::from(f);
 +            let (body, sm) = db.body_with_source_map(f_id.into());
 +            let inference_result = db.infer(f_id.into());
 +            let (previous_exprs, previous_unknown, previous_partially_unknown) =
 +                (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
 +            for (expr_id, _) in body.exprs.iter() {
 +                let ty = &inference_result[expr_id];
 +                num_exprs += 1;
 +                let unknown_or_partial = if ty.is_unknown() {
 +                    num_exprs_unknown += 1;
 +                    if verbosity.is_spammy() {
 +                        if let Some((path, start, end)) =
 +                            expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
 +                        {
 +                            bar.println(format!(
 +                                "{} {}:{}-{}:{}: Unknown type",
 +                                path,
 +                                start.line + 1,
 +                                start.col,
 +                                end.line + 1,
 +                                end.col,
 +                            ));
 +                        } else {
 +                            bar.println(format!("{}: Unknown type", name,));
 +                        }
 +                    }
 +                    true
 +                } else {
 +                    let mut is_partially_unknown = false;
 +                    ty.walk(&mut |ty| {
 +                        if ty.is_unknown() {
 +                            is_partially_unknown = true;
 +                        }
 +                    });
 +                    if is_partially_unknown {
 +                        num_exprs_partially_unknown += 1;
 +                    }
 +                    is_partially_unknown
 +                };
 +                if self.only.is_some() && verbosity.is_spammy() {
 +                    // in super-verbose mode for just one function, we print every single expression
 +                    if let Some((_, start, end)) =
 +                        expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
 +                    {
 +                        bar.println(format!(
 +                            "{}:{}-{}:{}: {}",
 +                            start.line + 1,
 +                            start.col,
 +                            end.line + 1,
 +                            end.col,
 +                            ty.display(db)
 +                        ));
 +                    } else {
 +                        bar.println(format!("unknown location: {}", ty.display(db)));
 +                    }
 +                }
 +                if unknown_or_partial && self.output == Some(OutputFormat::Csv) {
 +                    println!(
 +                        r#"{},type,"{}""#,
 +                        location_csv(db, &analysis, vfs, &sm, expr_id),
 +                        ty.display(db)
 +                    );
 +                }
 +                if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
 +                    num_type_mismatches += 1;
 +                    if verbosity.is_verbose() {
 +                        if let Some((path, start, end)) =
 +                            expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
 +                        {
 +                            bar.println(format!(
 +                                "{} {}:{}-{}:{}: Expected {}, got {}",
 +                                path,
 +                                start.line + 1,
 +                                start.col,
 +                                end.line + 1,
 +                                end.col,
 +                                mismatch.expected.display(db),
 +                                mismatch.actual.display(db)
 +                            ));
 +                        } else {
 +                            bar.println(format!(
 +                                "{}: Expected {}, got {}",
 +                                name,
 +                                mismatch.expected.display(db),
 +                                mismatch.actual.display(db)
 +                            ));
 +                        }
 +                    }
 +                    if self.output == Some(OutputFormat::Csv) {
 +                        println!(
 +                            r#"{},mismatch,"{}","{}""#,
 +                            location_csv(db, &analysis, vfs, &sm, expr_id),
 +                            mismatch.expected.display(db),
 +                            mismatch.actual.display(db)
 +                        );
 +                    }
 +                }
 +            }
 +            if verbosity.is_spammy() {
 +                bar.println(format!(
 +                    "In {}: {} exprs, {} unknown, {} partial",
 +                    full_name,
 +                    num_exprs - previous_exprs,
 +                    num_exprs_unknown - previous_unknown,
 +                    num_exprs_partially_unknown - previous_partially_unknown
 +                ));
 +            }
 +            bar.inc(1);
 +        }
 +
 +        bar.finish_and_clear();
 +        eprintln!(
 +            "  exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}",
 +            num_exprs,
 +            num_exprs_unknown,
 +            percentage(num_exprs_unknown, num_exprs),
 +            num_exprs_partially_unknown,
 +            percentage(num_exprs_partially_unknown, num_exprs),
 +            num_type_mismatches
 +        );
 +        report_metric("unknown type", num_exprs_unknown, "#");
 +        report_metric("type mismatches", num_type_mismatches, "#");
 +
 +        eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed());
 +    }
 +
 +    fn stop_watch(&self) -> StopWatch {
 +        StopWatch::start().memory(self.memory_usage)
 +    }
 +}
 +
 +fn location_csv(
 +    db: &RootDatabase,
 +    analysis: &Analysis,
 +    vfs: &Vfs,
 +    sm: &BodySourceMap,
 +    expr_id: ExprId,
 +) -> String {
 +    let src = match sm.expr_syntax(expr_id) {
 +        Ok(s) => s,
 +        Err(SyntheticSyntax) => return "synthetic,,".to_string(),
 +    };
 +    let root = db.parse_or_expand(src.file_id).unwrap();
 +    let node = src.map(|e| e.to_node(&root).syntax().clone());
 +    let original_range = node.as_ref().original_file_range(db);
 +    let path = vfs.file_path(original_range.file_id);
 +    let line_index = analysis.file_line_index(original_range.file_id).unwrap();
 +    let text_range = original_range.range;
 +    let (start, end) =
 +        (line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
 +    format!("{},{}:{},{}:{}", path, start.line + 1, start.col, end.line + 1, end.col)
 +}
 +
 +fn expr_syntax_range(
 +    db: &RootDatabase,
 +    analysis: &Analysis,
 +    vfs: &Vfs,
 +    sm: &BodySourceMap,
 +    expr_id: ExprId,
 +) -> Option<(VfsPath, LineCol, LineCol)> {
 +    let src = sm.expr_syntax(expr_id);
 +    if let Ok(src) = src {
 +        let root = db.parse_or_expand(src.file_id).unwrap();
 +        let node = src.map(|e| e.to_node(&root).syntax().clone());
 +        let original_range = node.as_ref().original_file_range(db);
 +        let path = vfs.file_path(original_range.file_id);
 +        let line_index = analysis.file_line_index(original_range.file_id).unwrap();
 +        let text_range = original_range.range;
 +        let (start, end) =
 +            (line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
 +        Some((path, start, end))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
 +    for i in 0..slice.len() {
 +        randomize_first(rng, &mut slice[i..]);
 +    }
 +
 +    fn randomize_first<T>(rng: &mut Rand32, slice: &mut [T]) {
 +        assert!(!slice.is_empty());
 +        let idx = rng.rand_range(0..slice.len() as u32) as usize;
 +        slice.swap(0, idx);
 +    }
 +}
 +
 +fn percentage(n: u64, total: u64) -> u64 {
 +    (n * 100).checked_div(total).unwrap_or(100)
 +}
 +
 +fn syntax_len(node: SyntaxNode) -> usize {
 +    // Macro expanded code doesn't contain whitespace, so erase *all* whitespace
 +    // to make macro and non-macro code comparable.
 +    node.to_string().replace(|it: char| it.is_ascii_whitespace(), "").len()
 +}
index 5d1c013c3275b2fabf86110ec16ac13dc75e0a1f,0000000000000000000000000000000000000000..88953096e2bcd5fff1e61984085458505319b62a
mode 100644,000000..100644
--- /dev/null
@@@ -1,164 -1,0 +1,166 @@@
-     load_workspace(workspace, load_config)
 +//! Loads a Cargo project into a static instance of analysis, without support
 +//! for incorporating changes.
 +use std::{path::Path, sync::Arc};
 +
 +use anyhow::Result;
 +use crossbeam_channel::{unbounded, Receiver};
 +use hir::db::DefDatabase;
 +use ide::{AnalysisHost, Change};
 +use ide_db::base_db::CrateGraph;
 +use proc_macro_api::ProcMacroServer;
 +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 +use vfs::{loader::Handle, AbsPath, AbsPathBuf};
 +
 +use crate::reload::{load_proc_macro, ProjectFolders, SourceRootConfig};
 +
 +// Note: Since this type is used by external tools that use rust-analyzer as a library
 +// what otherwise would be `pub(crate)` has to be `pub` here instead.
 +pub struct LoadCargoConfig {
 +    pub load_out_dirs_from_check: bool,
 +    pub with_proc_macro: bool,
 +    pub prefill_caches: bool,
 +}
 +
 +// Note: Since this function is used by external tools that use rust-analyzer as a library
 +// what otherwise would be `pub(crate)` has to be `pub` here instead.
 +pub fn load_workspace_at(
 +    root: &Path,
 +    cargo_config: &CargoConfig,
 +    load_config: &LoadCargoConfig,
 +    progress: &dyn Fn(String),
 +) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroServer>)> {
 +    let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
 +    let root = ProjectManifest::discover_single(&root)?;
 +    let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
 +
 +    if load_config.load_out_dirs_from_check {
 +        let build_scripts = workspace.run_build_scripts(cargo_config, progress)?;
 +        workspace.set_build_scripts(build_scripts)
 +    }
 +
++    load_workspace(workspace, cargo_config, load_config)
 +}
 +
 +// Note: Since this function is used by external tools that use rust-analyzer as a library
 +// what otherwise would be `pub(crate)` has to be `pub` here instead.
 +//
 +// The reason both, `load_workspace_at` and `load_workspace` are `pub` is that some of
 +// these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides.
 +pub fn load_workspace(
 +    ws: ProjectWorkspace,
++    cargo_config: &CargoConfig,
 +    load_config: &LoadCargoConfig,
 +) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroServer>)> {
 +    let (sender, receiver) = unbounded();
 +    let mut vfs = vfs::Vfs::default();
 +    let mut loader = {
 +        let loader =
 +            vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
 +        Box::new(loader)
 +    };
 +
 +    let proc_macro_client = if load_config.with_proc_macro {
 +        let path = AbsPathBuf::assert(std::env::current_exe()?);
 +        Ok(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap())
 +    } else {
 +        Err("proc macro server not started".to_owned())
 +    };
 +
 +    let crate_graph = ws.to_crate_graph(
 +        &mut |_, path: &AbsPath| {
 +            load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
 +        },
 +        &mut |path: &AbsPath| {
 +            let contents = loader.load_sync(path);
 +            let path = vfs::VfsPath::from(path.to_path_buf());
 +            vfs.set_file_contents(path.clone(), contents);
 +            vfs.file_id(&path)
 +        },
++        cargo_config,
 +    );
 +
 +    let project_folders = ProjectFolders::new(&[ws], &[]);
 +    loader.set_config(vfs::loader::Config {
 +        load: project_folders.load,
 +        watch: vec![],
 +        version: 0,
 +    });
 +
 +    tracing::debug!("crate graph: {:?}", crate_graph);
 +    let host =
 +        load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
 +
 +    if load_config.prefill_caches {
 +        host.analysis().parallel_prime_caches(1, |_| {})?;
 +    }
 +    Ok((host, vfs, proc_macro_client.ok()))
 +}
 +
 +fn load_crate_graph(
 +    crate_graph: CrateGraph,
 +    source_root_config: SourceRootConfig,
 +    vfs: &mut vfs::Vfs,
 +    receiver: &Receiver<vfs::loader::Message>,
 +) -> AnalysisHost {
 +    let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
 +    let mut host = AnalysisHost::new(lru_cap);
 +    let mut analysis_change = Change::new();
 +
 +    host.raw_database_mut().set_enable_proc_attr_macros(true);
 +
 +    // wait until Vfs has loaded all roots
 +    for task in receiver {
 +        match task {
 +            vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => {
 +                if n_done == n_total {
 +                    break;
 +                }
 +            }
 +            vfs::loader::Message::Loaded { files } => {
 +                for (path, contents) in files {
 +                    vfs.set_file_contents(path.into(), contents);
 +                }
 +            }
 +        }
 +    }
 +    let changes = vfs.take_changes();
 +    for file in changes {
 +        if file.exists() {
 +            let contents = vfs.file_contents(file.file_id).to_vec();
 +            if let Ok(text) = String::from_utf8(contents) {
 +                analysis_change.change_file(file.file_id, Some(Arc::new(text)))
 +            }
 +        }
 +    }
 +    let source_roots = source_root_config.partition(vfs);
 +    analysis_change.set_roots(source_roots);
 +
 +    analysis_change.set_crate_graph(crate_graph);
 +
 +    host.apply_change(analysis_change);
 +    host
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use hir::Crate;
 +
 +    #[test]
 +    fn test_loading_rust_analyzer() {
 +        let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
 +        let cargo_config = CargoConfig::default();
 +        let load_cargo_config = LoadCargoConfig {
 +            load_out_dirs_from_check: false,
 +            with_proc_macro: false,
 +            prefill_caches: false,
 +        };
 +        let (host, _vfs, _proc_macro) =
 +            load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap();
 +
 +        let n_crates = Crate::all(host.raw_database()).len();
 +        // RA has quite a few crates, but the exact count doesn't matter
 +        assert!(n_crates > 20);
 +    }
 +}
index 491c55a04f8c0ade80b19ed3d56632ac82275120,0000000000000000000000000000000000000000..79577bf78c8f9d64096e6754017c19164ead274b
mode 100644,000000..100644
--- /dev/null
@@@ -1,328 -1,0 +1,329 @@@
-         let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
 +//! LSIF (language server index format) generator
 +
 +use std::collections::HashMap;
 +use std::env;
 +use std::time::Instant;
 +
 +use ide::{
 +    Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex,
 +    StaticIndexedFile, TokenId, TokenStaticData,
 +};
 +use ide_db::LineIndexDatabase;
 +
 +use ide_db::base_db::salsa::{self, ParallelDatabase};
 +use lsp_types::{self, lsif};
 +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 +use vfs::{AbsPathBuf, Vfs};
 +
 +use crate::cli::{
 +    flags,
 +    load_cargo::{load_workspace, LoadCargoConfig},
 +    Result,
 +};
 +use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
 +use crate::to_proto;
 +use crate::version::version;
 +
 +/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
 +struct Snap<DB>(DB);
 +impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
 +    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
 +        Snap(self.0.snapshot())
 +    }
 +}
 +
 +struct LsifManager<'a> {
 +    count: i32,
 +    token_map: HashMap<TokenId, Id>,
 +    range_map: HashMap<FileRange, Id>,
 +    file_map: HashMap<FileId, Id>,
 +    package_map: HashMap<PackageInformation, Id>,
 +    analysis: &'a Analysis,
 +    db: &'a RootDatabase,
 +    vfs: &'a Vfs,
 +}
 +
 +#[derive(Clone, Copy)]
 +struct Id(i32);
 +
 +impl From<Id> for lsp_types::NumberOrString {
 +    fn from(Id(x): Id) -> Self {
 +        lsp_types::NumberOrString::Number(x)
 +    }
 +}
 +
 +impl LsifManager<'_> {
 +    fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
 +        LsifManager {
 +            count: 0,
 +            token_map: HashMap::default(),
 +            range_map: HashMap::default(),
 +            file_map: HashMap::default(),
 +            package_map: HashMap::default(),
 +            analysis,
 +            db,
 +            vfs,
 +        }
 +    }
 +
 +    fn add(&mut self, data: lsif::Element) -> Id {
 +        let id = Id(self.count);
 +        self.emit(&serde_json::to_string(&lsif::Entry { id: id.into(), data }).unwrap());
 +        self.count += 1;
 +        id
 +    }
 +
 +    fn add_vertex(&mut self, vertex: lsif::Vertex) -> Id {
 +        self.add(lsif::Element::Vertex(vertex))
 +    }
 +
 +    fn add_edge(&mut self, edge: lsif::Edge) -> Id {
 +        self.add(lsif::Element::Edge(edge))
 +    }
 +
 +    // FIXME: support file in addition to stdout here
 +    fn emit(&self, data: &str) {
 +        println!("{}", data);
 +    }
 +
 +    fn get_token_id(&mut self, id: TokenId) -> Id {
 +        if let Some(x) = self.token_map.get(&id) {
 +            return *x;
 +        }
 +        let result_set_id = self.add_vertex(lsif::Vertex::ResultSet(lsif::ResultSet { key: None }));
 +        self.token_map.insert(id, result_set_id);
 +        result_set_id
 +    }
 +
 +    fn get_package_id(&mut self, package_information: PackageInformation) -> Id {
 +        if let Some(x) = self.package_map.get(&package_information) {
 +            return *x;
 +        }
 +        let pi = package_information.clone();
 +        let result_set_id =
 +            self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation {
 +                name: pi.name,
 +                manager: "cargo".to_string(),
 +                uri: None,
 +                content: None,
 +                repository: Some(lsif::Repository {
 +                    url: pi.repo,
 +                    r#type: "git".to_string(),
 +                    commit_id: None,
 +                }),
 +                version: Some(pi.version),
 +            }));
 +        self.package_map.insert(package_information, result_set_id);
 +        result_set_id
 +    }
 +
 +    fn get_range_id(&mut self, id: FileRange) -> Id {
 +        if let Some(x) = self.range_map.get(&id) {
 +            return *x;
 +        }
 +        let file_id = id.file_id;
 +        let doc_id = self.get_file_id(file_id);
 +        let line_index = self.db.line_index(file_id);
 +        let line_index = LineIndex {
 +            index: line_index,
 +            encoding: OffsetEncoding::Utf16,
 +            endings: LineEndings::Unix,
 +        };
 +        let range_id = self.add_vertex(lsif::Vertex::Range {
 +            range: to_proto::range(&line_index, id.range),
 +            tag: None,
 +        });
 +        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
 +            in_vs: vec![range_id.into()],
 +            out_v: doc_id.into(),
 +        }));
 +        range_id
 +    }
 +
 +    fn get_file_id(&mut self, id: FileId) -> Id {
 +        if let Some(x) = self.file_map.get(&id) {
 +            return *x;
 +        }
 +        let path = self.vfs.file_path(id);
 +        let path = path.as_path().unwrap();
 +        let doc_id = self.add_vertex(lsif::Vertex::Document(lsif::Document {
 +            language_id: "rust".to_string(),
 +            uri: lsp_types::Url::from_file_path(path).unwrap(),
 +        }));
 +        self.file_map.insert(id, doc_id);
 +        doc_id
 +    }
 +
 +    fn add_token(&mut self, id: TokenId, token: TokenStaticData) {
 +        let result_set_id = self.get_token_id(id);
 +        if let Some(hover) = token.hover {
 +            let hover_id = self.add_vertex(lsif::Vertex::HoverResult {
 +                result: lsp_types::Hover {
 +                    contents: lsp_types::HoverContents::Markup(to_proto::markup_content(
 +                        hover.markup,
 +                        ide::HoverDocFormat::Markdown,
 +                    )),
 +                    range: None,
 +                },
 +            });
 +            self.add_edge(lsif::Edge::Hover(lsif::EdgeData {
 +                in_v: hover_id.into(),
 +                out_v: result_set_id.into(),
 +            }));
 +        }
 +        if let Some(moniker) = token.moniker {
 +            let package_id = self.get_package_id(moniker.package_information);
 +            let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
 +                scheme: "rust-analyzer".to_string(),
 +                identifier: moniker.identifier.to_string(),
 +                unique: lsp_types::UniquenessLevel::Scheme,
 +                kind: Some(match moniker.kind {
 +                    MonikerKind::Import => lsp_types::MonikerKind::Import,
 +                    MonikerKind::Export => lsp_types::MonikerKind::Export,
 +                }),
 +            }));
 +            self.add_edge(lsif::Edge::PackageInformation(lsif::EdgeData {
 +                in_v: package_id.into(),
 +                out_v: moniker_id.into(),
 +            }));
 +            self.add_edge(lsif::Edge::Moniker(lsif::EdgeData {
 +                in_v: moniker_id.into(),
 +                out_v: result_set_id.into(),
 +            }));
 +        }
 +        if let Some(def) = token.definition {
 +            let result_id = self.add_vertex(lsif::Vertex::DefinitionResult);
 +            let def_vertex = self.get_range_id(def);
 +            self.add_edge(lsif::Edge::Item(lsif::Item {
 +                document: (*self.file_map.get(&def.file_id).unwrap()).into(),
 +                property: None,
 +                edge_data: lsif::EdgeDataMultiIn {
 +                    in_vs: vec![def_vertex.into()],
 +                    out_v: result_id.into(),
 +                },
 +            }));
 +            self.add_edge(lsif::Edge::Definition(lsif::EdgeData {
 +                in_v: result_id.into(),
 +                out_v: result_set_id.into(),
 +            }));
 +        }
 +        if !token.references.is_empty() {
 +            let result_id = self.add_vertex(lsif::Vertex::ReferenceResult);
 +            self.add_edge(lsif::Edge::References(lsif::EdgeData {
 +                in_v: result_id.into(),
 +                out_v: result_set_id.into(),
 +            }));
 +            let mut edges = token.references.iter().fold(
 +                HashMap::<_, Vec<lsp_types::NumberOrString>>::new(),
 +                |mut edges, x| {
 +                    let entry =
 +                        edges.entry((x.range.file_id, x.is_definition)).or_insert_with(Vec::new);
 +                    entry.push((*self.range_map.get(&x.range).unwrap()).into());
 +                    edges
 +                },
 +            );
 +            for x in token.references {
 +                if let Some(vertices) = edges.remove(&(x.range.file_id, x.is_definition)) {
 +                    self.add_edge(lsif::Edge::Item(lsif::Item {
 +                        document: (*self.file_map.get(&x.range.file_id).unwrap()).into(),
 +                        property: Some(if x.is_definition {
 +                            lsif::ItemKind::Definitions
 +                        } else {
 +                            lsif::ItemKind::References
 +                        }),
 +                        edge_data: lsif::EdgeDataMultiIn {
 +                            in_vs: vertices,
 +                            out_v: result_id.into(),
 +                        },
 +                    }));
 +                }
 +            }
 +        }
 +    }
 +
 +    fn add_file(&mut self, file: StaticIndexedFile) {
 +        let StaticIndexedFile { file_id, tokens, folds, .. } = file;
 +        let doc_id = self.get_file_id(file_id);
 +        let text = self.analysis.file_text(file_id).unwrap();
 +        let line_index = self.db.line_index(file_id);
 +        let line_index = LineIndex {
 +            index: line_index,
 +            encoding: OffsetEncoding::Utf16,
 +            endings: LineEndings::Unix,
 +        };
 +        let result = folds
 +            .into_iter()
 +            .map(|it| to_proto::folding_range(&*text, &line_index, false, it))
 +            .collect();
 +        let folding_id = self.add_vertex(lsif::Vertex::FoldingRangeResult { result });
 +        self.add_edge(lsif::Edge::FoldingRange(lsif::EdgeData {
 +            in_v: folding_id.into(),
 +            out_v: doc_id.into(),
 +        }));
 +        let tokens_id = tokens
 +            .into_iter()
 +            .map(|(range, id)| {
 +                let range_id = self.add_vertex(lsif::Vertex::Range {
 +                    range: to_proto::range(&line_index, range),
 +                    tag: None,
 +                });
 +                self.range_map.insert(FileRange { file_id, range }, range_id);
 +                let result_set_id = self.get_token_id(id);
 +                self.add_edge(lsif::Edge::Next(lsif::EdgeData {
 +                    in_v: result_set_id.into(),
 +                    out_v: range_id.into(),
 +                }));
 +                range_id.into()
 +            })
 +            .collect();
 +        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
 +            in_vs: tokens_id,
 +            out_v: doc_id.into(),
 +        }));
 +    }
 +}
 +
 +impl flags::Lsif {
 +    pub fn run(self) -> Result<()> {
 +        eprintln!("Generating LSIF started...");
 +        let now = Instant::now();
 +        let cargo_config = CargoConfig::default();
 +        let no_progress = &|_| ();
 +        let load_cargo_config = LoadCargoConfig {
 +            load_out_dirs_from_check: true,
 +            with_proc_macro: true,
 +            prefill_caches: false,
 +        };
 +        let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
 +        let manifest = ProjectManifest::discover_single(&path)?;
 +
 +        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 +
++        let (host, vfs, _proc_macro) =
++            load_workspace(workspace, &cargo_config, &load_cargo_config)?;
 +        let db = host.raw_database();
 +        let analysis = host.analysis();
 +
 +        let si = StaticIndex::compute(&analysis);
 +
 +        let mut lsif = LsifManager::new(&analysis, db, &vfs);
 +        lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData {
 +            version: String::from("0.5.0"),
 +            project_root: lsp_types::Url::from_file_path(path).unwrap(),
 +            position_encoding: lsif::Encoding::Utf16,
 +            tool_info: Some(lsp_types::lsif::ToolInfo {
 +                name: "rust-analyzer".to_string(),
 +                args: vec![],
 +                version: Some(version().to_string()),
 +            }),
 +        }));
 +        for file in si.files {
 +            lsif.add_file(file);
 +        }
 +        for (id, token) in si.tokens.iter() {
 +            lsif.add_token(id, token);
 +        }
 +        eprintln!("Generating LSIF finished in {:?}", now.elapsed());
 +        Ok(())
 +    }
 +}
index 65cc993c45e7145f8936532d002ba8133b7d6105,0000000000000000000000000000000000000000..05c16bb39e3515960130a7b4d19307ee083be650
mode 100644,000000..100644
--- /dev/null
@@@ -1,448 -1,0 +1,448 @@@
-         let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?;
 +//! SCIP generator
 +
 +use std::{
 +    collections::{HashMap, HashSet},
 +    time::Instant,
 +};
 +
 +use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
 +use hir::Name;
 +use ide::{
 +    LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange,
 +    TokenId,
 +};
 +use ide_db::LineIndexDatabase;
 +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 +use scip::types as scip_types;
 +use std::env;
 +
 +use crate::cli::{
 +    flags,
 +    load_cargo::{load_workspace, LoadCargoConfig},
 +    Result,
 +};
 +
 +impl flags::Scip {
 +    pub fn run(self) -> Result<()> {
 +        eprintln!("Generating SCIP start...");
 +        let now = Instant::now();
 +        let cargo_config = CargoConfig::default();
 +
 +        let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s));
 +        let load_cargo_config = LoadCargoConfig {
 +            load_out_dirs_from_check: true,
 +            with_proc_macro: true,
 +            prefill_caches: true,
 +        };
 +        let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path));
 +        let rootpath = path.normalize();
 +        let manifest = ProjectManifest::discover_single(&path)?;
 +
 +        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 +
++        let (host, vfs, _) = load_workspace(workspace, &cargo_config, &load_cargo_config)?;
 +        let db = host.raw_database();
 +        let analysis = host.analysis();
 +
 +        let si = StaticIndex::compute(&analysis);
 +
 +        let mut index = scip_types::Index {
 +            metadata: Some(scip_types::Metadata {
 +                version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
 +                tool_info: Some(scip_types::ToolInfo {
 +                    name: "rust-analyzer".to_owned(),
 +                    version: "0.1".to_owned(),
 +                    arguments: vec![],
 +                    ..Default::default()
 +                })
 +                .into(),
 +                project_root: format!(
 +                    "file://{}",
 +                    path.normalize()
 +                        .as_os_str()
 +                        .to_str()
 +                        .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
 +                        .to_string()
 +                ),
 +                text_document_encoding: scip_types::TextEncoding::UTF8.into(),
 +                ..Default::default()
 +            })
 +            .into(),
 +            ..Default::default()
 +        };
 +
 +        let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
 +        let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
 +
 +        for file in si.files {
 +            let mut local_count = 0;
 +            let mut new_local_symbol = || {
 +                let new_symbol = scip::types::Symbol::new_local(local_count);
 +                local_count += 1;
 +
 +                new_symbol
 +            };
 +
 +            let StaticIndexedFile { file_id, tokens, .. } = file;
 +            let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) {
 +                Some(relative_path) => relative_path,
 +                None => continue,
 +            };
 +
 +            let line_index = LineIndex {
 +                index: db.line_index(file_id),
 +                encoding: OffsetEncoding::Utf8,
 +                endings: LineEndings::Unix,
 +            };
 +
 +            let mut doc = scip_types::Document {
 +                relative_path,
 +                language: "rust".to_string(),
 +                ..Default::default()
 +            };
 +
 +            tokens.into_iter().for_each(|(range, id)| {
 +                let token = si.tokens.get(id).unwrap();
 +
 +                let mut occurrence = scip_types::Occurrence::default();
 +                occurrence.range = text_range_to_scip_range(&line_index, range);
 +                occurrence.symbol = match tokens_to_symbol.get(&id) {
 +                    Some(symbol) => symbol.clone(),
 +                    None => {
 +                        let symbol = match &token.moniker {
 +                            Some(moniker) => moniker_to_symbol(&moniker),
 +                            None => new_local_symbol(),
 +                        };
 +
 +                        let symbol = scip::symbol::format_symbol(symbol);
 +                        tokens_to_symbol.insert(id, symbol.clone());
 +                        symbol
 +                    }
 +                };
 +
 +                if let Some(def) = token.definition {
 +                    if def.range == range {
 +                        occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
 +                    }
 +
 +                    if !symbols_emitted.contains(&id) {
 +                        symbols_emitted.insert(id);
 +
 +                        let mut symbol_info = scip_types::SymbolInformation::default();
 +                        symbol_info.symbol = occurrence.symbol.clone();
 +                        if let Some(hover) = &token.hover {
 +                            if !hover.markup.as_str().is_empty() {
 +                                symbol_info.documentation = vec![hover.markup.as_str().to_string()];
 +                            }
 +                        }
 +
 +                        doc.symbols.push(symbol_info)
 +                    }
 +                }
 +
 +                doc.occurrences.push(occurrence);
 +            });
 +
 +            if doc.occurrences.is_empty() {
 +                continue;
 +            }
 +
 +            index.documents.push(doc);
 +        }
 +
 +        scip::write_message_to_file("index.scip", index)
 +            .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?;
 +
 +        eprintln!("Generating SCIP finished {:?}", now.elapsed());
 +        Ok(())
 +    }
 +}
 +
 +fn get_relative_filepath(
 +    vfs: &vfs::Vfs,
 +    rootpath: &vfs::AbsPathBuf,
 +    file_id: ide::FileId,
 +) -> Option<String> {
 +    Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string())
 +}
 +
 +// SCIP Ranges have a (very large) optimization that ranges if they are on the same line
 +// only encode as a vector of [start_line, start_col, end_col].
 +//
 +// This transforms a line index into the optimized SCIP Range.
 +fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec<i32> {
 +    let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start());
 +    let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end());
 +
 +    if start_line == end_line {
 +        vec![start_line as i32, start_col as i32, end_col as i32]
 +    } else {
 +        vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32]
 +    }
 +}
 +
 +fn new_descriptor_str(
 +    name: &str,
 +    suffix: scip_types::descriptor::Suffix,
 +) -> scip_types::Descriptor {
 +    scip_types::Descriptor {
 +        name: name.to_string(),
 +        disambiguator: "".to_string(),
 +        suffix: suffix.into(),
 +        ..Default::default()
 +    }
 +}
 +
 +fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor {
 +    let mut name = name.to_string();
 +    if name.contains("'") {
 +        name = format!("`{}`", name);
 +    }
 +
 +    new_descriptor_str(name.as_str(), suffix)
 +}
 +
 +/// Loosely based on `def_to_moniker`
 +///
 +/// Only returns a Symbol when it's a non-local symbol.
 +///     So if the visibility isn't outside of a document, then it will return None
 +fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
 +    use scip_types::descriptor::Suffix::*;
 +
 +    let package_name = moniker.package_information.name.clone();
 +    let version = moniker.package_information.version.clone();
 +    let descriptors = moniker
 +        .identifier
 +        .description
 +        .iter()
 +        .map(|desc| {
 +            new_descriptor(
 +                desc.name.clone(),
 +                match desc.desc {
 +                    MonikerDescriptorKind::Namespace => Namespace,
 +                    MonikerDescriptorKind::Type => Type,
 +                    MonikerDescriptorKind::Term => Term,
 +                    MonikerDescriptorKind::Method => Method,
 +                    MonikerDescriptorKind::TypeParameter => TypeParameter,
 +                    MonikerDescriptorKind::Parameter => Parameter,
 +                    MonikerDescriptorKind::Macro => Macro,
 +                    MonikerDescriptorKind::Meta => Meta,
 +                },
 +            )
 +        })
 +        .collect();
 +
 +    scip_types::Symbol {
 +        scheme: "rust-analyzer".into(),
 +        package: Some(scip_types::Package {
 +            manager: "cargo".to_string(),
 +            name: package_name,
 +            version,
 +            ..Default::default()
 +        })
 +        .into(),
 +        descriptors,
 +        ..Default::default()
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +    use hir::Semantics;
 +    use ide::{AnalysisHost, FilePosition};
 +    use ide_db::defs::IdentClass;
 +    use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token};
 +    use scip::symbol::format_symbol;
 +    use syntax::SyntaxKind::*;
 +    use syntax::{AstNode, T};
 +
 +    fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
 +        let mut host = AnalysisHost::default();
 +        let change_fixture = ChangeFixture::parse(ra_fixture);
 +        host.raw_database_mut().apply_change(change_fixture.change);
 +        let (file_id, range_or_offset) =
 +            change_fixture.file_position.expect("expected a marker ($0)");
 +        let offset = range_or_offset.expect_offset();
 +        (host, FilePosition { file_id, offset })
 +    }
 +
 +    /// If expected == "", then assert that there are no symbols (this is basically local symbol)
 +    #[track_caller]
 +    fn check_symbol(ra_fixture: &str, expected: &str) {
 +        let (host, position) = position(ra_fixture);
 +
 +        let FilePosition { file_id, offset } = position;
 +
 +        let db = host.raw_database();
 +        let sema = &Semantics::new(db);
 +        let file = sema.parse(file_id).syntax().clone();
 +        let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
 +            IDENT
 +            | INT_NUMBER
 +            | LIFETIME_IDENT
 +            | T![self]
 +            | T![super]
 +            | T![crate]
 +            | T![Self]
 +            | COMMENT => 2,
 +            kind if kind.is_trivia() => 0,
 +            _ => 1,
 +        })
 +        .expect("OK OK");
 +
 +        let navs = sema
 +            .descend_into_macros(original_token.clone())
 +            .into_iter()
 +            .filter_map(|token| {
 +                IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
 +                    it.into_iter().flat_map(|def| {
 +                        let module = def.module(db).unwrap();
 +                        let current_crate = module.krate();
 +
 +                        match MonikerResult::from_def(sema.db, def, current_crate) {
 +                            Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)),
 +                            None => None,
 +                        }
 +                    })
 +                })
 +            })
 +            .flatten()
 +            .collect::<Vec<_>>();
 +
 +        if expected == "" {
 +            assert_eq!(0, navs.len(), "must have no symbols {:?}", navs);
 +            return;
 +        }
 +
 +        assert_eq!(1, navs.len(), "must have one symbol {:?}", navs);
 +
 +        let res = navs.get(0).unwrap();
 +        let formatted = format_symbol(res.clone());
 +        assert_eq!(formatted, expected);
 +    }
 +
 +    #[test]
 +    fn basic() {
 +        check_symbol(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo::example_mod::func;
 +fn main() {
 +    func$0();
 +}
 +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +pub mod example_mod {
 +    pub fn func() {}
 +}
 +"#,
 +            "rust-analyzer cargo foo 0.1.0 example_mod/func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait() {
 +        check_symbol(
 +            r#"
 +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +pub mod module {
 +    pub trait MyTrait {
 +        pub fn func$0() {}
 +    }
 +}
 +"#,
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_constant() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            const MY_CONST$0: u8;
 +        }
 +    }
 +    "#,
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_type() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            type MyType$0;
 +        }
 +    }
 +    "#,
 +            // "foo::module::MyTrait::MyType",
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_impl_function() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            pub fn func() {}
 +        }
 +
 +        struct MyStruct {}
 +
 +        impl MyTrait for MyStruct {
 +            pub fn func$0() {}
 +        }
 +    }
 +    "#,
 +            // "foo::module::MyStruct::MyTrait::func",
 +            "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_field() {
 +        check_symbol(
 +            r#"
 +    //- /lib.rs crate:main deps:foo
 +    use foo::St;
 +    fn main() {
 +        let x = St { a$0: 2 };
 +    }
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub struct St {
 +        pub a: i32,
 +    }
 +    "#,
 +            "rust-analyzer cargo foo 0.1.0 St#a.",
 +        );
 +    }
 +
 +    #[test]
 +    fn local_symbol_for_local() {
 +        check_symbol(
 +            r#"
 +    //- /lib.rs crate:main deps:foo
 +    use foo::module::func;
 +    fn main() {
 +        func();
 +    }
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub fn func() {
 +            let x$0 = 2;
 +        }
 +    }
 +    "#,
 +            "",
 +        );
 +    }
 +}
index 54dcb42d99c789ea142e8873dee91d246114692e,0000000000000000000000000000000000000000..9ef79e6f381208c0a09dbcafbef2518751fc1ee5
mode 100644,000000..100644
--- /dev/null
@@@ -1,2034 -1,0 +1,2097 @@@
 +//! Config used by the language server.
 +//!
 +//! We currently get this config from `initialize` LSP request, which is not the
 +//! best way to do it, but was the simplest thing we could implement.
 +//!
 +//! Of particular interest is the `feature_flags` hash map: while other fields
 +//! configure the server itself, feature flags are passed into analysis, and
 +//! tweak things like automatic insertion of `()` in completions.
 +
 +use std::{ffi::OsString, fmt, iter, path::PathBuf};
 +
 +use flycheck::FlycheckConfig;
 +use ide::{
 +    AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
 +    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
 +    JoinLinesConfig, Snippet, SnippetScope,
 +};
 +use ide_db::{
 +    imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 +    SnippetCap,
 +};
 +use itertools::Itertools;
 +use lsp_types::{ClientCapabilities, MarkupKind};
 +use project_model::{
 +    CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource, UnsetTestCrates,
 +};
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use serde::{de::DeserializeOwned, Deserialize};
 +use vfs::AbsPathBuf;
 +
 +use crate::{
 +    caps::completion_item_edit_resolve,
 +    diagnostics::DiagnosticsMapConfig,
 +    line_index::OffsetEncoding,
 +    lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
 +};
 +
 +mod patch_old_style;
 +
 +// Conventions for configuration keys to preserve maximal extendability without breakage:
 +//  - Toggles (be it binary true/false or with more options in-between) should almost always suffix as `_enable`
 +//    This has the benefit of namespaces being extensible, and if the suffix doesn't fit later it can be changed without breakage.
 +//  - In general be wary of using the namespace of something verbatim, it prevents us from adding subkeys in the future
 +//  - Don't use abbreviations unless really necessary
 +//  - foo_command = overrides the subcommand, foo_overrideCommand allows full overwriting, extra args only applies for foo_command
 +
 +// Defines the server-side configuration of the rust-analyzer. We generate
 +// *parts* of VS Code's `package.json` config from this. Run `cargo test` to
 +// re-generate that file.
 +//
 +// However, editor specific config, which the server doesn't know about, should
 +// be specified directly in `package.json`.
 +//
 +// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
 +// parsing the old name.
 +config_data! {
 +    struct ConfigData {
 +        /// Placeholder expression to use for missing expressions in assists.
 +        assist_expressionFillDefault: ExprFillDefaultDef              = "\"todo\"",
 +
 +        /// Warm up caches on project load.
 +        cachePriming_enable: bool = "true",
 +        /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
 +        cachePriming_numThreads: ParallelCachePrimingNumThreads = "0",
 +
 +        /// Automatically refresh project info via `cargo metadata` on
 +        /// `Cargo.toml` or `.cargo/config.toml` changes.
 +        cargo_autoreload: bool           = "true",
 +        /// Run build scripts (`build.rs`) for more precise code analysis.
 +        cargo_buildScripts_enable: bool  = "true",
 +        /// Override the command rust-analyzer uses to run build scripts and
 +        /// build procedural macros. The command is required to output json
 +        /// and should therefore include `--message-format=json` or a similar
 +        /// option.
 +        ///
 +        /// By default, a cargo invocation will be constructed for the configured
 +        /// targets and features, with the following base command line:
 +        ///
 +        /// ```bash
 +        /// cargo check --quiet --workspace --message-format=json --all-targets
 +        /// ```
 +        /// .
 +        cargo_buildScripts_overrideCommand: Option<Vec<String>> = "null",
 +        /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
 +        /// avoid checking unnecessary things.
 +        cargo_buildScripts_useRustcWrapper: bool = "true",
++        /// Extra environment variables that will be set when running cargo, rustc
++        /// or other commands within the workspace. Useful for setting RUSTFLAGS.
++        cargo_extraEnv: FxHashMap<String, String> = "{}",
 +        /// List of features to activate.
 +        ///
 +        /// Set this to `"all"` to pass `--all-features` to cargo.
 +        cargo_features: CargoFeatures      = "[]",
 +        /// Whether to pass `--no-default-features` to cargo.
 +        cargo_noDefaultFeatures: bool    = "false",
 +        /// Internal config for debugging, disables loading of sysroot crates.
 +        cargo_noSysroot: bool            = "false",
 +        /// Compilation target override (target triple).
 +        cargo_target: Option<String>     = "null",
 +        /// Unsets `#[cfg(test)]` for the specified crates.
 +        cargo_unsetTest: Vec<String>   = "[\"core\"]",
 +
 +        /// Check all targets and tests (`--all-targets`).
 +        checkOnSave_allTargets: bool                     = "true",
 +        /// Cargo command to use for `cargo check`.
 +        checkOnSave_command: String                      = "\"check\"",
 +        /// Run specified `cargo check` command for diagnostics on save.
 +        checkOnSave_enable: bool                         = "true",
 +        /// Extra arguments for `cargo check`.
 +        checkOnSave_extraArgs: Vec<String>               = "[]",
++        /// Extra environment variables that will be set when running `cargo check`.
++        checkOnSave_extraEnv: FxHashMap<String, String> = "{}",
 +        /// List of features to activate. Defaults to
 +        /// `#rust-analyzer.cargo.features#`.
 +        ///
 +        /// Set to `"all"` to pass `--all-features` to Cargo.
 +        checkOnSave_features: Option<CargoFeatures>      = "null",
 +        /// Whether to pass `--no-default-features` to Cargo. Defaults to
 +        /// `#rust-analyzer.cargo.noDefaultFeatures#`.
 +        checkOnSave_noDefaultFeatures: Option<bool>      = "null",
 +        /// Override the command rust-analyzer uses instead of `cargo check` for
 +        /// diagnostics on save. The command is required to output json and
 +        /// should therefor include `--message-format=json` or a similar option.
 +        ///
 +        /// If you're changing this because you're using some tool wrapping
 +        /// Cargo, you might also want to change
 +        /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
 +        ///
 +        /// If there are multiple linked projects, this command is invoked for
 +        /// each of them, with the working directory being the project root
 +        /// (i.e., the folder containing the `Cargo.toml`).
 +        ///
 +        /// An example command would be:
 +        ///
 +        /// ```bash
 +        /// cargo check --workspace --message-format=json --all-targets
 +        /// ```
 +        /// .
 +        checkOnSave_overrideCommand: Option<Vec<String>> = "null",
 +        /// Check for a specific target. Defaults to
 +        /// `#rust-analyzer.cargo.target#`.
 +        checkOnSave_target: Option<String>               = "null",
 +
 +        /// Toggles the additional completions that automatically add imports when completed.
 +        /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 +        completion_autoimport_enable: bool       = "true",
 +        /// Toggles the additional completions that automatically show method calls and field accesses
 +        /// with `self` prefixed to them when inside a method.
 +        completion_autoself_enable: bool        = "true",
 +        /// Whether to add parenthesis and argument snippets when completing function.
 +        completion_callable_snippets: CallableCompletionDef  = "\"fill_arguments\"",
 +        /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 +        completion_postfix_enable: bool         = "true",
 +        /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
 +        completion_privateEditable_enable: bool = "false",
 +        /// Custom completion snippets.
 +        // NOTE: Keep this list in sync with the feature docs of user snippets.
 +        completion_snippets_custom: FxHashMap<String, SnippetDef> = r#"{
 +            "Arc::new": {
 +                "postfix": "arc",
 +                "body": "Arc::new(${receiver})",
 +                "requires": "std::sync::Arc",
 +                "description": "Put the expression into an `Arc`",
 +                "scope": "expr"
 +            },
 +            "Rc::new": {
 +                "postfix": "rc",
 +                "body": "Rc::new(${receiver})",
 +                "requires": "std::rc::Rc",
 +                "description": "Put the expression into an `Rc`",
 +                "scope": "expr"
 +            },
 +            "Box::pin": {
 +                "postfix": "pinbox",
 +                "body": "Box::pin(${receiver})",
 +                "requires": "std::boxed::Box",
 +                "description": "Put the expression into a pinned `Box`",
 +                "scope": "expr"
 +            },
 +            "Ok": {
 +                "postfix": "ok",
 +                "body": "Ok(${receiver})",
 +                "description": "Wrap the expression in a `Result::Ok`",
 +                "scope": "expr"
 +            },
 +            "Err": {
 +                "postfix": "err",
 +                "body": "Err(${receiver})",
 +                "description": "Wrap the expression in a `Result::Err`",
 +                "scope": "expr"
 +            },
 +            "Some": {
 +                "postfix": "some",
 +                "body": "Some(${receiver})",
 +                "description": "Wrap the expression in an `Option::Some`",
 +                "scope": "expr"
 +            }
 +        }"#,
 +
 +        /// List of rust-analyzer diagnostics to disable.
 +        diagnostics_disabled: FxHashSet<String> = "[]",
 +        /// Whether to show native rust-analyzer diagnostics.
 +        diagnostics_enable: bool                = "true",
 +        /// Whether to show experimental rust-analyzer diagnostics that might
 +        /// have more false positives than usual.
 +        diagnostics_experimental_enable: bool    = "false",
 +        /// 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<String, String> = "{}",
 +        /// List of warnings that should be displayed with hint severity.
 +        ///
 +        /// The warnings will be indicated by faded text or three dots in code
 +        /// and will not show up in the `Problems Panel`.
 +        diagnostics_warningsAsHint: Vec<String> = "[]",
 +        /// List of warnings that should be displayed with info severity.
 +        ///
 +        /// The warnings will be indicated by a blue squiggly underline in code
 +        /// and a blue icon in the `Problems Panel`.
 +        diagnostics_warningsAsInfo: Vec<String> = "[]",
 +
 +        /// These directories will be ignored by rust-analyzer. They are
 +        /// relative to the workspace root, and globs are not supported. You may
 +        /// also need to add the folders to Code's `files.watcherExclude`.
 +        files_excludeDirs: Vec<PathBuf> = "[]",
 +        /// Controls file watching implementation.
 +        files_watcher: FilesWatcherDef = "\"client\"",
-                 FlycheckConfig::CustomCommand { command, args }
 +        /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
 +        highlightRelated_breakPoints_enable: bool = "true",
 +        /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
 +        highlightRelated_exitPoints_enable: bool = "true",
 +        /// Enables highlighting of related references while the cursor is on any identifier.
 +        highlightRelated_references_enable: bool = "true",
 +        /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
 +        highlightRelated_yieldPoints_enable: bool = "true",
 +
 +        /// Whether to show `Debug` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_debug_enable: bool           = "true",
 +        /// Whether to show HoverActions in Rust files.
 +        hover_actions_enable: bool          = "true",
 +        /// Whether to show `Go to Type Definition` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_gotoTypeDef_enable: bool     = "true",
 +        /// Whether to show `Implementations` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_implementations_enable: bool = "true",
 +        /// Whether to show `References` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_references_enable: bool      = "false",
 +        /// Whether to show `Run` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_run_enable: bool             = "true",
 +
 +        /// Whether to show documentation on hover.
 +        hover_documentation_enable: bool           = "true",
 +        /// Whether to show keyword hover popups. Only applies when
 +        /// `#rust-analyzer.hover.documentation.enable#` is set.
 +        hover_documentation_keywords_enable: bool  = "true",
 +        /// Use markdown syntax for links in hover.
 +        hover_links_enable: bool = "true",
 +
 +        /// 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.
 +        imports_granularity_group: ImportGranularityDef  = "\"crate\"",
 +        /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
 +        imports_group_enable: bool                           = "true",
 +        /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 +        imports_merge_glob: bool           = "true",
++        /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
++        imports_prefer_no_std: bool                     = "false",
 +        /// The path structure for newly inserted paths to use.
 +        imports_prefix: ImportPrefixDef               = "\"plain\"",
 +
 +        /// Whether to show inlay type hints for binding modes.
 +        inlayHints_bindingModeHints_enable: bool                   = "false",
 +        /// Whether to show inlay type hints for method chains.
 +        inlayHints_chainingHints_enable: bool                      = "true",
 +        /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
 +        inlayHints_closingBraceHints_enable: bool                  = "true",
 +        /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
 +        /// to always show them).
 +        inlayHints_closingBraceHints_minLines: usize               = "25",
 +        /// Whether to show inlay type hints for return types of closures.
 +        inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef  = "\"never\"",
 +        /// Whether to show inlay type hints for elided lifetimes in function signatures.
 +        inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
 +        /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
 +        inlayHints_lifetimeElisionHints_useParameterNames: bool    = "false",
 +        /// Maximum length for inlay hints. Set to null to have an unlimited length.
 +        inlayHints_maxLength: Option<usize>                        = "25",
 +        /// Whether to show function parameter name inlay hints at the call
 +        /// site.
 +        inlayHints_parameterHints_enable: bool                     = "true",
 +        /// Whether to show inlay type hints for compiler inserted reborrows.
 +        inlayHints_reborrowHints_enable: ReborrowHintsDef          = "\"never\"",
 +        /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
 +        inlayHints_renderColons: bool                              = "true",
 +        /// Whether to show inlay type hints for variables.
 +        inlayHints_typeHints_enable: bool                          = "true",
 +        /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
 +        /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
 +        inlayHints_typeHints_hideClosureInitialization: bool       = "false",
 +        /// Whether to hide inlay type hints for constructors.
 +        inlayHints_typeHints_hideNamedConstructor: bool            = "false",
 +
 +        /// Join lines merges consecutive declaration and initialization of an assignment.
 +        joinLines_joinAssignments: bool = "true",
 +        /// Join lines inserts else between consecutive ifs.
 +        joinLines_joinElseIf: bool = "true",
 +        /// Join lines removes trailing commas.
 +        joinLines_removeTrailingComma: bool = "true",
 +        /// Join lines unwraps trivial blocks.
 +        joinLines_unwrapTrivialBlock: bool = "true",
 +
++
 +        /// Whether to show `Debug` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_debug_enable: bool            = "true",
 +        /// Whether to show CodeLens in Rust files.
 +        lens_enable: bool           = "true",
 +        /// Internal config: use custom client-side commands even when the
 +        /// client doesn't set the corresponding capability.
 +        lens_forceCustomCommands: bool = "true",
 +        /// Whether to show `Implementations` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_implementations_enable: bool  = "true",
++        /// Where to render annotations.
++        lens_location: AnnotationLocation = "\"above_name\"",
 +        /// Whether to show `References` lens for Struct, Enum, and Union.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_adt_enable: bool = "false",
 +        /// Whether to show `References` lens for Enum Variants.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_enumVariant_enable: bool = "false",
 +        /// Whether to show `Method References` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_references_method_enable: bool = "false",
 +        /// Whether to show `References` lens for Trait.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_trait_enable: bool = "false",
 +        /// Whether to show `Run` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_run_enable: bool              = "true",
 +
 +        /// Disable project auto-discovery in favor of explicitly specified set
 +        /// of projects.
 +        ///
 +        /// Elements must be paths pointing to `Cargo.toml`,
 +        /// `rust-project.json`, or JSON objects in `rust-project.json` format.
 +        linkedProjects: Vec<ManifestOrProjectJson> = "[]",
 +
 +        /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
 +        lru_capacity: Option<usize>                 = "null",
 +
 +        /// Whether to show `can't find Cargo.toml` error message.
 +        notifications_cargoTomlNotFound: bool      = "true",
 +
 +        /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
 +        procMacro_attributes_enable: bool = "true",
 +        /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
 +        procMacro_enable: bool                     = "true",
 +        /// These proc-macros will be ignored when trying to expand them.
 +        ///
 +        /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
 +        procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>>          = "{}",
 +        /// Internal config, path to proc-macro server executable (typically,
 +        /// this is rust-analyzer itself, but we override this in tests).
 +        procMacro_server: Option<PathBuf>          = "null",
 +
++        /// Exclude imports from find-all-references.
++        references_excludeImports: bool = "false",
++
 +        /// Command to be executed instead of 'cargo' for runnables.
 +        runnables_command: Option<String> = "null",
 +        /// Additional arguments to be passed to cargo for runnables such as
 +        /// tests or binaries. For example, it may be `--release`.
 +        runnables_extraArgs: Vec<String>   = "[]",
 +
 +        /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
 +        /// projects, or "discover" to try to automatically find it if the `rustc-dev` component
 +        /// is installed.
 +        ///
 +        /// Any project which uses rust-analyzer with the rustcPrivate
 +        /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
 +        ///
 +        /// This option does not take effect until rust-analyzer is restarted.
 +        rustc_source: Option<String> = "null",
 +
 +        /// Additional arguments to `rustfmt`.
 +        rustfmt_extraArgs: Vec<String>               = "[]",
 +        /// Advanced option, fully override the command rust-analyzer uses for
 +        /// formatting.
 +        rustfmt_overrideCommand: Option<Vec<String>> = "null",
 +        /// Enables the use of rustfmt's unstable range formatting command for the
 +        /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
 +        /// available on a nightly build.
 +        rustfmt_rangeFormatting_enable: bool = "false",
 +
 +        /// Inject additional highlighting into doc comments.
 +        ///
 +        /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
 +        /// doc links.
 +        semanticHighlighting_doc_comment_inject_enable: bool = "true",
 +        /// Use semantic tokens for operators.
 +        ///
 +        /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
 +        /// they are tagged with modifiers.
 +        semanticHighlighting_operator_enable: bool = "true",
 +        /// Use specialized semantic tokens for operators.
 +        ///
 +        /// When enabled, rust-analyzer will emit special token types for operator tokens instead
 +        /// of the generic `operator` token type.
 +        semanticHighlighting_operator_specialization_enable: bool = "false",
 +        /// Use semantic tokens for punctuations.
 +        ///
 +        /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
 +        /// they are tagged with modifiers or have a special role.
 +        semanticHighlighting_punctuation_enable: bool = "false",
 +        /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
 +        /// calls.
 +        semanticHighlighting_punctuation_separate_macro_bang: bool = "false",
 +        /// Use specialized semantic tokens for punctuations.
 +        ///
 +        /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
 +        /// of the generic `punctuation` token type.
 +        semanticHighlighting_punctuation_specialization_enable: bool = "false",
 +        /// Use semantic tokens for strings.
 +        ///
 +        /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
 +        /// By disabling semantic tokens for strings, other grammars can be used to highlight
 +        /// their contents.
 +        semanticHighlighting_strings_enable: bool = "true",
 +
 +        /// Show full signature of the callable. Only shows parameters if disabled.
 +        signatureInfo_detail: SignatureDetail                           = "\"full\"",
 +        /// Show documentation.
 +        signatureInfo_documentation_enable: bool                       = "true",
 +
 +        /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
 +        typing_autoClosingAngleBrackets_enable: bool = "false",
 +
 +        /// Workspace symbol search kind.
 +        workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = "\"only_types\"",
 +        /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
 +        /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
 +        /// Other clients requires all results upfront and might require a higher limit.
 +        workspace_symbol_search_limit: usize = "128",
 +        /// Workspace symbol search scope.
 +        workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = "\"workspace\"",
 +    }
 +}
 +
 +impl Default for ConfigData {
 +    fn default() -> Self {
 +        ConfigData::from_json(serde_json::Value::Null, &mut Vec::new())
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct Config {
 +    pub discovered_projects: Option<Vec<ProjectManifest>>,
 +    caps: lsp_types::ClientCapabilities,
 +    root_path: AbsPathBuf,
 +    data: ConfigData,
 +    detached_files: Vec<AbsPathBuf>,
 +    snippets: Vec<Snippet>,
 +}
 +
 +type ParallelCachePrimingNumThreads = u8;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum LinkedProject {
 +    ProjectManifest(ProjectManifest),
 +    InlineJsonProject(ProjectJson),
 +}
 +
 +impl From<ProjectManifest> for LinkedProject {
 +    fn from(v: ProjectManifest) -> Self {
 +        LinkedProject::ProjectManifest(v)
 +    }
 +}
 +
 +impl From<ProjectJson> for LinkedProject {
 +    fn from(v: ProjectJson) -> Self {
 +        LinkedProject::InlineJsonProject(v)
 +    }
 +}
 +
 +pub struct CallInfoConfig {
 +    pub params_only: bool,
 +    pub docs: bool,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct LensConfig {
 +    // runnables
 +    pub run: bool,
 +    pub debug: bool,
 +
 +    // implementations
 +    pub implementations: bool,
 +
 +    // references
 +    pub method_refs: bool,
 +    pub refs_adt: bool,   // for Struct, Enum, Union and Trait
 +    pub refs_trait: bool, // for Struct, Enum, Union and Trait
 +    pub enum_variant_refs: bool,
++
++    // annotations
++    pub location: AnnotationLocation,
++}
++
++#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
++#[serde(rename_all = "snake_case")]
++pub enum AnnotationLocation {
++    AboveName,
++    AboveWholeItem,
++}
++
++impl From<AnnotationLocation> for ide::AnnotationLocation {
++    fn from(location: AnnotationLocation) -> Self {
++        match location {
++            AnnotationLocation::AboveName => ide::AnnotationLocation::AboveName,
++            AnnotationLocation::AboveWholeItem => ide::AnnotationLocation::AboveWholeItem,
++        }
++    }
 +}
 +
 +impl LensConfig {
 +    pub fn any(&self) -> bool {
 +        self.run
 +            || self.debug
 +            || self.implementations
 +            || self.method_refs
 +            || self.refs_adt
 +            || self.refs_trait
 +            || self.enum_variant_refs
 +    }
 +
 +    pub fn none(&self) -> bool {
 +        !self.any()
 +    }
 +
 +    pub fn runnable(&self) -> bool {
 +        self.run || self.debug
 +    }
 +
 +    pub fn references(&self) -> bool {
 +        self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct HoverActionsConfig {
 +    pub implementations: bool,
 +    pub references: bool,
 +    pub run: bool,
 +    pub debug: bool,
 +    pub goto_type_def: bool,
 +}
 +
 +impl HoverActionsConfig {
 +    pub const NO_ACTIONS: Self = Self {
 +        implementations: false,
 +        references: false,
 +        run: false,
 +        debug: false,
 +        goto_type_def: false,
 +    };
 +
 +    pub fn any(&self) -> bool {
 +        self.implementations || self.references || self.runnable() || self.goto_type_def
 +    }
 +
 +    pub fn none(&self) -> bool {
 +        !self.any()
 +    }
 +
 +    pub fn runnable(&self) -> bool {
 +        self.run || self.debug
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct FilesConfig {
 +    pub watcher: FilesWatcher,
 +    pub exclude: Vec<AbsPathBuf>,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum FilesWatcher {
 +    Client,
 +    Server,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct NotificationsConfig {
 +    pub cargo_toml_not_found: bool,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum RustfmtConfig {
 +    Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool },
 +    CustomCommand { command: String, args: Vec<String> },
 +}
 +
 +/// Configuration for runnable items, such as `main` function or tests.
 +#[derive(Debug, Clone)]
 +pub struct RunnablesConfig {
 +    /// Custom command to be executed instead of `cargo` for runnables.
 +    pub override_cargo: Option<String>,
 +    /// Additional arguments for the `cargo`, e.g. `--release`.
 +    pub cargo_extra_args: Vec<String>,
 +}
 +
 +/// Configuration for workspace symbol search requests.
 +#[derive(Debug, Clone)]
 +pub struct WorkspaceSymbolConfig {
 +    /// In what scope should the symbol be searched in.
 +    pub search_scope: WorkspaceSymbolSearchScope,
 +    /// What kind of symbol is being searched for.
 +    pub search_kind: WorkspaceSymbolSearchKind,
 +    /// How many items are returned at most.
 +    pub search_limit: usize,
 +}
 +
 +pub struct ClientCommandsConfig {
 +    pub run_single: bool,
 +    pub debug_single: bool,
 +    pub show_reference: bool,
 +    pub goto_location: bool,
 +    pub trigger_parameter_hints: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct ConfigUpdateError {
 +    errors: Vec<(String, serde_json::Error)>,
 +}
 +
 +impl fmt::Display for ConfigUpdateError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let errors = self.errors.iter().format_with("\n", |(key, e), f| {
 +            f(key)?;
 +            f(&": ")?;
 +            f(e)
 +        });
 +        write!(
 +            f,
 +            "rust-analyzer found {} invalid config value{}:\n{}",
 +            self.errors.len(),
 +            if self.errors.len() == 1 { "" } else { "s" },
 +            errors
 +        )
 +    }
 +}
 +
 +impl Config {
 +    pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
 +        Config {
 +            caps,
 +            data: ConfigData::default(),
 +            detached_files: Vec::new(),
 +            discovered_projects: None,
 +            root_path,
 +            snippets: Default::default(),
 +        }
 +    }
 +
 +    pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> {
 +        tracing::info!("updating config from JSON: {:#}", json);
 +        if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
 +            return Ok(());
 +        }
 +        let mut errors = Vec::new();
 +        self.detached_files =
 +            get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
 +                .into_iter()
 +                .map(AbsPathBuf::assert)
 +                .collect();
 +        patch_old_style::patch_json_for_outdated_configs(&mut json);
 +        self.data = ConfigData::from_json(json, &mut errors);
 +        tracing::debug!("deserialized config data: {:#?}", self.data);
 +        self.snippets.clear();
 +        for (name, def) in self.data.completion_snippets_custom.iter() {
 +            if def.prefix.is_empty() && def.postfix.is_empty() {
 +                continue;
 +            }
 +            let scope = match def.scope {
 +                SnippetScopeDef::Expr => SnippetScope::Expr,
 +                SnippetScopeDef::Type => SnippetScope::Type,
 +                SnippetScopeDef::Item => SnippetScope::Item,
 +            };
 +            match Snippet::new(
 +                &def.prefix,
 +                &def.postfix,
 +                &def.body,
 +                def.description.as_ref().unwrap_or(name),
 +                &def.requires,
 +                scope,
 +            ) {
 +                Some(snippet) => self.snippets.push(snippet),
 +                None => errors.push((
 +                    format!("snippet {name} is invalid"),
 +                    <serde_json::Error as serde::de::Error>::custom(
 +                        "snippet path is invalid or triggers are missing",
 +                    ),
 +                )),
 +            }
 +        }
 +
 +        self.validate(&mut errors);
 +
 +        if errors.is_empty() {
 +            Ok(())
 +        } else {
 +            Err(ConfigUpdateError { errors })
 +        }
 +    }
 +
 +    fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) {
 +        use serde::de::Error;
 +        if self.data.checkOnSave_command.is_empty() {
 +            error_sink.push((
 +                "/checkOnSave/command".to_string(),
 +                serde_json::Error::custom("expected a non-empty string"),
 +            ));
 +        }
 +    }
 +
 +    pub fn json_schema() -> serde_json::Value {
 +        ConfigData::json_schema()
 +    }
 +
 +    pub fn root_path(&self) -> &AbsPathBuf {
 +        &self.root_path
 +    }
 +
 +    pub fn caps(&self) -> &lsp_types::ClientCapabilities {
 +        &self.caps
 +    }
 +
 +    pub fn detached_files(&self) -> &[AbsPathBuf] {
 +        &self.detached_files
 +    }
 +}
 +
 +macro_rules! try_ {
 +    ($expr:expr) => {
 +        || -> _ { Some($expr) }()
 +    };
 +}
 +macro_rules! try_or {
 +    ($expr:expr, $or:expr) => {
 +        try_!($expr).unwrap_or($or)
 +    };
 +}
 +
 +macro_rules! try_or_def {
 +    ($expr:expr) => {
 +        try_!($expr).unwrap_or_default()
 +    };
 +}
 +
 +impl Config {
 +    pub fn linked_projects(&self) -> Vec<LinkedProject> {
 +        match self.data.linkedProjects.as_slice() {
 +            [] => match self.discovered_projects.as_ref() {
 +                Some(discovered_projects) => {
 +                    let exclude_dirs: Vec<_> = self
 +                        .data
 +                        .files_excludeDirs
 +                        .iter()
 +                        .map(|p| self.root_path.join(p))
 +                        .collect();
 +                    discovered_projects
 +                        .iter()
 +                        .filter(|p| {
 +                            let (ProjectManifest::ProjectJson(path)
 +                            | ProjectManifest::CargoToml(path)) = p;
 +                            !exclude_dirs.iter().any(|p| path.starts_with(p))
 +                        })
 +                        .cloned()
 +                        .map(LinkedProject::from)
 +                        .collect()
 +                }
 +                None => Vec::new(),
 +            },
 +            linked_projects => linked_projects
 +                .iter()
 +                .filter_map(|linked_project| match linked_project {
 +                    ManifestOrProjectJson::Manifest(it) => {
 +                        let path = self.root_path.join(it);
 +                        ProjectManifest::from_manifest_file(path)
 +                            .map_err(|e| tracing::error!("failed to load linked project: {}", e))
 +                            .ok()
 +                            .map(Into::into)
 +                    }
 +                    ManifestOrProjectJson::ProjectJson(it) => {
 +                        Some(ProjectJson::new(&self.root_path, it.clone()).into())
 +                    }
 +                })
 +                .collect(),
 +        }
 +    }
 +
 +    pub fn did_save_text_document_dynamic_registration(&self) -> bool {
 +        let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?);
 +        caps.did_save == Some(true) && caps.dynamic_registration == Some(true)
 +    }
 +
 +    pub fn did_change_watched_files_dynamic_registration(&self) -> bool {
 +        try_or_def!(
 +            self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration?
 +        )
 +    }
 +
 +    pub fn prefill_caches(&self) -> bool {
 +        self.data.cachePriming_enable
 +    }
 +
 +    pub fn location_link(&self) -> bool {
 +        try_or_def!(self.caps.text_document.as_ref()?.definition?.link_support?)
 +    }
 +
 +    pub fn line_folding_only(&self) -> bool {
 +        try_or_def!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?)
 +    }
 +
 +    pub fn hierarchical_symbols(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .document_symbol
 +                .as_ref()?
 +                .hierarchical_document_symbol_support?
 +        )
 +    }
 +
 +    pub fn code_action_literals(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .code_action
 +            .as_ref()?
 +            .code_action_literal_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn work_done_progress(&self) -> bool {
 +        try_or_def!(self.caps.window.as_ref()?.work_done_progress?)
 +    }
 +
 +    pub fn will_rename(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?)
 +    }
 +
 +    pub fn change_annotation_support(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .workspace
 +            .as_ref()?
 +            .workspace_edit
 +            .as_ref()?
 +            .change_annotation_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn code_action_resolve(&self) -> bool {
 +        try_or_def!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .code_action
 +            .as_ref()?
 +            .resolve_support
 +            .as_ref()?
 +            .properties
 +            .as_slice())
 +        .iter()
 +        .any(|it| it == "edit")
 +    }
 +
 +    pub fn signature_help_label_offsets(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .signature_help
 +                .as_ref()?
 +                .signature_information
 +                .as_ref()?
 +                .parameter_information
 +                .as_ref()?
 +                .label_offset_support?
 +        )
 +    }
 +
 +    pub fn completion_label_details_support(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .completion
 +            .as_ref()?
 +            .completion_item
 +            .as_ref()?
 +            .label_details_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn offset_encoding(&self) -> OffsetEncoding {
 +        if supports_utf8(&self.caps) {
 +            OffsetEncoding::Utf8
 +        } else {
 +            OffsetEncoding::Utf16
 +        }
 +    }
 +
 +    fn experimental(&self, index: &'static str) -> bool {
 +        try_or_def!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?)
 +    }
 +
 +    pub fn code_action_group(&self) -> bool {
 +        self.experimental("codeActionGroup")
 +    }
 +
 +    pub fn server_status_notification(&self) -> bool {
 +        self.experimental("serverStatusNotification")
 +    }
 +
 +    pub fn publish_diagnostics(&self) -> bool {
 +        self.data.diagnostics_enable
 +    }
 +
 +    pub fn diagnostics(&self) -> DiagnosticsConfig {
 +        DiagnosticsConfig {
 +            proc_attr_macros_enabled: self.expand_proc_attr_macros(),
 +            proc_macros_enabled: self.data.procMacro_enable,
 +            disable_experimental: !self.data.diagnostics_experimental_enable,
 +            disabled: self.data.diagnostics_disabled.clone(),
 +            expr_fill_default: match self.data.assist_expressionFillDefault {
 +                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
 +                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
 +            },
 +            insert_use: self.insert_use_config(),
++            prefer_no_std: self.data.imports_prefer_no_std,
 +        }
 +    }
 +
 +    pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
 +        DiagnosticsMapConfig {
 +            remap_prefix: self.data.diagnostics_remapPrefix.clone(),
 +            warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(),
 +            warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(),
 +        }
 +    }
 +
++    pub fn extra_env(&self) -> &FxHashMap<String, String> {
++        &self.data.cargo_extraEnv
++    }
++
++    pub fn check_on_save_extra_env(&self) -> FxHashMap<String, String> {
++        let mut extra_env = self.data.cargo_extraEnv.clone();
++        extra_env.extend(self.data.checkOnSave_extraEnv.clone());
++        extra_env
++    }
++
 +    pub fn lru_capacity(&self) -> Option<usize> {
 +        self.data.lru_capacity
 +    }
 +
 +    pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, Vec<OsString>)> {
 +        if !self.data.procMacro_enable {
 +            return None;
 +        }
 +        let path = match &self.data.procMacro_server {
 +            Some(it) => self.root_path.join(it),
 +            None => AbsPathBuf::assert(std::env::current_exe().ok()?),
 +        };
 +        Some((path, vec!["proc-macro".into()]))
 +    }
 +
 +    pub fn dummy_replacements(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
 +        &self.data.procMacro_ignored
 +    }
 +
 +    pub fn expand_proc_attr_macros(&self) -> bool {
 +        self.data.procMacro_enable && self.data.procMacro_attributes_enable
 +    }
 +
 +    pub fn files(&self) -> FilesConfig {
 +        FilesConfig {
 +            watcher: match self.data.files_watcher {
 +                FilesWatcherDef::Client if self.did_change_watched_files_dynamic_registration() => {
 +                    FilesWatcher::Client
 +                }
 +                _ => FilesWatcher::Server,
 +            },
 +            exclude: self.data.files_excludeDirs.iter().map(|it| self.root_path.join(it)).collect(),
 +        }
 +    }
 +
 +    pub fn notifications(&self) -> NotificationsConfig {
 +        NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
 +    }
 +
 +    pub fn cargo_autoreload(&self) -> bool {
 +        self.data.cargo_autoreload
 +    }
 +
 +    pub fn run_build_scripts(&self) -> bool {
 +        self.data.cargo_buildScripts_enable || self.data.procMacro_enable
 +    }
 +
 +    pub fn cargo(&self) -> CargoConfig {
 +        let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
 +            if rustc_src == "discover" {
 +                RustcSource::Discover
 +            } else {
 +                RustcSource::Path(self.root_path.join(rustc_src))
 +            }
 +        });
 +
 +        CargoConfig {
 +            no_default_features: self.data.cargo_noDefaultFeatures,
 +            all_features: matches!(self.data.cargo_features, CargoFeatures::All),
 +            features: match &self.data.cargo_features {
 +                CargoFeatures::All => vec![],
 +                CargoFeatures::Listed(it) => it.clone(),
 +            },
 +            target: self.data.cargo_target.clone(),
 +            no_sysroot: self.data.cargo_noSysroot,
 +            rustc_source,
 +            unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
 +            wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
 +            run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
++            extra_env: self.data.cargo_extraEnv.clone(),
 +        }
 +    }
 +
 +    pub fn rustfmt(&self) -> RustfmtConfig {
 +        match &self.data.rustfmt_overrideCommand {
 +            Some(args) if !args.is_empty() => {
 +                let mut args = args.clone();
 +                let command = args.remove(0);
 +                RustfmtConfig::CustomCommand { command, args }
 +            }
 +            Some(_) | None => RustfmtConfig::Rustfmt {
 +                extra_args: self.data.rustfmt_extraArgs.clone(),
 +                enable_range_formatting: self.data.rustfmt_rangeFormatting_enable,
 +            },
 +        }
 +    }
 +
 +    pub fn flycheck(&self) -> Option<FlycheckConfig> {
 +        if !self.data.checkOnSave_enable {
 +            return None;
 +        }
 +        let flycheck_config = match &self.data.checkOnSave_overrideCommand {
 +            Some(args) if !args.is_empty() => {
 +                let mut args = args.clone();
 +                let command = args.remove(0);
++                FlycheckConfig::CustomCommand {
++                    command,
++                    args,
++                    extra_env: self.check_on_save_extra_env(),
++                }
 +            }
 +            Some(_) | None => FlycheckConfig::CargoCommand {
 +                command: self.data.checkOnSave_command.clone(),
 +                target_triple: self
 +                    .data
 +                    .checkOnSave_target
 +                    .clone()
 +                    .or_else(|| self.data.cargo_target.clone()),
 +                all_targets: self.data.checkOnSave_allTargets,
 +                no_default_features: self
 +                    .data
 +                    .checkOnSave_noDefaultFeatures
 +                    .unwrap_or(self.data.cargo_noDefaultFeatures),
 +                all_features: matches!(
 +                    self.data.checkOnSave_features.as_ref().unwrap_or(&self.data.cargo_features),
 +                    CargoFeatures::All
 +                ),
 +                features: match self
 +                    .data
 +                    .checkOnSave_features
 +                    .clone()
 +                    .unwrap_or_else(|| self.data.cargo_features.clone())
 +                {
 +                    CargoFeatures::All => vec![],
 +                    CargoFeatures::Listed(it) => it,
 +                },
 +                extra_args: self.data.checkOnSave_extraArgs.clone(),
++                extra_env: self.check_on_save_extra_env(),
 +            },
 +        };
 +        Some(flycheck_config)
 +    }
 +
 +    pub fn runnables(&self) -> RunnablesConfig {
 +        RunnablesConfig {
 +            override_cargo: self.data.runnables_command.clone(),
 +            cargo_extra_args: self.data.runnables_extraArgs.clone(),
 +        }
 +    }
 +
 +    pub fn inlay_hints(&self) -> InlayHintsConfig {
 +        InlayHintsConfig {
 +            render_colons: self.data.inlayHints_renderColons,
 +            type_hints: self.data.inlayHints_typeHints_enable,
 +            parameter_hints: self.data.inlayHints_parameterHints_enable,
 +            chaining_hints: self.data.inlayHints_chainingHints_enable,
 +            closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable {
 +                ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
 +                ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
 +                ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock,
 +            },
 +            lifetime_elision_hints: match self.data.inlayHints_lifetimeElisionHints_enable {
 +                LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always,
 +                LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never,
 +                LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
 +            },
 +            hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
 +            hide_closure_initialization_hints: self
 +                .data
 +                .inlayHints_typeHints_hideClosureInitialization,
 +            reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
 +                ReborrowHintsDef::Always => ide::ReborrowHints::Always,
 +                ReborrowHintsDef::Never => ide::ReborrowHints::Never,
 +                ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
 +            },
 +            binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
 +            param_names_for_lifetime_elision_hints: self
 +                .data
 +                .inlayHints_lifetimeElisionHints_useParameterNames,
 +            max_length: self.data.inlayHints_maxLength,
 +            closing_brace_hints_min_lines: if self.data.inlayHints_closingBraceHints_enable {
 +                Some(self.data.inlayHints_closingBraceHints_minLines)
 +            } else {
 +                None
 +            },
 +        }
 +    }
 +
 +    fn insert_use_config(&self) -> InsertUseConfig {
 +        InsertUseConfig {
 +            granularity: match self.data.imports_granularity_group {
 +                ImportGranularityDef::Preserve => ImportGranularity::Preserve,
 +                ImportGranularityDef::Item => ImportGranularity::Item,
 +                ImportGranularityDef::Crate => ImportGranularity::Crate,
 +                ImportGranularityDef::Module => ImportGranularity::Module,
 +            },
 +            enforce_granularity: self.data.imports_granularity_enforce,
 +            prefix_kind: match self.data.imports_prefix {
 +                ImportPrefixDef::Plain => PrefixKind::Plain,
 +                ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
 +                ImportPrefixDef::BySelf => PrefixKind::BySelf,
 +            },
 +            group: self.data.imports_group_enable,
 +            skip_glob_imports: !self.data.imports_merge_glob,
 +        }
 +    }
 +
 +    pub fn completion(&self) -> CompletionConfig {
 +        CompletionConfig {
 +            enable_postfix_completions: self.data.completion_postfix_enable,
 +            enable_imports_on_the_fly: self.data.completion_autoimport_enable
 +                && completion_item_edit_resolve(&self.caps),
 +            enable_self_on_the_fly: self.data.completion_autoself_enable,
 +            enable_private_editable: self.data.completion_privateEditable_enable,
 +            callable: match self.data.completion_callable_snippets {
 +                CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
 +                CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
 +                CallableCompletionDef::None => None,
 +            },
 +            insert_use: self.insert_use_config(),
++            prefer_no_std: self.data.imports_prefer_no_std,
 +            snippet_cap: SnippetCap::new(try_or_def!(
 +                self.caps
 +                    .text_document
 +                    .as_ref()?
 +                    .completion
 +                    .as_ref()?
 +                    .completion_item
 +                    .as_ref()?
 +                    .snippet_support?
 +            )),
 +            snippets: self.snippets.clone(),
 +        }
 +    }
 +
++    pub fn find_all_refs_exclude_imports(&self) -> bool {
++        self.data.references_excludeImports
++    }
++
 +    pub fn snippet_cap(&self) -> bool {
 +        self.experimental("snippetTextEdit")
 +    }
 +
 +    pub fn assist(&self) -> AssistConfig {
 +        AssistConfig {
 +            snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
 +            allowed: None,
 +            insert_use: self.insert_use_config(),
++            prefer_no_std: self.data.imports_prefer_no_std,
 +        }
 +    }
 +
 +    pub fn join_lines(&self) -> JoinLinesConfig {
 +        JoinLinesConfig {
 +            join_else_if: self.data.joinLines_joinElseIf,
 +            remove_trailing_comma: self.data.joinLines_removeTrailingComma,
 +            unwrap_trivial_blocks: self.data.joinLines_unwrapTrivialBlock,
 +            join_assignments: self.data.joinLines_joinAssignments,
 +        }
 +    }
 +
 +    pub fn call_info(&self) -> CallInfoConfig {
 +        CallInfoConfig {
 +            params_only: matches!(self.data.signatureInfo_detail, SignatureDetail::Parameters),
 +            docs: self.data.signatureInfo_documentation_enable,
 +        }
 +    }
 +
 +    pub fn lens(&self) -> LensConfig {
 +        LensConfig {
 +            run: self.data.lens_enable && self.data.lens_run_enable,
 +            debug: self.data.lens_enable && self.data.lens_debug_enable,
 +            implementations: self.data.lens_enable && self.data.lens_implementations_enable,
 +            method_refs: self.data.lens_enable && self.data.lens_references_method_enable,
 +            refs_adt: self.data.lens_enable && self.data.lens_references_adt_enable,
 +            refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable,
 +            enum_variant_refs: self.data.lens_enable
 +                && self.data.lens_references_enumVariant_enable,
++            location: self.data.lens_location,
 +        }
 +    }
 +
 +    pub fn hover_actions(&self) -> HoverActionsConfig {
 +        let enable = self.experimental("hoverActions") && self.data.hover_actions_enable;
 +        HoverActionsConfig {
 +            implementations: enable && self.data.hover_actions_implementations_enable,
 +            references: enable && self.data.hover_actions_references_enable,
 +            run: enable && self.data.hover_actions_run_enable,
 +            debug: enable && self.data.hover_actions_debug_enable,
 +            goto_type_def: enable && self.data.hover_actions_gotoTypeDef_enable,
 +        }
 +    }
 +
 +    pub fn highlighting_config(&self) -> HighlightConfig {
 +        HighlightConfig {
 +            strings: self.data.semanticHighlighting_strings_enable,
 +            punctuation: self.data.semanticHighlighting_punctuation_enable,
 +            specialize_punctuation: self
 +                .data
 +                .semanticHighlighting_punctuation_specialization_enable,
 +            macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang,
 +            operator: self.data.semanticHighlighting_operator_enable,
 +            specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
 +            inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable,
 +            syntactic_name_ref_highlighting: false,
 +        }
 +    }
 +
 +    pub fn hover(&self) -> HoverConfig {
 +        HoverConfig {
 +            links_in_hover: self.data.hover_links_enable,
 +            documentation: self.data.hover_documentation_enable.then(|| {
 +                let is_markdown = try_or_def!(self
 +                    .caps
 +                    .text_document
 +                    .as_ref()?
 +                    .hover
 +                    .as_ref()?
 +                    .content_format
 +                    .as_ref()?
 +                    .as_slice())
 +                .contains(&MarkupKind::Markdown);
 +                if is_markdown {
 +                    HoverDocFormat::Markdown
 +                } else {
 +                    HoverDocFormat::PlainText
 +                }
 +            }),
 +            keywords: self.data.hover_documentation_keywords_enable,
 +        }
 +    }
 +
 +    pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig {
 +        WorkspaceSymbolConfig {
 +            search_scope: match self.data.workspace_symbol_search_scope {
 +                WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
 +                WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
 +                    WorkspaceSymbolSearchScope::WorkspaceAndDependencies
 +                }
 +            },
 +            search_kind: match self.data.workspace_symbol_search_kind {
 +                WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes,
 +                WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols,
 +            },
 +            search_limit: self.data.workspace_symbol_search_limit,
 +        }
 +    }
 +
 +    pub fn semantic_tokens_refresh(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?)
 +    }
 +
 +    pub fn code_lens_refresh(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?)
 +    }
 +
 +    pub fn insert_replace_support(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .completion
 +                .as_ref()?
 +                .completion_item
 +                .as_ref()?
 +                .insert_replace_support?
 +        )
 +    }
 +
 +    pub fn client_commands(&self) -> ClientCommandsConfig {
 +        let commands =
 +            try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null);
 +        let commands: Option<lsp_ext::ClientCommandOptions> =
 +            serde_json::from_value(commands.clone()).ok();
 +        let force = commands.is_none() && self.data.lens_forceCustomCommands;
 +        let commands = commands.map(|it| it.commands).unwrap_or_default();
 +
 +        let get = |name: &str| commands.iter().any(|it| it == name) || force;
 +
 +        ClientCommandsConfig {
 +            run_single: get("rust-analyzer.runSingle"),
 +            debug_single: get("rust-analyzer.debugSingle"),
 +            show_reference: get("rust-analyzer.showReferences"),
 +            goto_location: get("rust-analyzer.gotoLocation"),
 +            trigger_parameter_hints: get("editor.action.triggerParameterHints"),
 +        }
 +    }
 +
 +    pub fn highlight_related(&self) -> HighlightRelatedConfig {
 +        HighlightRelatedConfig {
 +            references: self.data.highlightRelated_references_enable,
 +            break_points: self.data.highlightRelated_breakPoints_enable,
 +            exit_points: self.data.highlightRelated_exitPoints_enable,
 +            yield_points: self.data.highlightRelated_yieldPoints_enable,
 +        }
 +    }
 +
 +    pub fn prime_caches_num_threads(&self) -> u8 {
 +        match self.data.cachePriming_numThreads {
 +            0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX),
 +            n => n,
 +        }
 +    }
 +
 +    pub fn typing_autoclose_angle(&self) -> bool {
 +        self.data.typing_autoClosingAngleBrackets_enable
 +    }
 +}
 +// Deserialization definitions
 +
 +macro_rules! create_bool_or_string_de {
 +    ($ident:ident<$bool:literal, $string:literal>) => {
 +        fn $ident<'de, D>(d: D) -> Result<(), D::Error>
 +        where
 +            D: serde::Deserializer<'de>,
 +        {
 +            struct V;
 +            impl<'de> serde::de::Visitor<'de> for V {
 +                type Value = ();
 +
 +                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                    formatter.write_str(concat!(
 +                        stringify!($bool),
 +                        " or \"",
 +                        stringify!($string),
 +                        "\""
 +                    ))
 +                }
 +
 +                fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
 +                where
 +                    E: serde::de::Error,
 +                {
 +                    match v {
 +                        $bool => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Bool(v),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +
 +                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
 +                where
 +                    E: serde::de::Error,
 +                {
 +                    match v {
 +                        $string => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Str(v),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +
 +                fn visit_enum<A>(self, a: A) -> Result<Self::Value, A::Error>
 +                where
 +                    A: serde::de::EnumAccess<'de>,
 +                {
 +                    use serde::de::VariantAccess;
 +                    let (variant, va) = a.variant::<&'de str>()?;
 +                    va.unit_variant()?;
 +                    match variant {
 +                        $string => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Str(variant),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +            }
 +            d.deserialize_any(V)
 +        }
 +    };
 +}
 +create_bool_or_string_de!(true_or_always<true, "always">);
 +create_bool_or_string_de!(false_or_never<false, "never">);
 +
 +macro_rules! named_unit_variant {
 +    ($variant:ident) => {
 +        pub(super) fn $variant<'de, D>(deserializer: D) -> Result<(), D::Error>
 +        where
 +            D: serde::Deserializer<'de>,
 +        {
 +            struct V;
 +            impl<'de> serde::de::Visitor<'de> for V {
 +                type Value = ();
 +                fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +                    f.write_str(concat!("\"", stringify!($variant), "\""))
 +                }
 +                fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
 +                    if value == stringify!($variant) {
 +                        Ok(())
 +                    } else {
 +                        Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
 +                    }
 +                }
 +            }
 +            deserializer.deserialize_str(V)
 +        }
 +    };
 +}
 +
 +mod de_unit_v {
 +    named_unit_variant!(all);
 +    named_unit_variant!(skip_trivial);
 +    named_unit_variant!(mutable);
 +    named_unit_variant!(with_block);
 +}
 +
 +#[derive(Deserialize, Debug, Clone, Copy)]
 +#[serde(rename_all = "snake_case")]
 +enum SnippetScopeDef {
 +    Expr,
 +    Item,
 +    Type,
 +}
 +
 +impl Default for SnippetScopeDef {
 +    fn default() -> Self {
 +        SnippetScopeDef::Expr
 +    }
 +}
 +
 +#[derive(Deserialize, Debug, Clone, Default)]
 +#[serde(default)]
 +struct SnippetDef {
 +    #[serde(deserialize_with = "single_or_array")]
 +    prefix: Vec<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    postfix: Vec<String>,
 +    description: Option<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    body: Vec<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    requires: Vec<String>,
 +    scope: SnippetScopeDef,
 +}
 +
 +fn single_or_array<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
 +where
 +    D: serde::Deserializer<'de>,
 +{
 +    struct SingleOrVec;
 +
 +    impl<'de> serde::de::Visitor<'de> for SingleOrVec {
 +        type Value = Vec<String>;
 +
 +        fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +            formatter.write_str("string or array of strings")
 +        }
 +
 +        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
 +        where
 +            E: serde::de::Error,
 +        {
 +            Ok(vec![value.to_owned()])
 +        }
 +
 +        fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
 +        where
 +            A: serde::de::SeqAccess<'de>,
 +        {
 +            Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq))
 +        }
 +    }
 +
 +    deserializer.deserialize_any(SingleOrVec)
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ManifestOrProjectJson {
 +    Manifest(PathBuf),
 +    ProjectJson(ProjectJsonData),
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ExprFillDefaultDef {
 +    Todo,
 +    Default,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ImportGranularityDef {
 +    Preserve,
 +    Item,
 +    Crate,
 +    Module,
 +}
 +
 +#[derive(Deserialize, Debug, Copy, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum CallableCompletionDef {
 +    FillArguments,
 +    AddParentheses,
 +    None,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum CargoFeatures {
 +    #[serde(deserialize_with = "de_unit_v::all")]
 +    All,
 +    Listed(Vec<String>),
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum LifetimeElisionDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::skip_trivial")]
 +    SkipTrivial,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ClosureReturnTypeHintsDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::with_block")]
 +    WithBlock,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ReborrowHintsDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::mutable")]
 +    Mutable,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum FilesWatcherDef {
 +    Client,
 +    Notify,
 +    Server,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ImportPrefixDef {
 +    Plain,
 +    #[serde(alias = "self")]
 +    BySelf,
 +    #[serde(alias = "crate")]
 +    ByCrate,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum WorkspaceSymbolSearchScopeDef {
 +    Workspace,
 +    WorkspaceAndDependencies,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum SignatureDetail {
 +    Full,
 +    Parameters,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum WorkspaceSymbolSearchKindDef {
 +    OnlyTypes,
 +    AllSymbols,
 +}
 +
 +macro_rules! _config_data {
 +    (struct $name:ident {
 +        $(
 +            $(#[doc=$doc:literal])*
 +            $field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
 +        )*
 +    }) => {
 +        #[allow(non_snake_case)]
 +        #[derive(Debug, Clone)]
 +        struct $name { $($field: $ty,)* }
 +        impl $name {
 +            fn from_json(mut json: serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name {
 +                $name {$(
 +                    $field: get_field(
 +                        &mut json,
 +                        error_sink,
 +                        stringify!($field),
 +                        None$(.or(Some(stringify!($alias))))*,
 +                        $default,
 +                    ),
 +                )*}
 +            }
 +
 +            fn json_schema() -> serde_json::Value {
 +                schema(&[
 +                    $({
 +                        let field = stringify!($field);
 +                        let ty = stringify!($ty);
 +
 +                        (field, ty, &[$($doc),*], $default)
 +                    },)*
 +                ])
 +            }
 +
 +            #[cfg(test)]
 +            fn manual() -> String {
 +                manual(&[
 +                    $({
 +                        let field = stringify!($field);
 +                        let ty = stringify!($ty);
 +
 +                        (field, ty, &[$($doc),*], $default)
 +                    },)*
 +                ])
 +            }
 +        }
 +
 +        #[test]
 +        fn fields_are_sorted() {
 +            [$(stringify!($field)),*].windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
 +        }
 +    };
 +}
 +use _config_data as config_data;
 +
 +fn get_field<T: DeserializeOwned>(
 +    json: &mut serde_json::Value,
 +    error_sink: &mut Vec<(String, serde_json::Error)>,
 +    field: &'static str,
 +    alias: Option<&'static str>,
 +    default: &str,
 +) -> T {
 +    let default = serde_json::from_str(default).unwrap();
 +    // XXX: check alias first, to work-around the VS Code where it pre-fills the
 +    // defaults instead of sending an empty object.
 +    alias
 +        .into_iter()
 +        .chain(iter::once(field))
 +        .find_map(move |field| {
 +            let mut pointer = field.replace('_', "/");
 +            pointer.insert(0, '/');
 +            json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) {
 +                Ok(it) => Some(it),
 +                Err(e) => {
 +                    tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
 +                    error_sink.push((pointer, e));
 +                    None
 +                }
 +            })
 +        })
 +        .unwrap_or(default)
 +}
 +
 +fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value {
 +    for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) {
 +        fn key(f: &str) -> &str {
 +            f.splitn(2, '_').next().unwrap()
 +        }
 +        assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2);
 +    }
 +
 +    let map = fields
 +        .iter()
 +        .map(|(field, ty, doc, default)| {
 +            let name = field.replace('_', ".");
 +            let name = format!("rust-analyzer.{}", name);
 +            let props = field_props(field, ty, doc, default);
 +            (name, props)
 +        })
 +        .collect::<serde_json::Map<_, _>>();
 +    map.into()
 +}
 +
 +fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value {
 +    let doc = doc_comment_to_string(doc);
 +    let doc = doc.trim_end_matches('\n');
 +    assert!(
 +        doc.ends_with('.') && doc.starts_with(char::is_uppercase),
 +        "bad docs for {}: {:?}",
 +        field,
 +        doc
 +    );
 +    let default = default.parse::<serde_json::Value>().unwrap();
 +
 +    let mut map = serde_json::Map::default();
 +    macro_rules! set {
 +        ($($key:literal: $value:tt),*$(,)?) => {{$(
 +            map.insert($key.into(), serde_json::json!($value));
 +        )*}};
 +    }
 +    set!("markdownDescription": doc);
 +    set!("default": default);
 +
 +    match ty {
 +        "bool" => set!("type": "boolean"),
 +        "usize" => set!("type": "integer", "minimum": 0),
 +        "String" => set!("type": "string"),
 +        "Vec<String>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +        },
 +        "Vec<PathBuf>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +        },
 +        "FxHashSet<String>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +            "uniqueItems": true,
 +        },
 +        "FxHashMap<Box<str>, Box<[Box<str>]>>" => set! {
 +            "type": "object",
 +        },
 +        "FxHashMap<String, SnippetDef>" => set! {
 +            "type": "object",
 +        },
 +        "FxHashMap<String, String>" => set! {
 +            "type": "object",
 +        },
 +        "Option<usize>" => set! {
 +            "type": ["null", "integer"],
 +            "minimum": 0,
 +        },
 +        "Option<String>" => set! {
 +            "type": ["null", "string"],
 +        },
 +        "Option<PathBuf>" => set! {
 +            "type": ["null", "string"],
 +        },
 +        "Option<bool>" => set! {
 +            "type": ["null", "boolean"],
 +        },
 +        "Option<Vec<String>>" => set! {
 +            "type": ["null", "array"],
 +            "items": { "type": "string" },
 +        },
 +        "MergeBehaviorDef" => set! {
 +            "type": "string",
 +            "enum": ["none", "crate", "module"],
 +            "enumDescriptions": [
 +                "Do not merge imports at all.",
 +                "Merge imports from the same crate into a single `use` statement.",
 +                "Merge imports from the same module into a single `use` statement."
 +            ],
 +        },
 +        "ExprFillDefaultDef" => set! {
 +            "type": "string",
 +            "enum": ["todo", "default"],
 +            "enumDescriptions": [
 +                "Fill missing expressions with the `todo` macro",
 +                "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
 +            ],
 +        },
 +        "ImportGranularityDef" => set! {
 +            "type": "string",
 +            "enum": ["preserve", "crate", "module", "item"],
 +            "enumDescriptions": [
 +                "Do not change the granularity of any imports and preserve the original structure written by the developer.",
 +                "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
 +                "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
 +                "Flatten imports so that each has its own use statement."
 +            ],
 +        },
 +        "ImportPrefixDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "plain",
 +                "self",
 +                "crate"
 +            ],
 +            "enumDescriptions": [
 +                "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
 +                "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
 +                "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
 +            ],
 +        },
 +        "Vec<ManifestOrProjectJson>" => set! {
 +            "type": "array",
 +            "items": { "type": ["string", "object"] },
 +        },
 +        "WorkspaceSymbolSearchScopeDef" => set! {
 +            "type": "string",
 +            "enum": ["workspace", "workspace_and_dependencies"],
 +            "enumDescriptions": [
 +                "Search in current workspace only.",
 +                "Search in current workspace and dependencies."
 +            ],
 +        },
 +        "WorkspaceSymbolSearchKindDef" => set! {
 +            "type": "string",
 +            "enum": ["only_types", "all_symbols"],
 +            "enumDescriptions": [
 +                "Search for types only.",
 +                "Search for all symbols kinds."
 +            ],
 +        },
 +        "ParallelCachePrimingNumThreads" => set! {
 +            "type": "number",
 +            "minimum": 0,
 +            "maximum": 255
 +        },
 +        "LifetimeElisionDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "skip_trivial"
 +            ],
 +            "enumDescriptions": [
 +                "Always show lifetime elision hints.",
 +                "Never show lifetime elision hints.",
 +                "Only show lifetime elision hints if a return type is involved."
 +            ]
 +        },
 +        "ClosureReturnTypeHintsDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "with_block"
 +            ],
 +            "enumDescriptions": [
 +                "Always show type hints for return types of closures.",
 +                "Never show type hints for return types of closures.",
 +                "Only show type hints for return types of closures with blocks."
 +            ]
 +        },
 +        "ReborrowHintsDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "mutable"
 +            ],
 +            "enumDescriptions": [
 +                "Always show reborrow hints.",
 +                "Never show reborrow hints.",
 +                "Only show mutable reborrow hints."
 +            ]
 +        },
 +        "CargoFeatures" => set! {
 +            "anyOf": [
 +                {
 +                    "type": "string",
 +                    "enum": [
 +                        "all"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Pass `--all-features` to cargo",
 +                    ]
 +                },
 +                {
 +                    "type": "array",
 +                    "items": { "type": "string" }
 +                }
 +            ],
 +        },
 +        "Option<CargoFeatures>" => set! {
 +            "anyOf": [
 +                {
 +                    "type": "string",
 +                    "enum": [
 +                        "all"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Pass `--all-features` to cargo",
 +                    ]
 +                },
 +                {
 +                    "type": "array",
 +                    "items": { "type": "string" }
 +                },
 +                { "type": "null" }
 +            ],
 +        },
 +        "CallableCompletionDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "fill_arguments",
 +                "add_parentheses",
 +                "none",
 +            ],
 +            "enumDescriptions": [
 +                "Add call parentheses and pre-fill arguments.",
 +                "Add call parentheses.",
 +                "Do no snippet completions for callables."
 +            ]
 +        },
 +        "SignatureDetail" => set! {
 +            "type": "string",
 +            "enum": ["full", "parameters"],
 +            "enumDescriptions": [
 +                "Show the entire signature.",
 +                "Show only the parameters."
 +            ],
 +        },
 +        "FilesWatcherDef" => set! {
 +            "type": "string",
 +            "enum": ["client", "server"],
 +            "enumDescriptions": [
 +                "Use the client (editor) to watch files for changes",
 +                "Use server-side file watching",
 +            ],
 +        },
++        "AnnotationLocation" => set! {
++            "type": "string",
++            "enum": ["above_name", "above_whole_item"],
++            "enumDescriptions": [
++                "Render annotations above the name of the item.",
++                "Render annotations above the whole item, including documentation comments and attributes."
++            ],
++        },
 +        _ => panic!("missing entry for {}: {}", ty, default),
 +    }
 +
 +    map.into()
 +}
 +
 +#[cfg(test)]
 +fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
 +    fields
 +        .iter()
 +        .map(|(field, _ty, doc, default)| {
 +            let name = format!("rust-analyzer.{}", field.replace('_', "."));
 +            let doc = doc_comment_to_string(*doc);
 +            if default.contains('\n') {
 +                format!(
 +                    r#"[[{}]]{}::
 ++
 +--
 +Default:
 +----
 +{}
 +----
 +{}
 +--
 +"#,
 +                    name, name, default, doc
 +                )
 +            } else {
 +                format!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name, name, default, doc)
 +            }
 +        })
 +        .collect::<String>()
 +}
 +
 +fn doc_comment_to_string(doc: &[&str]) -> String {
 +    doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{}\n", it)).collect()
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::fs;
 +
 +    use test_utils::{ensure_file_contents, project_root};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn generate_package_json_config() {
 +        let s = Config::json_schema();
 +        let schema = format!("{:#}", s);
 +        let mut schema = schema
 +            .trim_start_matches('{')
 +            .trim_end_matches('}')
 +            .replace("  ", "    ")
 +            .replace('\n', "\n            ")
 +            .trim_start_matches('\n')
 +            .trim_end()
 +            .to_string();
 +        schema.push_str(",\n");
 +
 +        // Transform the asciidoc form link to markdown style.
 +        //
 +        // https://link[text] => [text](https://link)
 +        let url_matches = schema.match_indices("https://");
 +        let mut url_offsets = url_matches.map(|(idx, _)| idx).collect::<Vec<usize>>();
 +        url_offsets.reverse();
 +        for idx in url_offsets {
 +            let link = &schema[idx..];
 +            // matching on whitespace to ignore normal links
 +            if let Some(link_end) = link.find(|c| c == ' ' || c == '[') {
 +                if link.chars().nth(link_end) == Some('[') {
 +                    if let Some(link_text_end) = link.find(']') {
 +                        let link_text = link[link_end..(link_text_end + 1)].to_string();
 +
 +                        schema.replace_range((idx + link_end)..(idx + link_text_end + 1), "");
 +                        schema.insert(idx, '(');
 +                        schema.insert(idx + link_end + 1, ')');
 +                        schema.insert_str(idx, &link_text);
 +                    }
 +                }
 +            }
 +        }
 +
 +        let package_json_path = project_root().join("editors/code/package.json");
 +        let mut package_json = fs::read_to_string(&package_json_path).unwrap();
 +
 +        let start_marker = "                \"$generated-start\": {},\n";
 +        let end_marker = "                \"$generated-end\": {}\n";
 +
 +        let start = package_json.find(start_marker).unwrap() + start_marker.len();
 +        let end = package_json.find(end_marker).unwrap();
 +
 +        let p = remove_ws(&package_json[start..end]);
 +        let s = remove_ws(&schema);
 +        if !p.contains(&s) {
 +            package_json.replace_range(start..end, &schema);
 +            ensure_file_contents(&package_json_path, &package_json)
 +        }
 +    }
 +
 +    #[test]
 +    fn generate_config_documentation() {
 +        let docs_path = project_root().join("docs/user/generated_config.adoc");
 +        let expected = ConfigData::manual();
 +        ensure_file_contents(&docs_path, &expected);
 +    }
 +
 +    fn remove_ws(text: &str) -> String {
 +        text.replace(char::is_whitespace, "")
 +    }
 +}
index e79cf3d3fd6e9ffe535e5ff9aee9f007c52ec157,0000000000000000000000000000000000000000..8c3ea77d0611587c2f7f7b94083f5d4764d0cf6b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1911 -1,0 +1,1920 @@@
-     HoverAction, HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SingleResolve,
-     SourceChange, TextEdit,
 +//! This module is responsible for implementing handlers for Language Server
 +//! Protocol. The majority of requests are fulfilled by calling into the
 +//! `ide` crate.
 +
 +use std::{
 +    io::Write as _,
 +    process::{self, Stdio},
 +};
 +
 +use anyhow::Context;
 +use ide::{
 +    AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
-                     refs.into_iter().map(move |(range, _)| FileRange { file_id, range })
++    HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
++    SingleResolve, SourceChange, TextEdit,
 +};
 +use ide_db::SymbolKind;
 +use lsp_server::ErrorCode;
 +use lsp_types::{
 +    CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
 +    CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
 +    CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, FoldingRange,
 +    FoldingRangeParams, HoverContents, InlayHint, InlayHintParams, Location, LocationLink,
 +    NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
 +    SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
 +    SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
 +    SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 +};
 +use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 +use serde_json::json;
 +use stdx::{format_to, never};
 +use syntax::{algo, ast, AstNode, TextRange, TextSize, T};
 +use vfs::AbsPathBuf;
 +
 +use crate::{
 +    cargo_target_spec::CargoTargetSpec,
 +    config::{RustfmtConfig, WorkspaceSymbolConfig},
 +    diff::diff,
 +    from_proto,
 +    global_state::{GlobalState, GlobalStateSnapshot},
 +    line_index::LineEndings,
 +    lsp_ext::{self, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams},
 +    lsp_utils::{all_edits_are_disjoint, invalid_params_error},
 +    to_proto, LspError, Result,
 +};
 +
 +pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.proc_macro_clients.clear();
 +    state.proc_macro_changed = false;
 +    state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
 +    state.fetch_build_data_queue.request_op("reload workspace request".to_string());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> {
 +    let _p = profile::span("handle_stop_flycheck");
 +    state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_analyzer_status(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::AnalyzerStatusParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_analyzer_status");
 +
 +    let mut buf = String::new();
 +
 +    let mut file_id = None;
 +    if let Some(tdi) = params.text_document {
 +        match from_proto::file_id(&snap, &tdi.uri) {
 +            Ok(it) => file_id = Some(it),
 +            Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri),
 +        }
 +    }
 +
 +    if snap.workspaces.is_empty() {
 +        buf.push_str("No workspaces\n")
 +    } else {
 +        buf.push_str("Workspaces:\n");
 +        format_to!(
 +            buf,
 +            "Loaded {:?} packages across {} workspace{}.\n",
 +            snap.workspaces.iter().map(|w| w.n_packages()).sum::<usize>(),
 +            snap.workspaces.len(),
 +            if snap.workspaces.len() == 1 { "" } else { "s" }
 +        );
 +    }
 +    buf.push_str("\nAnalysis:\n");
 +    buf.push_str(
 +        &snap
 +            .analysis
 +            .status(file_id)
 +            .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
 +    );
 +    Ok(buf)
 +}
 +
 +pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> {
 +    let _p = profile::span("handle_memory_usage");
 +    let mut mem = state.analysis_host.per_query_memory_usage();
 +    mem.push(("Remaining".into(), profile::memory_usage().allocated));
 +
 +    let mut out = String::new();
 +    for (name, bytes) in mem {
 +        format_to!(out, "{:>8} {}\n", bytes, name);
 +    }
 +    Ok(out)
 +}
 +
 +pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.analysis_host.shuffle_crate_graph();
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_syntax_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SyntaxTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_syntax_tree");
 +    let id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(id)?;
 +    let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
 +    let res = snap.analysis.syntax_tree(id, text_range)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_hir(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_hir");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let res = snap.analysis.view_hir(position)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_file_text(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentIdentifier,
 +) -> Result<String> {
 +    let file_id = from_proto::file_id(&snap, &params.uri)?;
 +    Ok(snap.analysis.file_text(file_id)?.to_string())
 +}
 +
 +pub(crate) fn handle_view_item_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ViewItemTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_item_tree");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let res = snap.analysis.view_item_tree(file_id)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_crate_graph(
 +    snap: GlobalStateSnapshot,
 +    params: ViewCrateGraphParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_crate_graph");
 +    let dot = snap.analysis.view_crate_graph(params.full)??;
 +    Ok(dot)
 +}
 +
 +pub(crate) fn handle_expand_macro(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ExpandMacroParams,
 +) -> Result<Option<lsp_ext::ExpandedMacro>> {
 +    let _p = profile::span("handle_expand_macro");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, params.position)?;
 +
 +    let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?;
 +    Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion }))
 +}
 +
 +pub(crate) fn handle_selection_range(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SelectionRangeParams,
 +) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
 +    let _p = profile::span("handle_selection_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let res: Result<Vec<lsp_types::SelectionRange>> = params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position)?;
 +            let mut ranges = Vec::new();
 +            {
 +                let mut range = TextRange::new(offset, offset);
 +                loop {
 +                    ranges.push(range);
 +                    let frange = FileRange { file_id, range };
 +                    let next = snap.analysis.extend_selection(frange)?;
 +                    if next == range {
 +                        break;
 +                    } else {
 +                        range = next
 +                    }
 +                }
 +            }
 +            let mut range = lsp_types::SelectionRange {
 +                range: to_proto::range(&line_index, *ranges.last().unwrap()),
 +                parent: None,
 +            };
 +            for &r in ranges.iter().rev().skip(1) {
 +                range = lsp_types::SelectionRange {
 +                    range: to_proto::range(&line_index, r),
 +                    parent: Some(Box::new(range)),
 +                }
 +            }
 +            Ok(range)
 +        })
 +        .collect();
 +
 +    Ok(Some(res?))
 +}
 +
 +pub(crate) fn handle_matching_brace(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MatchingBraceParams,
 +) -> Result<Vec<Position>> {
 +    let _p = profile::span("handle_matching_brace");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position);
 +            offset.map(|offset| {
 +                let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) {
 +                    Ok(Some(matching_brace_offset)) => matching_brace_offset,
 +                    Err(_) | Ok(None) => offset,
 +                };
 +                to_proto::position(&line_index, offset)
 +            })
 +        })
 +        .collect()
 +}
 +
 +pub(crate) fn handle_join_lines(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::JoinLinesParams,
 +) -> Result<Vec<lsp_types::TextEdit>> {
 +    let _p = profile::span("handle_join_lines");
 +
 +    let config = snap.config.join_lines();
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut res = TextEdit::default();
 +    for range in params.ranges {
 +        let range = from_proto::text_range(&line_index, range)?;
 +        let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?;
 +        match res.union(edit) {
 +            Ok(()) => (),
 +            Err(_edit) => {
 +                // just ignore overlapping edits
 +            }
 +        }
 +    }
 +
 +    Ok(to_proto::text_edit_vec(&line_index, res))
 +}
 +
 +pub(crate) fn handle_on_enter(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_enter");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let edit = match snap.analysis.on_enter(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit);
 +    Ok(Some(edit))
 +}
 +
 +pub(crate) fn handle_on_type_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentOnTypeFormattingParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_type_formatting");
 +    let mut position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    // in `ide`, the `on_type` invariant is that
 +    // `text.char_at(position) == typed_char`.
 +    position.offset -= TextSize::of('.');
 +    let char_typed = params.ch.chars().next().unwrap_or('\0');
 +
 +    let text = snap.analysis.file_text(position.file_id)?;
 +    if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) {
 +        return Ok(None);
 +    }
 +
 +    // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
 +    // but it requires precise cursor positioning to work, and one can't
 +    // position the cursor with on_type formatting. So, let's just toggle this
 +    // feature off here, hoping that we'll enable it one day, 😿.
 +    if char_typed == '>' {
 +        return Ok(None);
 +    }
 +
 +    let edit =
 +        snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?;
 +    let edit = match edit {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    // This should be a single-file edit
 +    let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap();
 +
 +    let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit);
 +    Ok(Some(change))
 +}
 +
 +pub(crate) fn handle_document_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentSymbolParams,
 +) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
 +    let _p = profile::span("handle_document_symbol");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
 +
 +    for symbol in snap.analysis.file_structure(file_id)? {
 +        let mut tags = Vec::new();
 +        if symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        };
 +
 +        #[allow(deprecated)]
 +        let doc_symbol = lsp_types::DocumentSymbol {
 +            name: symbol.label,
 +            detail: symbol.detail,
 +            kind: to_proto::structure_node_kind(symbol.kind),
 +            tags: Some(tags),
 +            deprecated: Some(symbol.deprecated),
 +            range: to_proto::range(&line_index, symbol.node_range),
 +            selection_range: to_proto::range(&line_index, symbol.navigation_range),
 +            children: None,
 +        };
 +        parents.push((doc_symbol, symbol.parent));
 +    }
 +
 +    // Builds hierarchy from a flat list, in reverse order (so that indices
 +    // makes sense)
 +    let document_symbols = {
 +        let mut acc = Vec::new();
 +        while let Some((mut node, parent_idx)) = parents.pop() {
 +            if let Some(children) = &mut node.children {
 +                children.reverse();
 +            }
 +            let parent = match parent_idx {
 +                None => &mut acc,
 +                Some(i) => parents[i].0.children.get_or_insert_with(Vec::new),
 +            };
 +            parent.push(node);
 +        }
 +        acc.reverse();
 +        acc
 +    };
 +
 +    let res = if snap.config.hierarchical_symbols() {
 +        document_symbols.into()
 +    } else {
 +        let url = to_proto::url(&snap, file_id);
 +        let mut symbol_information = Vec::<SymbolInformation>::new();
 +        for symbol in document_symbols {
 +            flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
 +        }
 +        symbol_information.into()
 +    };
 +    return Ok(Some(res));
 +
 +    fn flatten_document_symbol(
 +        symbol: &lsp_types::DocumentSymbol,
 +        container_name: Option<String>,
 +        url: &Url,
 +        res: &mut Vec<SymbolInformation>,
 +    ) {
 +        let mut tags = Vec::new();
 +
 +        #[allow(deprecated)]
 +        if let Some(true) = symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        }
 +
 +        #[allow(deprecated)]
 +        res.push(SymbolInformation {
 +            name: symbol.name.clone(),
 +            kind: symbol.kind,
 +            tags: Some(tags),
 +            deprecated: symbol.deprecated,
 +            location: Location::new(url.clone(), symbol.range),
 +            container_name,
 +        });
 +
 +        for child in symbol.children.iter().flatten() {
 +            flatten_document_symbol(child, Some(symbol.name.clone()), url, res);
 +        }
 +    }
 +}
 +
 +pub(crate) fn handle_workspace_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: WorkspaceSymbolParams,
 +) -> Result<Option<Vec<SymbolInformation>>> {
 +    let _p = profile::span("handle_workspace_symbol");
 +
 +    let config = snap.config.workspace_symbol();
 +    let (all_symbols, libs) = decide_search_scope_and_kind(&params, &config);
 +    let limit = config.search_limit;
 +
 +    let query = {
 +        let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
 +        let mut q = Query::new(query);
 +        if !all_symbols {
 +            q.only_types();
 +        }
 +        if libs {
 +            q.libs();
 +        }
 +        q.limit(limit);
 +        q
 +    };
 +    let mut res = exec_query(&snap, query)?;
 +    if res.is_empty() && !all_symbols {
 +        let mut query = Query::new(params.query);
 +        query.limit(limit);
 +        res = exec_query(&snap, query)?;
 +    }
 +
 +    return Ok(Some(res));
 +
 +    fn decide_search_scope_and_kind(
 +        params: &WorkspaceSymbolParams,
 +        config: &WorkspaceSymbolConfig,
 +    ) -> (bool, bool) {
 +        // Support old-style parsing of markers in the query.
 +        let mut all_symbols = params.query.contains('#');
 +        let mut libs = params.query.contains('*');
 +
 +        // If no explicit marker was set, check request params. If that's also empty
 +        // use global config.
 +        if !all_symbols {
 +            let search_kind = match params.search_kind {
 +                Some(ref search_kind) => search_kind,
 +                None => &config.search_kind,
 +            };
 +            all_symbols = match search_kind {
 +                lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false,
 +                lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true,
 +            }
 +        }
 +
 +        if !libs {
 +            let search_scope = match params.search_scope {
 +                Some(ref search_scope) => search_scope,
 +                None => &config.search_scope,
 +            };
 +            libs = match search_scope {
 +                lsp_ext::WorkspaceSymbolSearchScope::Workspace => false,
 +                lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true,
 +            }
 +        }
 +
 +        (all_symbols, libs)
 +    }
 +
 +    fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
 +        let mut res = Vec::new();
 +        for nav in snap.analysis.symbol_search(query)? {
 +            let container_name = nav.container_name.as_ref().map(|v| v.to_string());
 +
 +            #[allow(deprecated)]
 +            let info = SymbolInformation {
 +                name: nav.name.to_string(),
 +                kind: nav
 +                    .kind
 +                    .map(to_proto::symbol_kind)
 +                    .unwrap_or(lsp_types::SymbolKind::VARIABLE),
 +                tags: None,
 +                location: to_proto::location_from_nav(snap, nav)?,
 +                container_name,
 +                deprecated: None,
 +            };
 +            res.push(info);
 +        }
 +        Ok(res)
 +    }
 +}
 +
 +pub(crate) fn handle_will_rename_files(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::RenameFilesParams,
 +) -> Result<Option<lsp_types::WorkspaceEdit>> {
 +    let _p = profile::span("handle_will_rename_files");
 +
 +    let source_changes: Vec<SourceChange> = params
 +        .files
 +        .into_iter()
 +        .filter_map(|file_rename| {
 +            let from = Url::parse(&file_rename.old_uri).ok()?;
 +            let to = Url::parse(&file_rename.new_uri).ok()?;
 +
 +            let from_path = from.to_file_path().ok()?;
 +            let to_path = to.to_file_path().ok()?;
 +
 +            // Limit to single-level moves for now.
 +            match (from_path.parent(), to_path.parent()) {
 +                (Some(p1), Some(p2)) if p1 == p2 => {
 +                    if from_path.is_dir() {
 +                        // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/`
 +                        let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string();
 +                        old_folder_name.push('/');
 +                        let from_with_trailing_slash = from.join(&old_folder_name).ok()?;
 +
 +                        let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?;
 +                        let new_file_name = to_path.file_name()?.to_str()?;
 +                        Some((
 +                            snap.url_to_file_id(&imitate_from_url).ok()?,
 +                            new_file_name.to_string(),
 +                        ))
 +                    } else {
 +                        let old_name = from_path.file_stem()?.to_str()?;
 +                        let new_name = to_path.file_stem()?.to_str()?;
 +                        match (old_name, new_name) {
 +                            ("mod", _) => None,
 +                            (_, "mod") => None,
 +                            _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())),
 +                        }
 +                    }
 +                }
 +                _ => None,
 +            }
 +        })
 +        .filter_map(|(file_id, new_name)| {
 +            snap.analysis.will_rename_file(file_id, &new_name).ok()?
 +        })
 +        .collect();
 +
 +    // Drop file system edits since we're just renaming things on the same level
 +    let mut source_changes = source_changes.into_iter();
 +    let mut source_change = source_changes.next().unwrap_or_default();
 +    source_change.file_system_edits.clear();
 +    // no collect here because we want to merge text edits on same file ids
 +    source_change.extend(source_changes.flat_map(|it| it.source_file_edits));
 +    if source_change.source_file_edits.is_empty() {
 +        Ok(None)
 +    } else {
 +        to_proto::workspace_edit(&snap, source_change).map(Some)
 +    }
 +}
 +
 +pub(crate) fn handle_goto_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::GotoDefinitionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_declaration(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoDeclarationParams,
 +) -> Result<Option<lsp_types::request::GotoDeclarationResponse>> {
 +    let _p = profile::span("handle_goto_declaration");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?;
 +    let nav_info = match snap.analysis.goto_declaration(position)? {
 +        None => return handle_goto_definition(snap, params),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_implementation(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoImplementationParams,
 +) -> Result<Option<lsp_types::request::GotoImplementationResponse>> {
 +    let _p = profile::span("handle_goto_implementation");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_implementation(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_type_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoTypeDefinitionParams,
 +) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_type_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_type_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_parent_module(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_parent_module");
 +    if let Ok(file_path) = &params.text_document.uri.to_file_path() {
 +        if file_path.file_name().unwrap_or_default() == "Cargo.toml" {
 +            // search workspaces for parent packages or fallback to workspace root
 +            let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() {
 +                Some(abs_path_buf) => abs_path_buf,
 +                None => return Ok(None),
 +            };
 +
 +            let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() {
 +                Some(manifest_path) => manifest_path,
 +                None => return Ok(None),
 +            };
 +
 +            let links: Vec<LocationLink> = snap
 +                .workspaces
 +                .iter()
 +                .filter_map(|ws| match ws {
 +                    ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
 +                    _ => None,
 +                })
 +                .flatten()
 +                .map(|parent_manifest_path| LocationLink {
 +                    origin_selection_range: None,
 +                    target_uri: to_proto::url_from_abs_path(&parent_manifest_path),
 +                    target_range: Range::default(),
 +                    target_selection_range: Range::default(),
 +                })
 +                .collect::<_>();
 +            return Ok(Some(links.into()));
 +        }
 +
 +        // check if invoked at the crate root
 +        let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +        let crate_id = match snap.analysis.crate_for(file_id)?.first() {
 +            Some(&crate_id) => crate_id,
 +            None => return Ok(None),
 +        };
 +        let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +            Some(it) => it,
 +            None => return Ok(None),
 +        };
 +
 +        if snap.analysis.crate_root(crate_id)? == file_id {
 +            let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +            let res = vec![LocationLink {
 +                origin_selection_range: None,
 +                target_uri: cargo_toml_url,
 +                target_range: Range::default(),
 +                target_selection_range: Range::default(),
 +            }]
 +            .into();
 +            return Ok(Some(res));
 +        }
 +    }
 +
 +    // locate parent module by semantics
 +    let position = from_proto::file_position(&snap, params)?;
 +    let navs = snap.analysis.parent_module(position)?;
 +    let res = to_proto::goto_definition_response(&snap, None, navs)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_runnables(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::RunnablesParams,
 +) -> Result<Vec<lsp_ext::Runnable>> {
 +    let _p = profile::span("handle_runnables");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
 +    let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let expect_test = match offset {
 +        Some(offset) => {
 +            let source_file = snap.analysis.parse(file_id)?;
 +            algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
 +                .and_then(|it| it.path()?.segment()?.name_ref())
 +                .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
 +        }
 +        None => false,
 +    };
 +
 +    let mut res = Vec::new();
 +    for runnable in snap.analysis.runnables(file_id)? {
 +        if should_skip_for_offset(&runnable, offset) {
 +            continue;
 +        }
 +        if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +            continue;
 +        }
 +        let mut runnable = to_proto::runnable(&snap, runnable)?;
 +        if expect_test {
 +            runnable.label = format!("{} + expect", runnable.label);
 +            runnable.args.expect_test = Some(true);
 +        }
 +        res.push(runnable);
 +    }
 +
 +    // Add `cargo check` and `cargo test` for all targets of the whole package
 +    let config = snap.config.runnables();
 +    match cargo_spec {
 +        Some(spec) => {
 +            for cmd in ["check", "test"] {
 +                res.push(lsp_ext::Runnable {
 +                    label: format!("cargo {} -p {} --all-targets", cmd, spec.package),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: Some(spec.workspace_root.clone().into()),
 +                        override_cargo: config.override_cargo.clone(),
 +                        cargo_args: vec![
 +                            cmd.to_string(),
 +                            "--package".to_string(),
 +                            spec.package.clone(),
 +                            "--all-targets".to_string(),
 +                        ],
 +                        cargo_extra_args: config.cargo_extra_args.clone(),
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                })
 +            }
 +        }
 +        None => {
 +            if !snap.config.linked_projects().is_empty()
 +                || !snap
 +                    .config
 +                    .discovered_projects
 +                    .as_ref()
 +                    .map(|projects| projects.is_empty())
 +                    .unwrap_or(true)
 +            {
 +                res.push(lsp_ext::Runnable {
 +                    label: "cargo check --workspace".to_string(),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: None,
 +                        override_cargo: config.override_cargo,
 +                        cargo_args: vec!["check".to_string(), "--workspace".to_string()],
 +                        cargo_extra_args: config.cargo_extra_args,
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                });
 +            }
 +        }
 +    }
 +    Ok(res)
 +}
 +
 +fn should_skip_for_offset(runnable: &Runnable, offset: Option<TextSize>) -> bool {
 +    match offset {
 +        None => false,
 +        _ if matches!(&runnable.kind, RunnableKind::TestMod { .. }) => false,
 +        Some(offset) => !runnable.nav.full_range.contains_inclusive(offset),
 +    }
 +}
 +
 +pub(crate) fn handle_related_tests(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Vec<lsp_ext::TestInfo>> {
 +    let _p = profile::span("handle_related_tests");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let tests = snap.analysis.related_tests(position, None)?;
 +    let mut res = Vec::new();
 +    for it in tests {
 +        if let Ok(runnable) = to_proto::runnable(&snap, it) {
 +            res.push(lsp_ext::TestInfo { runnable })
 +        }
 +    }
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_completion(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CompletionParams,
 +) -> Result<Option<lsp_types::CompletionResponse>> {
 +    let _p = profile::span("handle_completion");
 +    let text_document_position = params.text_document_position.clone();
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let completion_trigger_character =
 +        params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 +
 +    if Some(':') == completion_trigger_character {
 +        let source_file = snap.analysis.parse(position.file_id)?;
 +        let left_token = source_file.syntax().token_at_offset(position.offset).left_biased();
 +        let completion_triggered_after_single_colon = match left_token {
 +            Some(left_token) => left_token.kind() == T![:],
 +            None => true,
 +        };
 +        if completion_triggered_after_single_colon {
 +            return Ok(None);
 +        }
 +    }
 +
 +    let completion_config = &snap.config.completion();
 +    let items = match snap.analysis.completions(
 +        completion_config,
 +        position,
 +        completion_trigger_character,
 +    )? {
 +        None => return Ok(None),
 +        Some(items) => items,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let items =
 +        to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
 +
 +    let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
 +    Ok(Some(completion_list.into()))
 +}
 +
 +pub(crate) fn handle_completion_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut original_completion: CompletionItem,
 +) -> Result<CompletionItem> {
 +    let _p = profile::span("handle_completion_resolve");
 +
 +    if !all_edits_are_disjoint(&original_completion, &[]) {
 +        return Err(invalid_params_error(
 +            "Received a completion with overlapping edits, this is not LSP-compliant".to_string(),
 +        )
 +        .into());
 +    }
 +
 +    let data = match original_completion.data.take() {
 +        Some(it) => it,
 +        None => return Ok(original_completion),
 +    };
 +
 +    let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 +
 +    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
 +
 +    let additional_edits = snap
 +        .analysis
 +        .resolve_completion_edits(
 +            &snap.config.completion(),
 +            FilePosition { file_id, offset },
 +            resolve_data
 +                .imports
 +                .into_iter()
 +                .map(|import| (import.full_import_path, import.imported_name)),
 +        )?
 +        .into_iter()
 +        .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
 +        .collect::<Vec<_>>();
 +
 +    if !all_edits_are_disjoint(&original_completion, &additional_edits) {
 +        return Err(LspError::new(
 +            ErrorCode::InternalError as i32,
 +            "Import edit overlaps with the original completion edits, this is not LSP-compliant"
 +                .into(),
 +        )
 +        .into());
 +    }
 +
 +    if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
 +        original_additional_edits.extend(additional_edits.into_iter())
 +    } else {
 +        original_completion.additional_text_edits = Some(additional_edits);
 +    }
 +
 +    Ok(original_completion)
 +}
 +
 +pub(crate) fn handle_folding_range(
 +    snap: GlobalStateSnapshot,
 +    params: FoldingRangeParams,
 +) -> Result<Option<Vec<FoldingRange>>> {
 +    let _p = profile::span("handle_folding_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let folds = snap.analysis.folding_ranges(file_id)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let line_folding_only = snap.config.line_folding_only();
 +    let res = folds
 +        .into_iter()
 +        .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_signature_help(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SignatureHelpParams,
 +) -> Result<Option<lsp_types::SignatureHelp>> {
 +    let _p = profile::span("handle_signature_help");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let help = match snap.analysis.signature_help(position)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +    let config = snap.config.call_info();
 +    let res = to_proto::signature_help(help, config, snap.config.signature_help_label_offsets());
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_hover(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::HoverParams,
 +) -> Result<Option<lsp_ext::Hover>> {
 +    let _p = profile::span("handle_hover");
 +    let range = match params.position {
 +        PositionOrRange::Position(position) => Range::new(position, position),
 +        PositionOrRange::Range(range) => range,
 +    };
 +
 +    let file_range = from_proto::file_range(&snap, params.text_document, range)?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(None),
 +        Some(info) => info,
 +    };
 +
 +    let line_index = snap.file_line_index(file_range.file_id)?;
 +    let range = to_proto::range(&line_index, info.range);
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +    let hover = lsp_ext::Hover {
 +        hover: lsp_types::Hover {
 +            contents: HoverContents::Markup(to_proto::markup_content(
 +                info.info.markup,
 +                markup_kind,
 +            )),
 +            range: Some(range),
 +        },
 +        actions: if snap.config.hover_actions().none() {
 +            Vec::new()
 +        } else {
 +            prepare_hover_actions(&snap, &info.info.actions)
 +        },
 +    };
 +
 +    Ok(Some(hover))
 +}
 +
 +pub(crate) fn handle_prepare_rename(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<PrepareRenameResponse>> {
 +    let _p = profile::span("handle_prepare_rename");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
 +
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let range = to_proto::range(&line_index, change.range);
 +    Ok(Some(PrepareRenameResponse::Range(range)))
 +}
 +
 +pub(crate) fn handle_rename(
 +    snap: GlobalStateSnapshot,
 +    params: RenameParams,
 +) -> Result<Option<WorkspaceEdit>> {
 +    let _p = profile::span("handle_rename");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
 +    let mut change =
 +        snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?;
 +
 +    // this is kind of a hack to prevent double edits from happening when moving files
 +    // When a module gets renamed by renaming the mod declaration this causes the file to move
 +    // which in turn will trigger a WillRenameFiles request to the server for which we reply with a
 +    // a second identical set of renames, the client will then apply both edits causing incorrect edits
 +    // with this we only emit source_file_edits in the WillRenameFiles response which will do the rename instead
 +    // See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
 +    if !change.file_system_edits.is_empty() && snap.config.will_rename() {
 +        change.source_file_edits.clear();
 +    }
 +    let workspace_edit = to_proto::workspace_edit(&snap, change)?;
 +    Ok(Some(workspace_edit))
 +}
 +
 +pub(crate) fn handle_references(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::ReferenceParams,
 +) -> Result<Option<Vec<Location>>> {
 +    let _p = profile::span("handle_references");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
++    let exclude_imports = snap.config.find_all_refs_exclude_imports();
++
 +    let refs = match snap.analysis.find_all_refs(position, None)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +
 +    let include_declaration = params.context.include_declaration;
 +    let locations = refs
 +        .into_iter()
 +        .flat_map(|refs| {
 +            let decl = if include_declaration {
 +                refs.declaration.map(|decl| FileRange {
 +                    file_id: decl.nav.file_id,
 +                    range: decl.nav.focus_or_full_range(),
 +                })
 +            } else {
 +                None
 +            };
 +            refs.references
 +                .into_iter()
 +                .flat_map(|(file_id, refs)| {
-             kind: category.map(to_proto::document_highlight_kind),
++                    refs.into_iter()
++                        .filter(|&(_, category)| {
++                            !exclude_imports || category != Some(ReferenceCategory::Import)
++                        })
++                        .map(move |(range, _)| FileRange { file_id, range })
 +                })
 +                .chain(decl)
 +        })
 +        .filter_map(|frange| to_proto::location(&snap, frange).ok())
 +        .collect();
 +
 +    Ok(Some(locations))
 +}
 +
 +pub(crate) fn handle_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: DocumentFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, None)
 +}
 +
 +pub(crate) fn handle_range_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentRangeFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_range_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, Some(params.range))
 +}
 +
 +pub(crate) fn handle_code_action(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeActionParams,
 +) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
 +    let _p = profile::span("handle_code_action");
 +
 +    if !snap.config.code_action_literals() {
 +        // We intentionally don't support command-based actions, as those either
 +        // require either custom client-code or server-initiated edits. Server
 +        // initiated edits break causality, so we avoid those.
 +        return Ok(None);
 +    }
 +
 +    let line_index =
 +        snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
 +    let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .context
 +        .only
 +        .clone()
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
 +
 +    let code_action_resolve_cap = snap.config.code_action_resolve();
 +    let resolve = if code_action_resolve_cap {
 +        AssistResolveStrategy::None
 +    } else {
 +        AssistResolveStrategy::All
 +    };
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        resolve,
 +        frange,
 +    )?;
 +    for (index, assist) in assists.into_iter().enumerate() {
 +        let resolve_data =
 +            if code_action_resolve_cap { Some((index, params.clone())) } else { None };
 +        let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
 +        res.push(code_action)
 +    }
 +
 +    // Fixes from `cargo check`.
 +    for fix in
 +        snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten()
 +    {
 +        // FIXME: this mapping is awkward and shouldn't exist. Refactor
 +        // `snap.check_fixes` to not convert to LSP prematurely.
 +        let intersect_fix_range = fix
 +            .ranges
 +            .iter()
 +            .copied()
 +            .filter_map(|range| from_proto::text_range(&line_index, range).ok())
 +            .any(|fix_range| fix_range.intersect(frange.range).is_some());
 +        if intersect_fix_range {
 +            res.push(fix.action.clone());
 +        }
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_action_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut code_action: lsp_ext::CodeAction,
 +) -> Result<lsp_ext::CodeAction> {
 +    let _p = profile::span("handle_code_action_resolve");
 +    let params = match code_action.data.take() {
 +        Some(it) => it,
 +        None => return Err(invalid_params_error("code action without data".to_string()).into()),
 +    };
 +
 +    let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
 +    let frange = FileRange { file_id, range };
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .code_action_params
 +        .context
 +        .only
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let (assist_index, assist_resolve) = match parse_action_id(&params.id) {
 +        Ok(parsed_data) => parsed_data,
 +        Err(e) => {
 +            return Err(invalid_params_error(format!(
 +                "Failed to parse action id string '{}': {}",
 +                params.id, e
 +            ))
 +            .into())
 +        }
 +    };
 +
 +    let expected_assist_id = assist_resolve.assist_id.clone();
 +    let expected_kind = assist_resolve.assist_kind;
 +
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        AssistResolveStrategy::Single(assist_resolve),
 +        frange,
 +    )?;
 +
 +    let assist = match assists.get(assist_index) {
 +        Some(assist) => assist,
 +        None => return Err(invalid_params_error(format!(
 +            "Failed to find the assist for index {} provided by the resolve request. Resolve request assist id: {}",
 +            assist_index, params.id,
 +        ))
 +        .into())
 +    };
 +    if assist.id.0 != expected_assist_id || assist.id.1 != expected_kind {
 +        return Err(invalid_params_error(format!(
 +            "Mismatching assist at index {} for the resolve parameters given. Resolve request assist id: {}, actual id: {:?}.",
 +            assist_index, params.id, assist.id
 +        ))
 +        .into());
 +    }
 +    let ca = to_proto::code_action(&snap, assist.clone(), None)?;
 +    code_action.edit = ca.edit;
 +    code_action.command = ca.command;
 +    Ok(code_action)
 +}
 +
 +fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> {
 +    let id_parts = action_id.split(':').collect::<Vec<_>>();
 +    match id_parts.as_slice() {
 +        [assist_id_string, assist_kind_string, index_string] => {
 +            let assist_kind: AssistKind = assist_kind_string.parse()?;
 +            let index: usize = match index_string.parse() {
 +                Ok(index) => index,
 +                Err(e) => return Err(format!("Incorrect index string: {}", e)),
 +            };
 +            Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind }))
 +        }
 +        _ => Err("Action id contains incorrect number of segments".to_string()),
 +    }
 +}
 +
 +pub(crate) fn handle_code_lens(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeLensParams,
 +) -> Result<Option<Vec<CodeLens>>> {
 +    let _p = profile::span("handle_code_lens");
 +
 +    let lens_config = snap.config.lens();
 +    if lens_config.none() {
 +        // early return before any db query!
 +        return Ok(Some(Vec::default()));
 +    }
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let annotations = snap.analysis.annotations(
 +        &AnnotationConfig {
 +            binary_target: cargo_target_spec
 +                .map(|spec| {
 +                    matches!(
 +                        spec.target_kind,
 +                        TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                    )
 +                })
 +                .unwrap_or(false),
 +            annotate_runnables: lens_config.runnable(),
 +            annotate_impls: lens_config.implementations,
 +            annotate_references: lens_config.refs_adt,
 +            annotate_method_references: lens_config.method_refs,
 +            annotate_enum_variant_references: lens_config.enum_variant_refs,
++            location: lens_config.location.into(),
 +        },
 +        file_id,
 +    )?;
 +
 +    let mut res = Vec::new();
 +    for a in annotations {
 +        to_proto::code_lens(&mut res, &snap, a)?;
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_lens_resolve(
 +    snap: GlobalStateSnapshot,
 +    code_lens: CodeLens,
 +) -> Result<CodeLens> {
 +    let annotation = from_proto::annotation(&snap, code_lens.clone())?;
 +    let annotation = snap.analysis.resolve_annotation(annotation)?;
 +
 +    let mut acc = Vec::new();
 +    to_proto::code_lens(&mut acc, &snap, annotation)?;
 +
 +    let res = match acc.pop() {
 +        Some(it) if acc.is_empty() => it,
 +        _ => {
 +            never!();
 +            code_lens
 +        }
 +    };
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_document_highlight(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentHighlightParams,
 +) -> Result<Option<Vec<lsp_types::DocumentHighlight>>> {
 +    let _p = profile::span("handle_document_highlight");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let refs = match snap.analysis.highlight_related(snap.config.highlight_related(), position)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +    let res = refs
 +        .into_iter()
 +        .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight {
 +            range: to_proto::range(&line_index, range),
++            kind: category.and_then(to_proto::document_highlight_kind),
 +        })
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_ssr(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SsrParams,
 +) -> Result<lsp_types::WorkspaceEdit> {
 +    let _p = profile::span("handle_ssr");
 +    let selections = params
 +        .selections
 +        .iter()
 +        .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range))
 +        .collect::<Result<Vec<_>, _>>()?;
 +    let position = from_proto::file_position(&snap, params.position)?;
 +    let source_change = snap.analysis.structural_search_replace(
 +        &params.query,
 +        params.parse_only,
 +        position,
 +        selections,
 +    )??;
 +    to_proto::workspace_edit(&snap, source_change)
 +}
 +
 +pub(crate) fn publish_diagnostics(
 +    snap: &GlobalStateSnapshot,
 +    file_id: FileId,
 +) -> Result<Vec<Diagnostic>> {
 +    let _p = profile::span("publish_diagnostics");
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let diagnostics: Vec<Diagnostic> = snap
 +        .analysis
 +        .diagnostics(&snap.config.diagnostics(), AssistResolveStrategy::None, file_id)?
 +        .into_iter()
 +        .map(|d| Diagnostic {
 +            range: to_proto::range(&line_index, d.range),
 +            severity: Some(to_proto::diagnostic_severity(d.severity)),
 +            code: Some(NumberOrString::String(d.code.as_str().to_string())),
 +            code_description: Some(lsp_types::CodeDescription {
 +                href: lsp_types::Url::parse(&format!(
 +                    "https://rust-analyzer.github.io/manual.html#{}",
 +                    d.code.as_str()
 +                ))
 +                .unwrap(),
 +            }),
 +            source: Some("rust-analyzer".to_string()),
 +            message: d.message,
 +            related_information: None,
 +            tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None },
 +            data: None,
 +        })
 +        .collect();
 +    Ok(diagnostics)
 +}
 +
 +pub(crate) fn handle_inlay_hints(
 +    snap: GlobalStateSnapshot,
 +    params: InlayHintParams,
 +) -> Result<Option<Vec<InlayHint>>> {
 +    let _p = profile::span("handle_inlay_hints");
 +    let document_uri = &params.text_document.uri;
 +    let file_id = from_proto::file_id(&snap, document_uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::file_range(
 +        &snap,
 +        TextDocumentIdentifier::new(document_uri.to_owned()),
 +        params.range,
 +    )?;
 +    let inlay_hints_config = snap.config.inlay_hints();
 +    Ok(Some(
 +        snap.analysis
 +            .inlay_hints(&inlay_hints_config, file_id, Some(range))?
 +            .into_iter()
 +            .map(|it| {
 +                to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
 +            })
 +            .collect::<Result<Vec<_>>>()?,
 +    ))
 +}
 +
 +pub(crate) fn handle_inlay_hints_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut hint: InlayHint,
 +) -> Result<InlayHint> {
 +    let _p = profile::span("handle_inlay_hints_resolve");
 +    let data = match hint.data.take() {
 +        Some(it) => it,
 +        None => return Ok(hint),
 +    };
 +
 +    let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
 +
 +    let file_range = from_proto::file_range(
 +        &snap,
 +        resolve_data.text_document,
 +        match resolve_data.position {
 +            PositionOrRange::Position(pos) => Range::new(pos, pos),
 +            PositionOrRange::Range(range) => range,
 +        },
 +    )?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(hint),
 +        Some(info) => info,
 +    };
 +
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +
 +    // FIXME: hover actions?
 +    hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content(
 +        info.info.markup,
 +        markup_kind,
 +    )));
 +    Ok(hint)
 +}
 +
 +pub(crate) fn handle_call_hierarchy_prepare(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyPrepareParams,
 +) -> Result<Option<Vec<CallHierarchyItem>>> {
 +    let _p = profile::span("handle_call_hierarchy_prepare");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +
 +    let nav_info = match snap.analysis.call_hierarchy(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let RangeInfo { range: _, info: navs } = nav_info;
 +    let res = navs
 +        .into_iter()
 +        .filter(|it| it.kind == Some(SymbolKind::Function))
 +        .map(|it| to_proto::call_hierarchy_item(&snap, it))
 +        .collect::<Result<Vec<_>>>()?;
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_incoming(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyIncomingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyIncomingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_incoming");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.incoming_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyIncomingCall {
 +            from: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_outgoing(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyOutgoingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_outgoing");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.outgoing_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyOutgoingCall {
 +            to: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensParams,
 +) -> Result<Option<SemanticTokensResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut highlight_config = snap.config.highlighting_config();
 +    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
 +    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
 +
 +    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    // Unconditionally cache the tokens
 +    snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone());
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full_delta(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensDeltaParams,
 +) -> Result<Option<SemanticTokensFullDeltaResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full_delta");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut highlight_config = snap.config.highlighting_config();
 +    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
 +    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
 +
 +    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    let mut cache = snap.semantic_tokens_cache.lock();
 +    let cached_tokens = cache.entry(params.text_document.uri).or_default();
 +
 +    if let Some(prev_id) = &cached_tokens.result_id {
 +        if *prev_id == params.previous_result_id {
 +            let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens);
 +            *cached_tokens = semantic_tokens;
 +            return Ok(Some(delta.into()));
 +        }
 +    }
 +
 +    *cached_tokens = semantic_tokens.clone();
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_range(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensRangeParams,
 +) -> Result<Option<SemanticTokensRangeResult>> {
 +    let _p = profile::span("handle_semantic_tokens_range");
 +
 +    let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
 +    let text = snap.analysis.file_text(frange.file_id)?;
 +    let line_index = snap.file_line_index(frange.file_id)?;
 +
 +    let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_open_docs(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::Url>> {
 +    let _p = profile::span("handle_open_docs");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let remote = snap.analysis.external_docs(position)?;
 +
 +    Ok(remote.and_then(|remote| Url::parse(&remote).ok()))
 +}
 +
 +pub(crate) fn handle_open_cargo_toml(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::OpenCargoTomlParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_open_cargo_toml");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +
 +    let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +    let res: lsp_types::GotoDefinitionResponse =
 +        Location::new(cargo_toml_url, Range::default()).into();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_move_item(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MoveItemParams,
 +) -> Result<Vec<lsp_ext::SnippetTextEdit>> {
 +    let _p = profile::span("handle_move_item");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let range = from_proto::file_range(&snap, params.text_document, params.range)?;
 +
 +    let direction = match params.direction {
 +        lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
 +        lsp_ext::MoveItemDirection::Down => ide::Direction::Down,
 +    };
 +
 +    match snap.analysis.move_item(range, direction)? {
 +        Some(text_edit) => {
 +            let line_index = snap.file_line_index(file_id)?;
 +            Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit))
 +        }
 +        None => Ok(vec![]),
 +    }
 +}
 +
 +fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink {
 +    lsp_ext::CommandLink { tooltip: Some(tooltip), command }
 +}
 +
 +fn show_impl_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
 +        if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = nav_data
 +                .info
 +                .into_iter()
 +                .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
 +                .collect();
 +            let title = to_proto::implementation_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to implementations".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn show_ref_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
 +        if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = ref_search_res
 +                .into_iter()
 +                .flat_map(|res| res.references)
 +                .flat_map(|(file_id, ranges)| {
 +                    ranges.into_iter().filter_map(move |(range, _)| {
 +                        to_proto::location(snap, FileRange { file_id, range }).ok()
 +                    })
 +                })
 +                .collect();
 +            let title = to_proto::reference_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to references".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn runnable_action_links(
 +    snap: &GlobalStateSnapshot,
 +    runnable: Runnable,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    let hover_actions_config = snap.config.hover_actions();
 +    if !hover_actions_config.runnable() {
 +        return None;
 +    }
 +
 +    let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
 +    if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +        return None;
 +    }
 +
 +    let client_commands_config = snap.config.client_commands();
 +    if !(client_commands_config.run_single || client_commands_config.debug_single) {
 +        return None;
 +    }
 +
 +    let title = runnable.title();
 +    let r = to_proto::runnable(snap, runnable).ok()?;
 +
 +    let mut group = lsp_ext::CommandLinkGroup::default();
 +
 +    if hover_actions_config.run && client_commands_config.run_single {
 +        let run_command = to_proto::command::run_single(&r, &title);
 +        group.commands.push(to_command_link(run_command, r.label.clone()));
 +    }
 +
 +    if hover_actions_config.debug && client_commands_config.debug_single {
 +        let dbg_command = to_proto::command::debug_single(&r);
 +        group.commands.push(to_command_link(dbg_command, r.label));
 +    }
 +
 +    Some(group)
 +}
 +
 +fn goto_type_action_links(
 +    snap: &GlobalStateSnapshot,
 +    nav_targets: &[HoverGotoTypeData],
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if !snap.config.hover_actions().goto_type_def
 +        || nav_targets.is_empty()
 +        || !snap.config.client_commands().goto_location
 +    {
 +        return None;
 +    }
 +
 +    Some(lsp_ext::CommandLinkGroup {
 +        title: Some("Go to ".into()),
 +        commands: nav_targets
 +            .iter()
 +            .filter_map(|it| {
 +                to_proto::command::goto_location(snap, &it.nav)
 +                    .map(|cmd| to_command_link(cmd, it.mod_path.clone()))
 +            })
 +            .collect(),
 +    })
 +}
 +
 +fn prepare_hover_actions(
 +    snap: &GlobalStateSnapshot,
 +    actions: &[HoverAction],
 +) -> Vec<lsp_ext::CommandLinkGroup> {
 +    actions
 +        .iter()
 +        .filter_map(|it| match it {
 +            HoverAction::Implementation(position) => show_impl_command_link(snap, position),
 +            HoverAction::Reference(position) => show_ref_command_link(snap, position),
 +            HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()),
 +            HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
 +        })
 +        .collect()
 +}
 +
 +fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
 +    match runnable.kind {
 +        RunnableKind::Bin => {
 +            // Do not suggest binary run on other target than binary
 +            match &cargo_spec {
 +                Some(spec) => !matches!(
 +                    spec.target_kind,
 +                    TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                ),
 +                None => true,
 +            }
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn run_rustfmt(
 +    snap: &GlobalStateSnapshot,
 +    text_document: TextDocumentIdentifier,
 +    range: Option<lsp_types::Range>,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let file_id = from_proto::file_id(snap, &text_document.uri)?;
 +    let file = snap.analysis.file_text(file_id)?;
 +    let crate_ids = snap.analysis.crate_for(file_id)?;
 +
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut command = match snap.config.rustfmt() {
 +        RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
 +            let mut cmd = process::Command::new(toolchain::rustfmt());
++            cmd.envs(snap.config.extra_env());
 +            cmd.args(extra_args);
 +            // try to chdir to the file so we can respect `rustfmt.toml`
 +            // FIXME: use `rustfmt --config-path` once
 +            // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
 +            match text_document.uri.to_file_path() {
 +                Ok(mut path) => {
 +                    // pop off file name
 +                    if path.pop() && path.is_dir() {
 +                        cmd.current_dir(path);
 +                    }
 +                }
 +                Err(_) => {
 +                    tracing::error!(
 +                        "Unable to get file path for {}, rustfmt.toml might be ignored",
 +                        text_document.uri
 +                    );
 +                }
 +            }
 +            if let Some(&crate_id) = crate_ids.first() {
 +                // Assume all crates are in the same edition
 +                let edition = snap.analysis.crate_edition(crate_id)?;
 +                cmd.arg("--edition");
 +                cmd.arg(edition.to_string());
 +            }
 +
 +            if let Some(range) = range {
 +                if !enable_range_formatting {
 +                    return Err(LspError::new(
 +                        ErrorCode::InvalidRequest as i32,
 +                        String::from(
 +                            "rustfmt range formatting is unstable. \
 +                            Opt-in by using a nightly build of rustfmt and setting \
 +                            `rustfmt.rangeFormatting.enable` to true in your LSP configuration",
 +                        ),
 +                    )
 +                    .into());
 +                }
 +
 +                let frange = from_proto::file_range(snap, text_document, range)?;
 +                let start_line = line_index.index.line_col(frange.range.start()).line;
 +                let end_line = line_index.index.line_col(frange.range.end()).line;
 +
 +                cmd.arg("--unstable-features");
 +                cmd.arg("--file-lines");
 +                cmd.arg(
 +                    json!([{
 +                        "file": "stdin",
 +                        "range": [start_line, end_line]
 +                    }])
 +                    .to_string(),
 +                );
 +            }
 +
 +            cmd
 +        }
 +        RustfmtConfig::CustomCommand { command, args } => {
 +            let mut cmd = process::Command::new(command);
++            cmd.envs(snap.config.extra_env());
 +            cmd.args(args);
 +            cmd
 +        }
 +    };
 +
 +    let mut rustfmt = command
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .context(format!("Failed to spawn {:?}", command))?;
 +
 +    rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
 +
 +    let output = rustfmt.wait_with_output()?;
 +    let captured_stdout = String::from_utf8(output.stdout)?;
 +    let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
 +
 +    if !output.status.success() {
 +        let rustfmt_not_installed =
 +            captured_stderr.contains("not installed") || captured_stderr.contains("not available");
 +
 +        return match output.status.code() {
 +            Some(1) if !rustfmt_not_installed => {
 +                // While `rustfmt` doesn't have a specific exit code for parse errors this is the
 +                // likely cause exiting with 1. Most Language Servers swallow parse errors on
 +                // formatting because otherwise an error is surfaced to the user on top of the
 +                // syntax error diagnostics they're already receiving. This is especially jarring
 +                // if they have format on save enabled.
 +                tracing::warn!(
 +                    ?command,
 +                    %captured_stderr,
 +                    "rustfmt exited with status 1"
 +                );
 +                Ok(None)
 +            }
 +            _ => {
 +                // Something else happened - e.g. `rustfmt` is missing or caught a signal
 +                Err(LspError::new(
 +                    -32900,
 +                    format!(
 +                        r#"rustfmt exited with:
 +                           Status: {}
 +                           stdout: {}
 +                           stderr: {}"#,
 +                        output.status, captured_stdout, captured_stderr,
 +                    ),
 +                )
 +                .into())
 +            }
 +        };
 +    }
 +
 +    let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
 +
 +    if line_index.endings != new_line_endings {
 +        // If line endings are different, send the entire file.
 +        // Diffing would not work here, as the line endings might be the only
 +        // difference.
 +        Ok(Some(to_proto::text_edit_vec(
 +            &line_index,
 +            TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text),
 +        )))
 +    } else if *file == new_text {
 +        // The document is already formatted correctly -- no edits needed.
 +        Ok(None)
 +    } else {
 +        Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text))))
 +    }
 +}
index e49a98685a7f11302fbaff40afe55d36c3719355,0000000000000000000000000000000000000000..96b1cb6b12713d5f0c666d8791cdb890a1d20e43
mode 100644,000000..100644
--- /dev/null
@@@ -1,196 -1,0 +1,198 @@@
 +//! Fully integrated benchmarks for rust-analyzer, which load real cargo
 +//! projects.
 +//!
 +//! The benchmark here is used to debug specific performance regressions. If you
 +//! notice that, eg, completion is slow in some specific case, you can  modify
 +//! code here exercise this specific completion, and thus have a fast
 +//! edit/compile/test cycle.
 +//!
 +//! Note that "rust-analyzer: Run" action does not allow running a single test
 +//! 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 std::sync::Arc;
 +
 +use ide::{CallableSnippets, Change, CompletionConfig, FilePosition, TextSize};
 +use ide_db::{
 +    imports::insert_use::{ImportGranularity, InsertUseConfig},
 +    SnippetCap,
 +};
 +use project_model::CargoConfig;
 +use test_utils::project_root;
 +use vfs::{AbsPathBuf, VfsPath};
 +
 +use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
 +
 +#[test]
 +fn integrated_highlighting_benchmark() {
 +    if std::env::var("RUN_SLOW_BENCHES").is_err() {
 +        return;
 +    }
 +
 +    // Load rust-analyzer itself.
 +    let workspace_to_load = project_root();
 +    let file = "./crates/ide-db/src/apply_change.rs";
 +
 +    let cargo_config = CargoConfig::default();
 +    let load_cargo_config = LoadCargoConfig {
 +        load_out_dirs_from_check: true,
 +        with_proc_macro: false,
 +        prefill_caches: false,
 +    };
 +
 +    let (mut host, vfs, _proc_macro) = {
 +        let _it = stdx::timeit("workspace loading");
 +        load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
 +    };
 +
 +    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 _it = stdx::timeit("initial");
 +        let analysis = host.analysis();
 +        analysis.highlight_as_html(file_id, false).unwrap();
 +    }
 +
 +    profile::init_from("*>100");
 +    // let _s = profile::heartbeat_span();
 +
 +    {
 +        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();
 +        change.change_file(file_id, Some(Arc::new(text)));
 +        host.apply_change(change);
 +    }
 +
 +    {
 +        let _it = stdx::timeit("after change");
 +        let _span = profile::cpu_span();
 +        let analysis = host.analysis();
 +        analysis.highlight_as_html(file_id, false).unwrap();
 +    }
 +}
 +
 +#[test]
 +fn integrated_completion_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::default();
 +    let load_cargo_config = LoadCargoConfig {
 +        load_out_dirs_from_check: true,
 +        with_proc_macro: false,
 +        prefill_caches: true,
 +    };
 +
 +    let (mut host, vfs, _proc_macro) = {
 +        let _it = stdx::timeit("workspace loading");
 +        load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
 +    };
 +
 +    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 _it = stdx::timeit("initial");
 +        let analysis = host.analysis();
 +        analysis.highlight_as_html(file_id, false).unwrap();
 +    }
 +
 +    profile::init_from("*>5");
 +    // let _s = profile::heartbeat_span();
 +
 +    let completion_offset = {
 +        let _it = stdx::timeit("change");
 +        let mut text = host.analysis().file_text(file_id).unwrap().to_string();
 +        let completion_offset =
 +            patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
 +                + "sel".len();
 +        let mut change = Change::new();
 +        change.change_file(file_id, Some(Arc::new(text)));
 +        host.apply_change(change);
 +        completion_offset
 +    };
 +
 +    {
 +        let _p = profile::span("unqualified path completion");
 +        let _span = profile::cpu_span();
 +        let analysis = host.analysis();
 +        let config = CompletionConfig {
 +            enable_postfix_completions: true,
 +            enable_imports_on_the_fly: true,
 +            enable_self_on_the_fly: true,
 +            enable_private_editable: true,
 +            callable: Some(CallableSnippets::FillArguments),
 +            snippet_cap: SnippetCap::new(true),
 +            insert_use: InsertUseConfig {
 +                granularity: ImportGranularity::Crate,
 +                prefix_kind: hir::PrefixKind::ByCrate,
 +                enforce_granularity: true,
 +                group: true,
 +                skip_glob_imports: true,
 +            },
 +            snippets: Vec::new(),
++            prefer_no_std: false,
 +        };
 +        let position =
 +            FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
 +        analysis.completions(&config, position, None).unwrap();
 +    }
 +
 +    let completion_offset = {
 +        let _it = stdx::timeit("change");
 +        let mut text = host.analysis().file_text(file_id).unwrap().to_string();
 +        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();
 +        change.change_file(file_id, Some(Arc::new(text)));
 +        host.apply_change(change);
 +        completion_offset
 +    };
 +
 +    {
 +        let _p = profile::span("dot completion");
 +        let _span = profile::cpu_span();
 +        let analysis = host.analysis();
 +        let config = CompletionConfig {
 +            enable_postfix_completions: true,
 +            enable_imports_on_the_fly: true,
 +            enable_self_on_the_fly: true,
 +            enable_private_editable: true,
 +            callable: Some(CallableSnippets::FillArguments),
 +            snippet_cap: SnippetCap::new(true),
 +            insert_use: InsertUseConfig {
 +                granularity: ImportGranularity::Crate,
 +                prefix_kind: hir::PrefixKind::ByCrate,
 +                enforce_granularity: true,
 +                group: true,
 +                skip_glob_imports: true,
 +            },
 +            snippets: Vec::new(),
++            prefer_no_std: false,
 +        };
 +        let position =
 +            FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
 +        analysis.completions(&config, position, None).unwrap();
 +    }
 +}
 +
 +fn patch(what: &mut String, from: &str, to: &str) -> usize {
 +    let idx = what.find(from).unwrap();
 +    *what = what.replacen(from, to, 1);
 +    idx
 +}
index e47f70fff39e0a3a48a07947d1b925a4c8ad2282,0000000000000000000000000000000000000000..4cf5de46c485ed134f8d93469a046e5016ca199f
mode 100644,000000..100644
--- /dev/null
@@@ -1,724 -1,0 +1,729 @@@
-                 crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
 +//! Project loading & configuration updates.
 +//!
 +//! This is quite tricky. The main problem is time and changes -- there's no
 +//! fixed "project" rust-analyzer is working with, "current project" is itself
 +//! mutable state. For example, when the user edits `Cargo.toml` by adding a new
 +//! dependency, project model changes. What's more, switching project model is
 +//! not instantaneous -- it takes time to run `cargo metadata` and (for proc
 +//! macros) `cargo check`.
 +//!
 +//! The main guiding principle here is, as elsewhere in rust-analyzer,
 +//! robustness. We try not to assume that the project model exists or is
 +//! correct. Instead, we try to provide a best-effort service. Even if the
 +//! project is currently loading and we don't have a full project model, we
 +//! still want to respond to various  requests.
 +use std::{mem, sync::Arc};
 +
 +use flycheck::{FlycheckConfig, FlycheckHandle};
 +use hir::db::DefDatabase;
 +use ide::Change;
 +use ide_db::base_db::{
 +    CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind,
 +    ProcMacroLoadResult, SourceRoot, VfsPath,
 +};
 +use proc_macro_api::{MacroDylib, ProcMacroServer};
 +use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
 +use syntax::SmolStr;
 +use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
 +
 +use crate::{
 +    config::{Config, FilesWatcher, LinkedProject},
 +    global_state::GlobalState,
 +    lsp_ext,
 +    main_loop::Task,
 +    op_queue::Cause,
 +};
 +
 +#[derive(Debug)]
 +pub(crate) enum ProjectWorkspaceProgress {
 +    Begin,
 +    Report(String),
 +    End(Vec<anyhow::Result<ProjectWorkspace>>),
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum BuildDataProgress {
 +    Begin,
 +    Report(String),
 +    End((Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)),
 +}
 +
 +impl GlobalState {
 +    pub(crate) fn is_quiescent(&self) -> bool {
 +        !(self.fetch_workspaces_queue.op_in_progress()
 +            || self.fetch_build_data_queue.op_in_progress()
 +            || self.vfs_progress_config_version < self.vfs_config_version
 +            || self.vfs_progress_n_done < self.vfs_progress_n_total)
 +    }
 +
 +    pub(crate) fn update_configuration(&mut self, config: Config) {
 +        let _p = profile::span("GlobalState::update_configuration");
 +        let old_config = mem::replace(&mut self.config, Arc::new(config));
 +        if self.config.lru_capacity() != old_config.lru_capacity() {
 +            self.analysis_host.update_lru_capacity(self.config.lru_capacity());
 +        }
 +        if self.config.linked_projects() != old_config.linked_projects() {
 +            self.fetch_workspaces_queue.request_op("linked projects changed".to_string())
 +        } else if self.config.flycheck() != old_config.flycheck() {
 +            self.reload_flycheck();
 +        }
 +
 +        if self.analysis_host.raw_database().enable_proc_attr_macros()
 +            != self.config.expand_proc_attr_macros()
 +        {
 +            self.analysis_host
 +                .raw_database_mut()
 +                .set_enable_proc_attr_macros(self.config.expand_proc_attr_macros());
 +        }
 +    }
 +
 +    pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
 +        let mut status = lsp_ext::ServerStatusParams {
 +            health: lsp_ext::Health::Ok,
 +            quiescent: self.is_quiescent(),
 +            message: None,
 +        };
 +
 +        if self.proc_macro_changed {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Reload required due to source changes of a procedural macro.".into())
 +        }
 +        if let Err(_) = self.fetch_build_data_error() {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Failed to run build scripts of some packages, check the logs.".to_string());
 +        }
 +        if !self.config.cargo_autoreload()
 +            && self.is_quiescent()
 +            && self.fetch_workspaces_queue.op_requested()
 +        {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message = Some("Workspace reload required".to_string())
 +        }
 +
 +        if let Err(error) = self.fetch_workspace_error() {
 +            status.health = lsp_ext::Health::Error;
 +            status.message = Some(error)
 +        }
 +        status
 +    }
 +
 +    pub(crate) fn fetch_workspaces(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch workspaces");
 +
 +        self.task_pool.handle.spawn_with_sender({
 +            let linked_projects = self.config.linked_projects();
 +            let detached_files = self.config.detached_files().to_vec();
 +            let cargo_config = self.config.cargo();
 +
 +            move |sender| {
 +                let progress = {
 +                    let sender = sender.clone();
 +                    move |msg| {
 +                        sender
 +                            .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg)))
 +                            .unwrap()
 +                    }
 +                };
 +
 +                sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap();
 +
 +                let mut workspaces = linked_projects
 +                    .iter()
 +                    .map(|project| match project {
 +                        LinkedProject::ProjectManifest(manifest) => {
 +                            project_model::ProjectWorkspace::load(
 +                                manifest.clone(),
 +                                &cargo_config,
 +                                &progress,
 +                            )
 +                        }
 +                        LinkedProject::InlineJsonProject(it) => {
 +                            project_model::ProjectWorkspace::load_inline(
 +                                it.clone(),
 +                                cargo_config.target.as_deref(),
++                                &cargo_config,
 +                            )
 +                        }
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                if !detached_files.is_empty() {
 +                    workspaces
 +                        .push(project_model::ProjectWorkspace::load_detached_files(detached_files));
 +                }
 +
 +                tracing::info!("did fetch workspaces {:?}", workspaces);
 +                sender
 +                    .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces)))
 +                    .unwrap();
 +            }
 +        });
 +    }
 +
 +    pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch build data");
 +        let workspaces = Arc::clone(&self.workspaces);
 +        let config = self.config.cargo();
 +        self.task_pool.handle.spawn_with_sender(move |sender| {
 +            sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
 +
 +            let progress = {
 +                let sender = sender.clone();
 +                move |msg| {
 +                    sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
 +                }
 +            };
 +            let mut res = Vec::new();
 +            for ws in workspaces.iter() {
 +                res.push(ws.run_build_scripts(&config, &progress));
 +            }
 +            sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
 +        });
 +    }
 +
 +    pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
 +        let _p = profile::span("GlobalState::switch_workspaces");
 +        tracing::info!(%cause, "will switch workspaces");
 +
 +        if let Err(error_message) = self.fetch_workspace_error() {
 +            self.show_and_log_error(error_message, None);
 +            if !self.workspaces.is_empty() {
 +                // It only makes sense to switch to a partially broken workspace
 +                // if we don't have any workspace at all yet.
 +                return;
 +            }
 +        }
 +
 +        if let Err(error) = self.fetch_build_data_error() {
 +            self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
 +        }
 +
 +        let workspaces = self
 +            .fetch_workspaces_queue
 +            .last_op_result()
 +            .iter()
 +            .filter_map(|res| res.as_ref().ok().cloned())
 +            .collect::<Vec<_>>();
 +
 +        fn eq_ignore_build_data<'a>(
 +            left: &'a ProjectWorkspace,
 +            right: &'a ProjectWorkspace,
 +        ) -> bool {
 +            let key = |p: &'a ProjectWorkspace| match p {
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +
 +                    build_scripts: _,
 +                    toolchain: _,
 +                } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
 +                _ => None,
 +            };
 +            match (key(left), key(right)) {
 +                (Some(lk), Some(rk)) => lk == rk,
 +                _ => left == right,
 +            }
 +        }
 +
 +        let same_workspaces = workspaces.len() == self.workspaces.len()
 +            && workspaces
 +                .iter()
 +                .zip(self.workspaces.iter())
 +                .all(|(l, r)| eq_ignore_build_data(l, r));
 +
 +        if same_workspaces {
 +            let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
 +            if Arc::ptr_eq(workspaces, &self.workspaces) {
 +                tracing::debug!("set build scripts to workspaces");
 +
 +                let workspaces = workspaces
 +                    .iter()
 +                    .cloned()
 +                    .zip(build_scripts)
 +                    .map(|(mut ws, bs)| {
 +                        ws.set_build_scripts(bs.as_ref().ok().cloned().unwrap_or_default());
 +                        ws
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                // Workspaces are the same, but we've updated build data.
 +                self.workspaces = Arc::new(workspaces);
 +            } else {
 +                tracing::info!("build scripts do not match the version of the active workspace");
 +                // Current build scripts do not match the version of the active
 +                // workspace, so there's nothing for us to update.
 +                return;
 +            }
 +        } else {
 +            tracing::debug!("abandon build scripts for workspaces");
 +
 +            // Here, we completely changed the workspace (Cargo.toml edit), so
 +            // we don't care about build-script results, they are stale.
 +            self.workspaces = Arc::new(workspaces)
 +        }
 +
 +        if let FilesWatcher::Client = self.config.files().watcher {
 +            let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
 +                watchers: self
 +                    .workspaces
 +                    .iter()
 +                    .flat_map(|ws| ws.to_roots())
 +                    .filter(|it| it.is_local)
 +                    .flat_map(|root| {
 +                        root.include.into_iter().flat_map(|it| {
 +                            [
 +                                format!("{}/**/*.rs", it.display()),
 +                                format!("{}/**/Cargo.toml", it.display()),
 +                                format!("{}/**/Cargo.lock", it.display()),
 +                            ]
 +                        })
 +                    })
 +                    .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
 +                    .collect(),
 +            };
 +            let registration = lsp_types::Registration {
 +                id: "workspace/didChangeWatchedFiles".to_string(),
 +                method: "workspace/didChangeWatchedFiles".to_string(),
 +                register_options: Some(serde_json::to_value(registration_options).unwrap()),
 +            };
 +            self.send_request::<lsp_types::request::RegisterCapability>(
 +                lsp_types::RegistrationParams { registrations: vec![registration] },
 +                |_, _| (),
 +            );
 +        }
 +
 +        let mut change = Change::new();
 +
 +        let files_config = self.config.files();
 +        let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 +
 +        let standalone_server_name =
 +            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
 +
 +        if self.proc_macro_clients.is_empty() {
 +            if let Some((path, args)) = self.config.proc_macro_srv() {
 +                tracing::info!("Spawning proc-macro servers");
 +                self.proc_macro_clients = self
 +                    .workspaces
 +                    .iter()
 +                    .map(|ws| {
 +                        let mut args = args.clone();
 +                        let mut path = path.clone();
 +
 +                        if let ProjectWorkspace::Cargo { sysroot, .. }
 +                        | ProjectWorkspace::Json { sysroot, .. } = ws
 +                        {
 +                            tracing::debug!("Found a cargo workspace...");
 +                            if let Some(sysroot) = sysroot.as_ref() {
 +                                tracing::debug!("Found a cargo workspace with a sysroot...");
 +                                let server_path =
 +                                    sysroot.root().join("libexec").join(&standalone_server_name);
 +                                if std::fs::metadata(&server_path).is_ok() {
 +                                    tracing::debug!(
 +                                        "And the server exists at {}",
 +                                        server_path.display()
 +                                    );
 +                                    path = server_path;
 +                                    args = vec![];
 +                                } else {
 +                                    tracing::debug!(
 +                                        "And the server does not exist at {}",
 +                                        server_path.display()
 +                                    );
 +                                }
 +                            }
 +                        }
 +
 +                        tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
 +                        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
 +                            let error = format!(
 +                                "Failed to run proc-macro server from path {}, error: {:?}",
 +                                path.display(),
 +                                err
 +                            );
 +                            tracing::error!(error);
 +                            error
 +                        })
 +                    })
 +                    .collect()
 +            };
 +        }
 +
 +        let watch = match files_config.watcher {
 +            FilesWatcher::Client => vec![],
 +            FilesWatcher::Server => project_folders.watch,
 +        };
 +        self.vfs_config_version += 1;
 +        self.loader.handle.set_config(vfs::loader::Config {
 +            load: project_folders.load,
 +            watch,
 +            version: self.vfs_config_version,
 +        });
 +
 +        // Create crate graph from all the workspaces
 +        let crate_graph = {
 +            let dummy_replacements = self.config.dummy_replacements();
 +
 +            let vfs = &mut self.vfs.write().0;
 +            let loader = &mut self.loader;
 +            let mem_docs = &self.mem_docs;
 +            let mut load = move |path: &AbsPath| {
 +                let _p = profile::span("GlobalState::load");
 +                let vfs_path = vfs::VfsPath::from(path.to_path_buf());
 +                if !mem_docs.contains(&vfs_path) {
 +                    let contents = loader.handle.load_sync(path);
 +                    vfs.set_file_contents(vfs_path.clone(), contents);
 +                }
 +                let res = vfs.file_id(&vfs_path);
 +                if res.is_none() {
 +                    tracing::warn!("failed to load {}", path.display())
 +                }
 +                res
 +            };
 +
 +            let mut crate_graph = CrateGraph::default();
 +            for (idx, ws) in self.workspaces.iter().enumerate() {
 +                let proc_macro_client = match self.proc_macro_clients.get(idx) {
 +                    Some(res) => res.as_ref().map_err(|e| &**e),
 +                    None => Err("Proc macros are disabled"),
 +                };
 +                let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
 +                    load_proc_macro(
 +                        proc_macro_client,
 +                        path,
 +                        dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
 +                    )
 +                };
++                crate_graph.extend(ws.to_crate_graph(
++                    &mut load_proc_macro,
++                    &mut load,
++                    &self.config.cargo(),
++                ));
 +            }
 +            crate_graph
 +        };
 +        change.set_crate_graph(crate_graph);
 +
 +        self.source_root_config = project_folders.source_root_config;
 +
 +        self.analysis_host.apply_change(change);
 +        self.process_changes();
 +        self.reload_flycheck();
 +        tracing::info!("did switch workspaces");
 +    }
 +
 +    fn fetch_workspace_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in self.fetch_workspaces_queue.last_op_result() {
 +            if let Err(err) = ws {
 +                stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            return Ok(());
 +        }
 +
 +        Err(buf)
 +    }
 +
 +    fn fetch_build_data_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in &self.fetch_build_data_queue.last_op_result().1 {
 +            match ws {
 +                Ok(data) => match data.error() {
 +                    Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr),
 +                    _ => (),
 +                },
 +                // io errors
 +                Err(err) => stdx::format_to!(buf, "{:#}\n", err),
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            Ok(())
 +        } else {
 +            Err(buf)
 +        }
 +    }
 +
 +    fn reload_flycheck(&mut self) {
 +        let _p = profile::span("GlobalState::reload_flycheck");
 +        let config = match self.config.flycheck() {
 +            Some(it) => it,
 +            None => {
 +                self.flycheck = Vec::new();
 +                self.diagnostics.clear_check_all();
 +                return;
 +            }
 +        };
 +
 +        let sender = self.flycheck_sender.clone();
 +        self.flycheck = self
 +            .workspaces
 +            .iter()
 +            .enumerate()
 +            .filter_map(|(id, w)| match w {
 +                ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
 +                ProjectWorkspace::Json { project, .. } => {
 +                    // Enable flychecks for json projects if a custom flycheck command was supplied
 +                    // in the workspace configuration.
 +                    match config {
 +                        FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
 +                        _ => None,
 +                    }
 +                }
 +                ProjectWorkspace::DetachedFiles { .. } => None,
 +            })
 +            .map(|(id, root)| {
 +                let sender = sender.clone();
 +                FlycheckHandle::spawn(
 +                    id,
 +                    Box::new(move |msg| sender.send(msg).unwrap()),
 +                    config.clone(),
 +                    root.to_path_buf(),
 +                )
 +            })
 +            .collect();
 +    }
 +}
 +
 +#[derive(Default)]
 +pub(crate) struct ProjectFolders {
 +    pub(crate) load: Vec<vfs::loader::Entry>,
 +    pub(crate) watch: Vec<usize>,
 +    pub(crate) source_root_config: SourceRootConfig,
 +}
 +
 +impl ProjectFolders {
 +    pub(crate) fn new(
 +        workspaces: &[ProjectWorkspace],
 +        global_excludes: &[AbsPathBuf],
 +    ) -> ProjectFolders {
 +        let mut res = ProjectFolders::default();
 +        let mut fsc = FileSetConfig::builder();
 +        let mut local_filesets = vec![];
 +
 +        for root in workspaces.iter().flat_map(|ws| ws.to_roots()) {
 +            let file_set_roots: Vec<VfsPath> =
 +                root.include.iter().cloned().map(VfsPath::from).collect();
 +
 +            let entry = {
 +                let mut dirs = vfs::loader::Directories::default();
 +                dirs.extensions.push("rs".into());
 +                dirs.include.extend(root.include);
 +                dirs.exclude.extend(root.exclude);
 +                for excl in global_excludes {
 +                    if dirs
 +                        .include
 +                        .iter()
 +                        .any(|incl| incl.starts_with(excl) || excl.starts_with(incl))
 +                    {
 +                        dirs.exclude.push(excl.clone());
 +                    }
 +                }
 +
 +                vfs::loader::Entry::Directories(dirs)
 +            };
 +
 +            if root.is_local {
 +                res.watch.push(res.load.len());
 +            }
 +            res.load.push(entry);
 +
 +            if root.is_local {
 +                local_filesets.push(fsc.len());
 +            }
 +            fsc.add_file_set(file_set_roots)
 +        }
 +
 +        let fsc = fsc.build();
 +        res.source_root_config = SourceRootConfig { fsc, local_filesets };
 +
 +        res
 +    }
 +}
 +
 +#[derive(Default, Debug)]
 +pub(crate) struct SourceRootConfig {
 +    pub(crate) fsc: FileSetConfig,
 +    pub(crate) local_filesets: Vec<usize>,
 +}
 +
 +impl SourceRootConfig {
 +    pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
 +        let _p = profile::span("SourceRootConfig::partition");
 +        self.fsc
 +            .partition(vfs)
 +            .into_iter()
 +            .enumerate()
 +            .map(|(idx, file_set)| {
 +                let is_local = self.local_filesets.contains(&idx);
 +                if is_local {
 +                    SourceRoot::new_local(file_set)
 +                } else {
 +                    SourceRoot::new_library(file_set)
 +                }
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 +/// with an identity dummy expander.
 +pub(crate) fn load_proc_macro(
 +    server: Result<&ProcMacroServer, &str>,
 +    path: &AbsPath,
 +    dummy_replace: &[Box<str>],
 +) -> ProcMacroLoadResult {
 +    let res: Result<Vec<_>, String> = (|| {
 +        let dylib = MacroDylib::new(path.to_path_buf())
 +            .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?;
 +        let server = server.map_err(ToOwned::to_owned)?;
 +        let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
 +        if vec.is_empty() {
 +            return Err("proc macro library returned no proc macros".to_string());
 +        }
 +        Ok(vec
 +            .into_iter()
 +            .map(|expander| expander_to_proc_macro(expander, dummy_replace))
 +            .collect())
 +    })();
 +    return match res {
 +        Ok(proc_macros) => {
 +            tracing::info!(
 +                "Loaded proc-macros for {}: {:?}",
 +                path.display(),
 +                proc_macros.iter().map(|it| it.name.clone()).collect::<Vec<_>>()
 +            );
 +            Ok(proc_macros)
 +        }
 +        Err(e) => {
 +            tracing::warn!("proc-macro loading for {} failed: {e}", path.display());
 +            Err(e)
 +        }
 +    };
 +
 +    fn expander_to_proc_macro(
 +        expander: proc_macro_api::ProcMacro,
 +        dummy_replace: &[Box<str>],
 +    ) -> ProcMacro {
 +        let name = SmolStr::from(expander.name());
 +        let kind = match expander.kind() {
 +            proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
 +            proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
 +            proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
 +        };
 +        let expander: Arc<dyn ProcMacroExpander> =
 +            if dummy_replace.iter().any(|replace| &**replace == name) {
 +                match kind {
 +                    ProcMacroKind::Attr => Arc::new(IdentityExpander),
 +                    _ => Arc::new(EmptyExpander),
 +                }
 +            } else {
 +                Arc::new(Expander(expander))
 +            };
 +        ProcMacro { name, kind, expander }
 +    }
 +
 +    #[derive(Debug)]
 +    struct Expander(proc_macro_api::ProcMacro);
 +
 +    impl ProcMacroExpander for Expander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            attrs: Option<&tt::Subtree>,
 +            env: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
 +            match self.0.expand(subtree, attrs, env) {
 +                Ok(Ok(subtree)) => Ok(subtree),
 +                Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)),
 +                Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
 +            }
 +        }
 +    }
 +
 +    /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct IdentityExpander;
 +
 +    impl ProcMacroExpander for IdentityExpander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(subtree.clone())
 +        }
 +    }
 +
 +    /// Empty expander, used for proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct EmptyExpander;
 +
 +    impl ProcMacroExpander for EmptyExpander {
 +        fn expand(
 +            &self,
 +            _: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(tt::Subtree::default())
 +        }
 +    }
 +}
 +
 +pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
 +    const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
 +    const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 +
 +    let file_name = match path.file_name().unwrap_or_default().to_str() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +
 +    if let "Cargo.toml" | "Cargo.lock" = file_name {
 +        return true;
 +    }
 +    if change_kind == ChangeKind::Modify {
 +        return false;
 +    }
 +
 +    // .cargo/config{.toml}
 +    if path.extension().unwrap_or_default() != "rs" {
 +        let is_cargo_config = matches!(file_name, "config.toml" | "config")
 +            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
 +        return is_cargo_config;
 +    }
 +
 +    if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    let parent = match path.parent() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +    if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    if file_name == "main.rs" {
 +        let grand_parent = match parent.parent() {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +        if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) {
 +            return true;
 +        }
 +    }
 +    false
 +}
index e083b9d0e33789ae448a42bd698dcee79a46f6c8,0000000000000000000000000000000000000000..1de801e23e5c861c6e80e9dab1231332e4244e72
mode 100644,000000..100644
--- /dev/null
@@@ -1,1423 -1,0 +1,1424 @@@
- ) -> lsp_types::DocumentHighlightKind {
 +//! Conversion of rust-analyzer specific types to lsp_types equivalents.
 +use std::{
 +    iter::once,
 +    path,
 +    sync::atomic::{AtomicU32, Ordering},
 +};
 +
 +use ide::{
 +    Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
 +    CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
 +    Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
 +    InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
 +    Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
 +    TextSize,
 +};
 +use itertools::Itertools;
 +use serde_json::to_value;
 +use vfs::AbsPath;
 +
 +use crate::{
 +    cargo_target_spec::CargoTargetSpec,
 +    config::{CallInfoConfig, Config},
 +    global_state::GlobalStateSnapshot,
 +    line_index::{LineEndings, LineIndex, OffsetEncoding},
 +    lsp_ext,
 +    lsp_utils::invalid_params_error,
 +    semantic_tokens, Result,
 +};
 +
 +pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
 +    let line_col = line_index.index.line_col(offset);
 +    match line_index.encoding {
 +        OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col),
 +        OffsetEncoding::Utf16 => {
 +            let line_col = line_index.index.to_utf16(line_col);
 +            lsp_types::Position::new(line_col.line, line_col.col)
 +        }
 +    }
 +}
 +
 +pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range {
 +    let start = position(line_index, range.start());
 +    let end = position(line_index, range.end());
 +    lsp_types::Range::new(start, end)
 +}
 +
 +pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
 +    match symbol_kind {
 +        SymbolKind::Function => lsp_types::SymbolKind::FUNCTION,
 +        SymbolKind::Struct => lsp_types::SymbolKind::STRUCT,
 +        SymbolKind::Enum => lsp_types::SymbolKind::ENUM,
 +        SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER,
 +        SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE,
 +        SymbolKind::Macro
 +        | SymbolKind::BuiltinAttr
 +        | SymbolKind::Attribute
 +        | SymbolKind::Derive
 +        | SymbolKind::DeriveHelper => lsp_types::SymbolKind::FUNCTION,
 +        SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE,
 +        SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => {
 +            lsp_types::SymbolKind::TYPE_PARAMETER
 +        }
 +        SymbolKind::Field => lsp_types::SymbolKind::FIELD,
 +        SymbolKind::Static => lsp_types::SymbolKind::CONSTANT,
 +        SymbolKind::Const => lsp_types::SymbolKind::CONSTANT,
 +        SymbolKind::ConstParam => lsp_types::SymbolKind::CONSTANT,
 +        SymbolKind::Impl => lsp_types::SymbolKind::OBJECT,
 +        SymbolKind::Local
 +        | SymbolKind::SelfParam
 +        | SymbolKind::LifetimeParam
 +        | SymbolKind::ValueParam
 +        | SymbolKind::Label => lsp_types::SymbolKind::VARIABLE,
 +        SymbolKind::Union => lsp_types::SymbolKind::STRUCT,
 +    }
 +}
 +
 +pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolKind {
 +    match kind {
 +        StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol),
 +        StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE,
 +    }
 +}
 +
 +pub(crate) fn document_highlight_kind(
 +    category: ReferenceCategory,
-         ReferenceCategory::Read => lsp_types::DocumentHighlightKind::READ,
-         ReferenceCategory::Write => lsp_types::DocumentHighlightKind::WRITE,
++) -> Option<lsp_types::DocumentHighlightKind> {
 +    match category {
++        ReferenceCategory::Read => Some(lsp_types::DocumentHighlightKind::READ),
++        ReferenceCategory::Write => Some(lsp_types::DocumentHighlightKind::WRITE),
++        ReferenceCategory::Import => None,
 +    }
 +}
 +
 +pub(crate) fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSeverity {
 +    match severity {
 +        Severity::Error => lsp_types::DiagnosticSeverity::ERROR,
 +        Severity::WeakWarning => lsp_types::DiagnosticSeverity::HINT,
 +    }
 +}
 +
 +pub(crate) fn documentation(documentation: Documentation) -> lsp_types::Documentation {
 +    let value = crate::markdown::format_docs(documentation.as_str());
 +    let markup_content = lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value };
 +    lsp_types::Documentation::MarkupContent(markup_content)
 +}
 +
 +pub(crate) fn completion_item_kind(
 +    completion_item_kind: CompletionItemKind,
 +) -> lsp_types::CompletionItemKind {
 +    match completion_item_kind {
 +        CompletionItemKind::Binding => lsp_types::CompletionItemKind::VARIABLE,
 +        CompletionItemKind::BuiltinType => lsp_types::CompletionItemKind::STRUCT,
 +        CompletionItemKind::InferredType => lsp_types::CompletionItemKind::SNIPPET,
 +        CompletionItemKind::Keyword => lsp_types::CompletionItemKind::KEYWORD,
 +        CompletionItemKind::Method => lsp_types::CompletionItemKind::METHOD,
 +        CompletionItemKind::Snippet => lsp_types::CompletionItemKind::SNIPPET,
 +        CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::REFERENCE,
 +        CompletionItemKind::SymbolKind(symbol) => match symbol {
 +            SymbolKind::Attribute => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT,
 +            SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
 +            SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::DeriveHelper => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::Enum => lsp_types::CompletionItemKind::ENUM,
 +            SymbolKind::Field => lsp_types::CompletionItemKind::FIELD,
 +            SymbolKind::Function => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::Impl => lsp_types::CompletionItemKind::TEXT,
 +            SymbolKind::Label => lsp_types::CompletionItemKind::VARIABLE,
 +            SymbolKind::LifetimeParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
 +            SymbolKind::Local => lsp_types::CompletionItemKind::VARIABLE,
 +            SymbolKind::Macro => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::Module => lsp_types::CompletionItemKind::MODULE,
 +            SymbolKind::SelfParam => lsp_types::CompletionItemKind::VALUE,
 +            SymbolKind::SelfType => lsp_types::CompletionItemKind::TYPE_PARAMETER,
 +            SymbolKind::Static => lsp_types::CompletionItemKind::VALUE,
 +            SymbolKind::Struct => lsp_types::CompletionItemKind::STRUCT,
 +            SymbolKind::Trait => lsp_types::CompletionItemKind::INTERFACE,
 +            SymbolKind::TypeAlias => lsp_types::CompletionItemKind::STRUCT,
 +            SymbolKind::TypeParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
 +            SymbolKind::Union => lsp_types::CompletionItemKind::STRUCT,
 +            SymbolKind::ValueParam => lsp_types::CompletionItemKind::VALUE,
 +            SymbolKind::Variant => lsp_types::CompletionItemKind::ENUM_MEMBER,
 +            SymbolKind::BuiltinAttr => lsp_types::CompletionItemKind::FUNCTION,
 +            SymbolKind::ToolModule => lsp_types::CompletionItemKind::MODULE,
 +        },
 +    }
 +}
 +
 +pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::TextEdit {
 +    let range = range(line_index, indel.delete);
 +    let new_text = match line_index.endings {
 +        LineEndings::Unix => indel.insert,
 +        LineEndings::Dos => indel.insert.replace('\n', "\r\n"),
 +    };
 +    lsp_types::TextEdit { range, new_text }
 +}
 +
 +pub(crate) fn completion_text_edit(
 +    line_index: &LineIndex,
 +    insert_replace_support: Option<lsp_types::Position>,
 +    indel: Indel,
 +) -> lsp_types::CompletionTextEdit {
 +    let text_edit = text_edit(line_index, indel);
 +    match insert_replace_support {
 +        Some(cursor_pos) => lsp_types::InsertReplaceEdit {
 +            new_text: text_edit.new_text,
 +            insert: lsp_types::Range { start: text_edit.range.start, end: cursor_pos },
 +            replace: text_edit.range,
 +        }
 +        .into(),
 +        None => text_edit.into(),
 +    }
 +}
 +
 +pub(crate) fn snippet_text_edit(
 +    line_index: &LineIndex,
 +    is_snippet: bool,
 +    indel: Indel,
 +) -> lsp_ext::SnippetTextEdit {
 +    let text_edit = text_edit(line_index, indel);
 +    let insert_text_format =
 +        if is_snippet { Some(lsp_types::InsertTextFormat::SNIPPET) } else { None };
 +    lsp_ext::SnippetTextEdit {
 +        range: text_edit.range,
 +        new_text: text_edit.new_text,
 +        insert_text_format,
 +        annotation_id: None,
 +    }
 +}
 +
 +pub(crate) fn text_edit_vec(
 +    line_index: &LineIndex,
 +    text_edit: TextEdit,
 +) -> Vec<lsp_types::TextEdit> {
 +    text_edit.into_iter().map(|indel| self::text_edit(line_index, indel)).collect()
 +}
 +
 +pub(crate) fn snippet_text_edit_vec(
 +    line_index: &LineIndex,
 +    is_snippet: bool,
 +    text_edit: TextEdit,
 +) -> Vec<lsp_ext::SnippetTextEdit> {
 +    text_edit
 +        .into_iter()
 +        .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel))
 +        .collect()
 +}
 +
 +pub(crate) fn completion_items(
 +    config: &Config,
 +    line_index: &LineIndex,
 +    tdpp: lsp_types::TextDocumentPositionParams,
 +    items: Vec<CompletionItem>,
 +) -> Vec<lsp_types::CompletionItem> {
 +    let max_relevance = items.iter().map(|it| it.relevance().score()).max().unwrap_or_default();
 +    let mut res = Vec::with_capacity(items.len());
 +    for item in items {
 +        completion_item(&mut res, config, line_index, &tdpp, max_relevance, item)
 +    }
 +    res
 +}
 +
 +fn completion_item(
 +    acc: &mut Vec<lsp_types::CompletionItem>,
 +    config: &Config,
 +    line_index: &LineIndex,
 +    tdpp: &lsp_types::TextDocumentPositionParams,
 +    max_relevance: u32,
 +    item: CompletionItem,
 +) {
 +    let insert_replace_support = config.insert_replace_support().then(|| tdpp.position);
 +    let mut additional_text_edits = Vec::new();
 +
 +    // LSP does not allow arbitrary edits in completion, so we have to do a
 +    // non-trivial mapping here.
 +    let text_edit = {
 +        let mut text_edit = None;
 +        let source_range = item.source_range();
 +        for indel in item.text_edit().iter() {
 +            if indel.delete.contains_range(source_range) {
 +                text_edit = Some(if indel.delete == source_range {
 +                    self::completion_text_edit(line_index, insert_replace_support, indel.clone())
 +                } else {
 +                    assert!(source_range.end() == indel.delete.end());
 +                    let range1 = TextRange::new(indel.delete.start(), source_range.start());
 +                    let range2 = source_range;
 +                    let indel1 = Indel::replace(range1, String::new());
 +                    let indel2 = Indel::replace(range2, indel.insert.clone());
 +                    additional_text_edits.push(self::text_edit(line_index, indel1));
 +                    self::completion_text_edit(line_index, insert_replace_support, indel2)
 +                })
 +            } else {
 +                assert!(source_range.intersect(indel.delete).is_none());
 +                let text_edit = self::text_edit(line_index, indel.clone());
 +                additional_text_edits.push(text_edit);
 +            }
 +        }
 +        text_edit.unwrap()
 +    };
 +
 +    let insert_text_format = item.is_snippet().then(|| lsp_types::InsertTextFormat::SNIPPET);
 +    let tags = item.deprecated().then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]);
 +    let command = if item.trigger_call_info() && config.client_commands().trigger_parameter_hints {
 +        Some(command::trigger_parameter_hints())
 +    } else {
 +        None
 +    };
 +
 +    let mut lsp_item = lsp_types::CompletionItem {
 +        label: item.label().to_string(),
 +        detail: item.detail().map(|it| it.to_string()),
 +        filter_text: Some(item.lookup().to_string()),
 +        kind: Some(completion_item_kind(item.kind())),
 +        text_edit: Some(text_edit),
 +        additional_text_edits: Some(additional_text_edits),
 +        documentation: item.documentation().map(documentation),
 +        deprecated: Some(item.deprecated()),
 +        tags,
 +        command,
 +        insert_text_format,
 +        ..Default::default()
 +    };
 +
 +    if config.completion_label_details_support() {
 +        lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
 +            detail: None,
 +            description: lsp_item.detail.clone(),
 +        });
 +    }
 +
 +    set_score(&mut lsp_item, max_relevance, item.relevance());
 +
 +    if config.completion().enable_imports_on_the_fly {
 +        if let imports @ [_, ..] = item.imports_to_add() {
 +            let imports: Vec<_> = imports
 +                .iter()
 +                .filter_map(|import_edit| {
 +                    let import_path = &import_edit.import_path;
 +                    let import_name = import_path.segments().last()?;
 +                    Some(lsp_ext::CompletionImport {
 +                        full_import_path: import_path.to_string(),
 +                        imported_name: import_name.to_string(),
 +                    })
 +                })
 +                .collect();
 +            if !imports.is_empty() {
 +                let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports };
 +                lsp_item.data = Some(to_value(data).unwrap());
 +            }
 +        }
 +    }
 +
 +    if let Some((mutability, offset, relevance)) = item.ref_match() {
 +        let mut lsp_item_with_ref = lsp_item.clone();
 +        set_score(&mut lsp_item_with_ref, max_relevance, relevance);
 +        lsp_item_with_ref.label =
 +            format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
 +        lsp_item_with_ref.additional_text_edits.get_or_insert_with(Default::default).push(
 +            self::text_edit(
 +                line_index,
 +                Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
 +            ),
 +        );
 +
 +        acc.push(lsp_item_with_ref);
 +    };
 +
 +    acc.push(lsp_item);
 +
 +    fn set_score(
 +        res: &mut lsp_types::CompletionItem,
 +        max_relevance: u32,
 +        relevance: CompletionRelevance,
 +    ) {
 +        if relevance.is_relevant() && relevance.score() == max_relevance {
 +            res.preselect = Some(true);
 +        }
 +        // The relevance needs to be inverted to come up with a sort score
 +        // because the client will sort ascending.
 +        let sort_score = relevance.score() ^ 0xFF_FF_FF_FF;
 +        // Zero pad the string to ensure values can be properly sorted
 +        // by the client. Hex format is used because it is easier to
 +        // visually compare very large values, which the sort text
 +        // tends to be since it is the opposite of the score.
 +        res.sort_text = Some(format!("{:08x}", sort_score));
 +    }
 +}
 +
 +pub(crate) fn signature_help(
 +    call_info: SignatureHelp,
 +    config: CallInfoConfig,
 +    label_offsets: bool,
 +) -> lsp_types::SignatureHelp {
 +    let (label, parameters) = match (config.params_only, label_offsets) {
 +        (concise, false) => {
 +            let params = call_info
 +                .parameter_labels()
 +                .map(|label| lsp_types::ParameterInformation {
 +                    label: lsp_types::ParameterLabel::Simple(label.to_string()),
 +                    documentation: None,
 +                })
 +                .collect::<Vec<_>>();
 +            let label =
 +                if concise { call_info.parameter_labels().join(", ") } else { call_info.signature };
 +            (label, params)
 +        }
 +        (false, true) => {
 +            let params = call_info
 +                .parameter_ranges()
 +                .iter()
 +                .map(|it| {
 +                    let start = call_info.signature[..it.start().into()].chars().count() as u32;
 +                    let end = call_info.signature[..it.end().into()].chars().count() as u32;
 +                    [start, end]
 +                })
 +                .map(|label_offsets| lsp_types::ParameterInformation {
 +                    label: lsp_types::ParameterLabel::LabelOffsets(label_offsets),
 +                    documentation: None,
 +                })
 +                .collect::<Vec<_>>();
 +            (call_info.signature, params)
 +        }
 +        (true, true) => {
 +            let mut params = Vec::new();
 +            let mut label = String::new();
 +            let mut first = true;
 +            for param in call_info.parameter_labels() {
 +                if !first {
 +                    label.push_str(", ");
 +                }
 +                first = false;
 +                let start = label.chars().count() as u32;
 +                label.push_str(param);
 +                let end = label.chars().count() as u32;
 +                params.push(lsp_types::ParameterInformation {
 +                    label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
 +                    documentation: None,
 +                });
 +            }
 +
 +            (label, params)
 +        }
 +    };
 +
 +    let documentation = call_info.doc.filter(|_| config.docs).map(|doc| {
 +        lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent {
 +            kind: lsp_types::MarkupKind::Markdown,
 +            value: doc,
 +        })
 +    });
 +
 +    let active_parameter = call_info.active_parameter.map(|it| it as u32);
 +
 +    let signature = lsp_types::SignatureInformation {
 +        label,
 +        documentation,
 +        parameters: Some(parameters),
 +        active_parameter,
 +    };
 +    lsp_types::SignatureHelp {
 +        signatures: vec![signature],
 +        active_signature: Some(0),
 +        active_parameter,
 +    }
 +}
 +
 +pub(crate) fn inlay_hint(
 +    snap: &GlobalStateSnapshot,
 +    line_index: &LineIndex,
 +    render_colons: bool,
 +    mut inlay_hint: InlayHint,
 +) -> Result<lsp_types::InlayHint> {
 +    match inlay_hint.kind {
 +        InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
 +        InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
 +        InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
 +        _ => {}
 +    }
 +
 +    Ok(lsp_types::InlayHint {
 +        position: match inlay_hint.kind {
 +            // before annotated thing
 +            InlayKind::ParameterHint
 +            | InlayKind::ImplicitReborrowHint
 +            | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
 +            // after annotated thing
 +            InlayKind::ClosureReturnTypeHint
 +            | InlayKind::TypeHint
 +            | InlayKind::ChainingHint
 +            | InlayKind::GenericParamListHint
 +            | InlayKind::LifetimeHint
 +            | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
 +        },
 +        padding_left: Some(match inlay_hint.kind {
 +            InlayKind::TypeHint => !render_colons,
 +            InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
 +            InlayKind::BindingModeHint
 +            | InlayKind::ClosureReturnTypeHint
 +            | InlayKind::GenericParamListHint
 +            | InlayKind::ImplicitReborrowHint
 +            | InlayKind::LifetimeHint
 +            | InlayKind::ParameterHint => false,
 +        }),
 +        padding_right: Some(match inlay_hint.kind {
 +            InlayKind::ChainingHint
 +            | InlayKind::ClosureReturnTypeHint
 +            | InlayKind::GenericParamListHint
 +            | InlayKind::ImplicitReborrowHint
 +            | InlayKind::TypeHint
 +            | InlayKind::ClosingBraceHint => false,
 +            InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
 +            InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
 +        }),
 +        kind: match inlay_hint.kind {
 +            InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
 +            InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
 +                Some(lsp_types::InlayHintKind::TYPE)
 +            }
 +            InlayKind::BindingModeHint
 +            | InlayKind::GenericParamListHint
 +            | InlayKind::LifetimeHint
 +            | InlayKind::ImplicitReborrowHint
 +            | InlayKind::ClosingBraceHint => None,
 +        },
 +        text_edits: None,
 +        data: (|| match inlay_hint.tooltip {
 +            Some(ide::InlayTooltip::HoverOffset(file_id, offset)) => {
 +                let uri = url(snap, file_id);
 +                let line_index = snap.file_line_index(file_id).ok()?;
 +
 +                let text_document = lsp_types::TextDocumentIdentifier { uri };
 +                to_value(lsp_ext::InlayHintResolveData {
 +                    text_document,
 +                    position: lsp_ext::PositionOrRange::Position(position(&line_index, offset)),
 +                })
 +                .ok()
 +            }
 +            Some(ide::InlayTooltip::HoverRanged(file_id, text_range)) => {
 +                let uri = url(snap, file_id);
 +                let text_document = lsp_types::TextDocumentIdentifier { uri };
 +                let line_index = snap.file_line_index(file_id).ok()?;
 +                to_value(lsp_ext::InlayHintResolveData {
 +                    text_document,
 +                    position: lsp_ext::PositionOrRange::Range(range(&line_index, text_range)),
 +                })
 +                .ok()
 +            }
 +            _ => None,
 +        })(),
 +        tooltip: Some(match inlay_hint.tooltip {
 +            Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
 +            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
 +        }),
 +        label: inlay_hint_label(snap, inlay_hint.label)?,
 +    })
 +}
 +
 +fn inlay_hint_label(
 +    snap: &GlobalStateSnapshot,
 +    label: InlayHintLabel,
 +) -> Result<lsp_types::InlayHintLabel> {
 +    Ok(match label.as_simple_str() {
 +        Some(s) => lsp_types::InlayHintLabel::String(s.into()),
 +        None => lsp_types::InlayHintLabel::LabelParts(
 +            label
 +                .parts
 +                .into_iter()
 +                .map(|part| {
 +                    Ok(lsp_types::InlayHintLabelPart {
 +                        value: part.text,
 +                        tooltip: None,
 +                        location: part
 +                            .linked_location
 +                            .map(|range| location(snap, range))
 +                            .transpose()?,
 +                        command: None,
 +                    })
 +                })
 +                .collect::<Result<Vec<_>>>()?,
 +        ),
 +    })
 +}
 +
 +static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
 +
 +pub(crate) fn semantic_tokens(
 +    text: &str,
 +    line_index: &LineIndex,
 +    highlights: Vec<HlRange>,
 +) -> lsp_types::SemanticTokens {
 +    let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string();
 +    let mut builder = semantic_tokens::SemanticTokensBuilder::new(id);
 +
 +    for highlight_range in highlights {
 +        if highlight_range.highlight.is_empty() {
 +            continue;
 +        }
 +
 +        let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
 +        let token_index = semantic_tokens::type_index(ty);
 +        let modifier_bitset = mods.0;
 +
 +        for mut text_range in line_index.index.lines(highlight_range.range) {
 +            if text[text_range].ends_with('\n') {
 +                text_range =
 +                    TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n'));
 +            }
 +            let range = range(line_index, text_range);
 +            builder.push(range, token_index, modifier_bitset);
 +        }
 +    }
 +
 +    builder.build()
 +}
 +
 +pub(crate) fn semantic_token_delta(
 +    previous: &lsp_types::SemanticTokens,
 +    current: &lsp_types::SemanticTokens,
 +) -> lsp_types::SemanticTokensDelta {
 +    let result_id = current.result_id.clone();
 +    let edits = semantic_tokens::diff_tokens(&previous.data, &current.data);
 +    lsp_types::SemanticTokensDelta { result_id, edits }
 +}
 +
 +fn semantic_token_type_and_modifiers(
 +    highlight: Highlight,
 +) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) {
 +    let mut mods = semantic_tokens::ModifierSet::default();
 +    let type_ = match highlight.tag {
 +        HlTag::Symbol(symbol) => match symbol {
 +            SymbolKind::Attribute => semantic_tokens::DECORATOR,
 +            SymbolKind::Derive => semantic_tokens::DERIVE,
 +            SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER,
 +            SymbolKind::Module => semantic_tokens::NAMESPACE,
 +            SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
 +            SymbolKind::Field => semantic_tokens::PROPERTY,
 +            SymbolKind::TypeParam => semantic_tokens::TYPE_PARAMETER,
 +            SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
 +            SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
 +            SymbolKind::Label => semantic_tokens::LABEL,
 +            SymbolKind::ValueParam => semantic_tokens::PARAMETER,
 +            SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
 +            SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
 +            SymbolKind::Local => semantic_tokens::VARIABLE,
 +            SymbolKind::Function => {
 +                if highlight.mods.contains(HlMod::Associated) {
 +                    semantic_tokens::METHOD
 +                } else {
 +                    semantic_tokens::FUNCTION
 +                }
 +            }
 +            SymbolKind::Const => {
 +                mods |= semantic_tokens::CONSTANT;
 +                mods |= semantic_tokens::STATIC;
 +                semantic_tokens::VARIABLE
 +            }
 +            SymbolKind::Static => {
 +                mods |= semantic_tokens::STATIC;
 +                semantic_tokens::VARIABLE
 +            }
 +            SymbolKind::Struct => semantic_tokens::STRUCT,
 +            SymbolKind::Enum => semantic_tokens::ENUM,
 +            SymbolKind::Variant => semantic_tokens::ENUM_MEMBER,
 +            SymbolKind::Union => semantic_tokens::UNION,
 +            SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS,
 +            SymbolKind::Trait => semantic_tokens::INTERFACE,
 +            SymbolKind::Macro => semantic_tokens::MACRO,
 +            SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE,
 +            SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE,
 +        },
 +        HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET,
 +        HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
 +        HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
 +        HlTag::ByteLiteral | HlTag::NumericLiteral => semantic_tokens::NUMBER,
 +        HlTag::CharLiteral => semantic_tokens::CHAR,
 +        HlTag::Comment => semantic_tokens::COMMENT,
 +        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
 +        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
 +        HlTag::Keyword => semantic_tokens::KEYWORD,
 +        HlTag::None => semantic_tokens::GENERIC,
 +        HlTag::Operator(op) => match op {
 +            HlOperator::Bitwise => semantic_tokens::BITWISE,
 +            HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
 +            HlOperator::Logical => semantic_tokens::LOGICAL,
 +            HlOperator::Comparison => semantic_tokens::COMPARISON,
 +            HlOperator::Other => semantic_tokens::OPERATOR,
 +        },
 +        HlTag::StringLiteral => semantic_tokens::STRING,
 +        HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
 +        HlTag::Punctuation(punct) => match punct {
 +            HlPunct::Bracket => semantic_tokens::BRACKET,
 +            HlPunct::Brace => semantic_tokens::BRACE,
 +            HlPunct::Parenthesis => semantic_tokens::PARENTHESIS,
 +            HlPunct::Angle => semantic_tokens::ANGLE,
 +            HlPunct::Comma => semantic_tokens::COMMA,
 +            HlPunct::Dot => semantic_tokens::DOT,
 +            HlPunct::Colon => semantic_tokens::COLON,
 +            HlPunct::Semi => semantic_tokens::SEMICOLON,
 +            HlPunct::Other => semantic_tokens::PUNCTUATION,
 +            HlPunct::MacroBang => semantic_tokens::MACRO_BANG,
 +        },
 +    };
 +
 +    for modifier in highlight.mods.iter() {
 +        let modifier = match modifier {
 +            HlMod::Associated => continue,
 +            HlMod::Async => semantic_tokens::ASYNC,
 +            HlMod::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER,
 +            HlMod::Callable => semantic_tokens::CALLABLE,
 +            HlMod::Consuming => semantic_tokens::CONSUMING,
 +            HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
 +            HlMod::CrateRoot => semantic_tokens::CRATE_ROOT,
 +            HlMod::DefaultLibrary => semantic_tokens::DEFAULT_LIBRARY,
 +            HlMod::Definition => semantic_tokens::DECLARATION,
 +            HlMod::Documentation => semantic_tokens::DOCUMENTATION,
 +            HlMod::Injected => semantic_tokens::INJECTED,
 +            HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
 +            HlMod::Library => semantic_tokens::LIBRARY,
 +            HlMod::Mutable => semantic_tokens::MUTABLE,
 +            HlMod::Public => semantic_tokens::PUBLIC,
 +            HlMod::Reference => semantic_tokens::REFERENCE,
 +            HlMod::Static => semantic_tokens::STATIC,
 +            HlMod::Trait => semantic_tokens::TRAIT_MODIFIER,
 +            HlMod::Unsafe => semantic_tokens::UNSAFE,
 +        };
 +        mods |= modifier;
 +    }
 +
 +    (type_, mods)
 +}
 +
 +pub(crate) fn folding_range(
 +    text: &str,
 +    line_index: &LineIndex,
 +    line_folding_only: bool,
 +    fold: Fold,
 +) -> lsp_types::FoldingRange {
 +    let kind = match fold.kind {
 +        FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
 +        FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
 +        FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
 +        FoldKind::Mods
 +        | FoldKind::Block
 +        | FoldKind::ArgList
 +        | FoldKind::Consts
 +        | FoldKind::Statics
 +        | FoldKind::WhereClause
 +        | FoldKind::ReturnType
 +        | FoldKind::Array
 +        | FoldKind::MatchArm => None,
 +    };
 +
 +    let range = range(line_index, fold.range);
 +
 +    if line_folding_only {
 +        // Clients with line_folding_only == true (such as VSCode) will fold the whole end line
 +        // even if it contains text not in the folding range. To prevent that we exclude
 +        // range.end.line from the folding region if there is more text after range.end
 +        // on the same line.
 +        let has_more_text_on_end_line = text[TextRange::new(fold.range.end(), TextSize::of(text))]
 +            .chars()
 +            .take_while(|it| *it != '\n')
 +            .any(|it| !it.is_whitespace());
 +
 +        let end_line = if has_more_text_on_end_line {
 +            range.end.line.saturating_sub(1)
 +        } else {
 +            range.end.line
 +        };
 +
 +        lsp_types::FoldingRange {
 +            start_line: range.start.line,
 +            start_character: None,
 +            end_line,
 +            end_character: None,
 +            kind,
 +        }
 +    } else {
 +        lsp_types::FoldingRange {
 +            start_line: range.start.line,
 +            start_character: Some(range.start.character),
 +            end_line: range.end.line,
 +            end_character: Some(range.end.character),
 +            kind,
 +        }
 +    }
 +}
 +
 +pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> lsp_types::Url {
 +    snap.file_id_to_url(file_id)
 +}
 +
 +/// Returns a `Url` object from a given path, will lowercase drive letters if present.
 +/// This will only happen when processing windows paths.
 +///
 +/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
 +pub(crate) fn url_from_abs_path(path: &AbsPath) -> lsp_types::Url {
 +    let url = lsp_types::Url::from_file_path(path).unwrap();
 +    match path.as_ref().components().next() {
 +        Some(path::Component::Prefix(prefix))
 +            if matches!(prefix.kind(), path::Prefix::Disk(_) | path::Prefix::VerbatimDisk(_)) =>
 +        {
 +            // Need to lowercase driver letter
 +        }
 +        _ => return url,
 +    }
 +
 +    let driver_letter_range = {
 +        let (scheme, drive_letter, _rest) = match url.as_str().splitn(3, ':').collect_tuple() {
 +            Some(it) => it,
 +            None => return url,
 +        };
 +        let start = scheme.len() + ':'.len_utf8();
 +        start..(start + drive_letter.len())
 +    };
 +
 +    // Note: lowercasing the `path` itself doesn't help, the `Url::parse`
 +    // machinery *also* canonicalizes the drive letter. So, just massage the
 +    // string in place.
 +    let mut url: String = url.into();
 +    url[driver_letter_range].make_ascii_lowercase();
 +    lsp_types::Url::parse(&url).unwrap()
 +}
 +
 +pub(crate) fn optional_versioned_text_document_identifier(
 +    snap: &GlobalStateSnapshot,
 +    file_id: FileId,
 +) -> lsp_types::OptionalVersionedTextDocumentIdentifier {
 +    let url = url(snap, file_id);
 +    let version = snap.url_file_version(&url);
 +    lsp_types::OptionalVersionedTextDocumentIdentifier { uri: url, version }
 +}
 +
 +pub(crate) fn location(
 +    snap: &GlobalStateSnapshot,
 +    frange: FileRange,
 +) -> Result<lsp_types::Location> {
 +    let url = url(snap, frange.file_id);
 +    let line_index = snap.file_line_index(frange.file_id)?;
 +    let range = range(&line_index, frange.range);
 +    let loc = lsp_types::Location::new(url, range);
 +    Ok(loc)
 +}
 +
 +/// Prefer using `location_link`, if the client has the cap.
 +pub(crate) fn location_from_nav(
 +    snap: &GlobalStateSnapshot,
 +    nav: NavigationTarget,
 +) -> Result<lsp_types::Location> {
 +    let url = url(snap, nav.file_id);
 +    let line_index = snap.file_line_index(nav.file_id)?;
 +    let range = range(&line_index, nav.full_range);
 +    let loc = lsp_types::Location::new(url, range);
 +    Ok(loc)
 +}
 +
 +pub(crate) fn location_link(
 +    snap: &GlobalStateSnapshot,
 +    src: Option<FileRange>,
 +    target: NavigationTarget,
 +) -> Result<lsp_types::LocationLink> {
 +    let origin_selection_range = match src {
 +        Some(src) => {
 +            let line_index = snap.file_line_index(src.file_id)?;
 +            let range = range(&line_index, src.range);
 +            Some(range)
 +        }
 +        None => None,
 +    };
 +    let (target_uri, target_range, target_selection_range) = location_info(snap, target)?;
 +    let res = lsp_types::LocationLink {
 +        origin_selection_range,
 +        target_uri,
 +        target_range,
 +        target_selection_range,
 +    };
 +    Ok(res)
 +}
 +
 +fn location_info(
 +    snap: &GlobalStateSnapshot,
 +    target: NavigationTarget,
 +) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> {
 +    let line_index = snap.file_line_index(target.file_id)?;
 +
 +    let target_uri = url(snap, target.file_id);
 +    let target_range = range(&line_index, target.full_range);
 +    let target_selection_range =
 +        target.focus_range.map(|it| range(&line_index, it)).unwrap_or(target_range);
 +    Ok((target_uri, target_range, target_selection_range))
 +}
 +
 +pub(crate) fn goto_definition_response(
 +    snap: &GlobalStateSnapshot,
 +    src: Option<FileRange>,
 +    targets: Vec<NavigationTarget>,
 +) -> Result<lsp_types::GotoDefinitionResponse> {
 +    if snap.config.location_link() {
 +        let links = targets
 +            .into_iter()
 +            .map(|nav| location_link(snap, src, nav))
 +            .collect::<Result<Vec<_>>>()?;
 +        Ok(links.into())
 +    } else {
 +        let locations = targets
 +            .into_iter()
 +            .map(|nav| {
 +                location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
 +            })
 +            .collect::<Result<Vec<_>>>()?;
 +        Ok(locations.into())
 +    }
 +}
 +
 +fn outside_workspace_annotation_id() -> String {
 +    String::from("OutsideWorkspace")
 +}
 +
 +pub(crate) fn snippet_text_document_edit(
 +    snap: &GlobalStateSnapshot,
 +    is_snippet: bool,
 +    file_id: FileId,
 +    edit: TextEdit,
 +) -> Result<lsp_ext::SnippetTextDocumentEdit> {
 +    let text_document = optional_versioned_text_document_identifier(snap, file_id);
 +    let line_index = snap.file_line_index(file_id)?;
 +    let mut edits: Vec<_> =
 +        edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect();
 +
 +    if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() {
 +        for edit in &mut edits {
 +            edit.annotation_id = Some(outside_workspace_annotation_id())
 +        }
 +    }
 +    Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
 +}
 +
 +pub(crate) fn snippet_text_document_ops(
 +    snap: &GlobalStateSnapshot,
 +    file_system_edit: FileSystemEdit,
 +) -> Cancellable<Vec<lsp_ext::SnippetDocumentChangeOperation>> {
 +    let mut ops = Vec::new();
 +    match file_system_edit {
 +        FileSystemEdit::CreateFile { dst, initial_contents } => {
 +            let uri = snap.anchored_path(&dst);
 +            let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile {
 +                uri: uri.clone(),
 +                options: None,
 +                annotation_id: None,
 +            });
 +            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file));
 +            if !initial_contents.is_empty() {
 +                let text_document =
 +                    lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None };
 +                let text_edit = lsp_ext::SnippetTextEdit {
 +                    range: lsp_types::Range::default(),
 +                    new_text: initial_contents,
 +                    insert_text_format: Some(lsp_types::InsertTextFormat::PLAIN_TEXT),
 +                    annotation_id: None,
 +                };
 +                let edit_file =
 +                    lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] };
 +                ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file));
 +            }
 +        }
 +        FileSystemEdit::MoveFile { src, dst } => {
 +            let old_uri = snap.file_id_to_url(src);
 +            let new_uri = snap.anchored_path(&dst);
 +            let mut rename_file =
 +                lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None };
 +            if snap.analysis.is_library_file(src).ok() == Some(true)
 +                && snap.config.change_annotation_support()
 +            {
 +                rename_file.annotation_id = Some(outside_workspace_annotation_id())
 +            }
 +            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename(
 +                rename_file,
 +            )))
 +        }
 +        FileSystemEdit::MoveDir { src, src_id, dst } => {
 +            let old_uri = snap.anchored_path(&src);
 +            let new_uri = snap.anchored_path(&dst);
 +            let mut rename_file =
 +                lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None };
 +            if snap.analysis.is_library_file(src_id).ok() == Some(true)
 +                && snap.config.change_annotation_support()
 +            {
 +                rename_file.annotation_id = Some(outside_workspace_annotation_id())
 +            }
 +            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename(
 +                rename_file,
 +            )))
 +        }
 +    }
 +    Ok(ops)
 +}
 +
 +pub(crate) fn snippet_workspace_edit(
 +    snap: &GlobalStateSnapshot,
 +    source_change: SourceChange,
 +) -> Result<lsp_ext::SnippetWorkspaceEdit> {
 +    let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
 +
 +    for op in source_change.file_system_edits {
 +        let ops = snippet_text_document_ops(snap, op)?;
 +        document_changes.extend_from_slice(&ops);
 +    }
 +    for (file_id, edit) in source_change.source_file_edits {
 +        let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?;
 +        document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
 +    }
 +    let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit {
 +        changes: None,
 +        document_changes: Some(document_changes),
 +        change_annotations: None,
 +    };
 +    if snap.config.change_annotation_support() {
 +        workspace_edit.change_annotations = Some(
 +            once((
 +                outside_workspace_annotation_id(),
 +                lsp_types::ChangeAnnotation {
 +                    label: String::from("Edit outside of the workspace"),
 +                    needs_confirmation: Some(true),
 +                    description: Some(String::from(
 +                        "This edit lies outside of the workspace and may affect dependencies",
 +                    )),
 +                },
 +            ))
 +            .collect(),
 +        )
 +    }
 +    Ok(workspace_edit)
 +}
 +
 +pub(crate) fn workspace_edit(
 +    snap: &GlobalStateSnapshot,
 +    source_change: SourceChange,
 +) -> Result<lsp_types::WorkspaceEdit> {
 +    assert!(!source_change.is_snippet);
 +    snippet_workspace_edit(snap, source_change).map(|it| it.into())
 +}
 +
 +impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
 +    fn from(snippet_workspace_edit: lsp_ext::SnippetWorkspaceEdit) -> lsp_types::WorkspaceEdit {
 +        lsp_types::WorkspaceEdit {
 +            changes: None,
 +            document_changes: snippet_workspace_edit.document_changes.map(|changes| {
 +                lsp_types::DocumentChanges::Operations(
 +                    changes
 +                        .into_iter()
 +                        .map(|change| match change {
 +                            lsp_ext::SnippetDocumentChangeOperation::Op(op) => {
 +                                lsp_types::DocumentChangeOperation::Op(op)
 +                            }
 +                            lsp_ext::SnippetDocumentChangeOperation::Edit(edit) => {
 +                                lsp_types::DocumentChangeOperation::Edit(
 +                                    lsp_types::TextDocumentEdit {
 +                                        text_document: edit.text_document,
 +                                        edits: edit.edits.into_iter().map(From::from).collect(),
 +                                    },
 +                                )
 +                            }
 +                        })
 +                        .collect(),
 +                )
 +            }),
 +            change_annotations: snippet_workspace_edit.change_annotations,
 +        }
 +    }
 +}
 +
 +impl From<lsp_ext::SnippetTextEdit>
 +    for lsp_types::OneOf<lsp_types::TextEdit, lsp_types::AnnotatedTextEdit>
 +{
 +    fn from(
 +        lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit,
 +    ) -> Self {
 +        match annotation_id {
 +            Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {
 +                text_edit: lsp_types::TextEdit { range, new_text },
 +                annotation_id,
 +            }),
 +            None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }),
 +        }
 +    }
 +}
 +
 +pub(crate) fn call_hierarchy_item(
 +    snap: &GlobalStateSnapshot,
 +    target: NavigationTarget,
 +) -> Result<lsp_types::CallHierarchyItem> {
 +    let name = target.name.to_string();
 +    let detail = target.description.clone();
 +    let kind = target.kind.map(symbol_kind).unwrap_or(lsp_types::SymbolKind::FUNCTION);
 +    let (uri, range, selection_range) = location_info(snap, target)?;
 +    Ok(lsp_types::CallHierarchyItem {
 +        name,
 +        kind,
 +        tags: None,
 +        detail,
 +        uri,
 +        range,
 +        selection_range,
 +        data: None,
 +    })
 +}
 +
 +pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
 +    match kind {
 +        AssistKind::None | AssistKind::Generate => lsp_types::CodeActionKind::EMPTY,
 +        AssistKind::QuickFix => lsp_types::CodeActionKind::QUICKFIX,
 +        AssistKind::Refactor => lsp_types::CodeActionKind::REFACTOR,
 +        AssistKind::RefactorExtract => lsp_types::CodeActionKind::REFACTOR_EXTRACT,
 +        AssistKind::RefactorInline => lsp_types::CodeActionKind::REFACTOR_INLINE,
 +        AssistKind::RefactorRewrite => lsp_types::CodeActionKind::REFACTOR_REWRITE,
 +    }
 +}
 +
 +pub(crate) fn code_action(
 +    snap: &GlobalStateSnapshot,
 +    assist: Assist,
 +    resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
 +) -> Result<lsp_ext::CodeAction> {
 +    let mut res = lsp_ext::CodeAction {
 +        title: assist.label.to_string(),
 +        group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
 +        kind: Some(code_action_kind(assist.id.1)),
 +        edit: None,
 +        is_preferred: None,
 +        data: None,
 +        command: None,
 +    };
 +
 +    if assist.trigger_signature_help && snap.config.client_commands().trigger_parameter_hints {
 +        res.command = Some(command::trigger_parameter_hints());
 +    }
 +
 +    match (assist.source_change, resolve_data) {
 +        (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
 +        (None, Some((index, code_action_params))) => {
 +            res.data = Some(lsp_ext::CodeActionData {
 +                id: format!("{}:{}:{}", assist.id.0, assist.id.1.name(), index),
 +                code_action_params,
 +            });
 +        }
 +        (None, None) => {
 +            stdx::never!("assist should always be resolved if client can't do lazy resolving")
 +        }
 +    };
 +    Ok(res)
 +}
 +
 +pub(crate) fn runnable(
 +    snap: &GlobalStateSnapshot,
 +    runnable: Runnable,
 +) -> Result<lsp_ext::Runnable> {
 +    let config = snap.config.runnables();
 +    let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?;
 +    let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone());
 +    let target = spec.as_ref().map(|s| s.target.clone());
 +    let (cargo_args, executable_args) =
 +        CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg)?;
 +    let label = runnable.label(target);
 +    let location = location_link(snap, None, runnable.nav)?;
 +
 +    Ok(lsp_ext::Runnable {
 +        label,
 +        location: Some(location),
 +        kind: lsp_ext::RunnableKind::Cargo,
 +        args: lsp_ext::CargoRunnable {
 +            workspace_root: workspace_root.map(|it| it.into()),
 +            override_cargo: config.override_cargo,
 +            cargo_args,
 +            cargo_extra_args: config.cargo_extra_args,
 +            executable_args,
 +            expect_test: None,
 +        },
 +    })
 +}
 +
 +pub(crate) fn code_lens(
 +    acc: &mut Vec<lsp_types::CodeLens>,
 +    snap: &GlobalStateSnapshot,
 +    annotation: Annotation,
 +) -> Result<()> {
 +    let client_commands_config = snap.config.client_commands();
 +    match annotation.kind {
 +        AnnotationKind::Runnable(run) => {
 +            let line_index = snap.file_line_index(run.nav.file_id)?;
 +            let annotation_range = range(&line_index, annotation.range);
 +
 +            let title = run.title();
 +            let can_debug = match run.kind {
 +                ide::RunnableKind::DocTest { .. } => false,
 +                ide::RunnableKind::TestMod { .. }
 +                | ide::RunnableKind::Test { .. }
 +                | ide::RunnableKind::Bench { .. }
 +                | ide::RunnableKind::Bin => true,
 +            };
 +            let r = runnable(snap, run)?;
 +
 +            let lens_config = snap.config.lens();
 +            if lens_config.run && client_commands_config.run_single {
 +                let command = command::run_single(&r, &title);
 +                acc.push(lsp_types::CodeLens {
 +                    range: annotation_range,
 +                    command: Some(command),
 +                    data: None,
 +                })
 +            }
 +            if lens_config.debug && can_debug && client_commands_config.debug_single {
 +                let command = command::debug_single(&r);
 +                acc.push(lsp_types::CodeLens {
 +                    range: annotation_range,
 +                    command: Some(command),
 +                    data: None,
 +                })
 +            }
 +        }
 +        AnnotationKind::HasImpls { file_id, data } => {
 +            if !client_commands_config.show_reference {
 +                return Ok(());
 +            }
 +            let line_index = snap.file_line_index(file_id)?;
 +            let annotation_range = range(&line_index, annotation.range);
 +            let url = url(snap, file_id);
 +
 +            let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 +
 +            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start);
 +
 +            let goto_params = lsp_types::request::GotoImplementationParams {
 +                text_document_position_params: doc_pos,
 +                work_done_progress_params: Default::default(),
 +                partial_result_params: Default::default(),
 +            };
 +
 +            let command = data.map(|ranges| {
 +                let locations: Vec<lsp_types::Location> = ranges
 +                    .into_iter()
 +                    .filter_map(|target| {
 +                        location(
 +                            snap,
 +                            FileRange { file_id: target.file_id, range: target.full_range },
 +                        )
 +                        .ok()
 +                    })
 +                    .collect();
 +
 +                command::show_references(
 +                    implementation_title(locations.len()),
 +                    &url,
 +                    annotation_range.start,
 +                    locations,
 +                )
 +            });
 +
 +            acc.push(lsp_types::CodeLens {
 +                range: annotation_range,
 +                command,
 +                data: Some(to_value(lsp_ext::CodeLensResolveData::Impls(goto_params)).unwrap()),
 +            })
 +        }
 +        AnnotationKind::HasReferences { file_id, data } => {
 +            if !client_commands_config.show_reference {
 +                return Ok(());
 +            }
 +            let line_index = snap.file_line_index(file_id)?;
 +            let annotation_range = range(&line_index, annotation.range);
 +            let url = url(snap, file_id);
 +
 +            let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 +
 +            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start);
 +
 +            let command = data.map(|ranges| {
 +                let locations: Vec<lsp_types::Location> =
 +                    ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect();
 +
 +                command::show_references(
 +                    reference_title(locations.len()),
 +                    &url,
 +                    annotation_range.start,
 +                    locations,
 +                )
 +            });
 +
 +            acc.push(lsp_types::CodeLens {
 +                range: annotation_range,
 +                command,
 +                data: Some(to_value(lsp_ext::CodeLensResolveData::References(doc_pos)).unwrap()),
 +            })
 +        }
 +    }
 +    Ok(())
 +}
 +
 +pub(crate) mod command {
 +    use ide::{FileRange, NavigationTarget};
 +    use serde_json::to_value;
 +
 +    use crate::{
 +        global_state::GlobalStateSnapshot,
 +        lsp_ext,
 +        to_proto::{location, location_link},
 +    };
 +
 +    pub(crate) fn show_references(
 +        title: String,
 +        uri: &lsp_types::Url,
 +        position: lsp_types::Position,
 +        locations: Vec<lsp_types::Location>,
 +    ) -> lsp_types::Command {
 +        // We cannot use the 'editor.action.showReferences' command directly
 +        // because that command requires vscode types which we convert in the handler
 +        // on the client side.
 +
 +        lsp_types::Command {
 +            title,
 +            command: "rust-analyzer.showReferences".into(),
 +            arguments: Some(vec![
 +                to_value(uri).unwrap(),
 +                to_value(position).unwrap(),
 +                to_value(locations).unwrap(),
 +            ]),
 +        }
 +    }
 +
 +    pub(crate) fn run_single(runnable: &lsp_ext::Runnable, title: &str) -> lsp_types::Command {
 +        lsp_types::Command {
 +            title: title.to_string(),
 +            command: "rust-analyzer.runSingle".into(),
 +            arguments: Some(vec![to_value(runnable).unwrap()]),
 +        }
 +    }
 +
 +    pub(crate) fn debug_single(runnable: &lsp_ext::Runnable) -> lsp_types::Command {
 +        lsp_types::Command {
 +            title: "Debug".into(),
 +            command: "rust-analyzer.debugSingle".into(),
 +            arguments: Some(vec![to_value(runnable).unwrap()]),
 +        }
 +    }
 +
 +    pub(crate) fn goto_location(
 +        snap: &GlobalStateSnapshot,
 +        nav: &NavigationTarget,
 +    ) -> Option<lsp_types::Command> {
 +        let value = if snap.config.location_link() {
 +            let link = location_link(snap, None, nav.clone()).ok()?;
 +            to_value(link).ok()?
 +        } else {
 +            let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() };
 +            let location = location(snap, range).ok()?;
 +            to_value(location).ok()?
 +        };
 +
 +        Some(lsp_types::Command {
 +            title: nav.name.to_string(),
 +            command: "rust-analyzer.gotoLocation".into(),
 +            arguments: Some(vec![value]),
 +        })
 +    }
 +
 +    pub(crate) fn trigger_parameter_hints() -> lsp_types::Command {
 +        lsp_types::Command {
 +            title: "triggerParameterHints".into(),
 +            command: "editor.action.triggerParameterHints".into(),
 +            arguments: None,
 +        }
 +    }
 +}
 +
 +pub(crate) fn implementation_title(count: usize) -> String {
 +    if count == 1 {
 +        "1 implementation".into()
 +    } else {
 +        format!("{} implementations", count)
 +    }
 +}
 +
 +pub(crate) fn reference_title(count: usize) -> String {
 +    if count == 1 {
 +        "1 reference".into()
 +    } else {
 +        format!("{} references", count)
 +    }
 +}
 +
 +pub(crate) fn markup_content(
 +    markup: Markup,
 +    kind: ide::HoverDocFormat,
 +) -> lsp_types::MarkupContent {
 +    let kind = match kind {
 +        ide::HoverDocFormat::Markdown => lsp_types::MarkupKind::Markdown,
 +        ide::HoverDocFormat::PlainText => lsp_types::MarkupKind::PlainText,
 +    };
 +    let value = crate::markdown::format_docs(markup.as_str());
 +    lsp_types::MarkupContent { kind, value }
 +}
 +
 +pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
 +    // This is wrong, but we don't have a better alternative I suppose?
 +    // https://github.com/microsoft/language-server-protocol/issues/1341
 +    invalid_params_error(err.to_string())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::sync::Arc;
 +
 +    use ide::Analysis;
 +
 +    use super::*;
 +
 +    #[test]
 +    fn conv_fold_line_folding_only_fixup() {
 +        let text = r#"mod a;
 +mod b;
 +mod c;
 +
 +fn main() {
 +    if cond {
 +        a::do_a();
 +    } else {
 +        b::do_b();
 +    }
 +}"#;
 +
 +        let (analysis, file_id) = Analysis::from_single_file(text.to_string());
 +        let folds = analysis.folding_ranges(file_id).unwrap();
 +        assert_eq!(folds.len(), 4);
 +
 +        let line_index = LineIndex {
 +            index: Arc::new(ide::LineIndex::new(text)),
 +            endings: LineEndings::Unix,
 +            encoding: OffsetEncoding::Utf16,
 +        };
 +        let converted: Vec<lsp_types::FoldingRange> =
 +            folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect();
 +
 +        let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
 +        assert_eq!(converted.len(), expected_lines.len());
 +        for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) {
 +            assert_eq!(folding_range.start_line, *start_line);
 +            assert_eq!(folding_range.start_character, None);
 +            assert_eq!(folding_range.end_line, *end_line);
 +            assert_eq!(folding_range.end_character, None);
 +        }
 +    }
 +
 +    // `Url` is not able to parse windows paths on unix machines.
 +    #[test]
 +    #[cfg(target_os = "windows")]
 +    fn test_lowercase_drive_letter() {
 +        use std::path::Path;
 +
 +        let url = url_from_abs_path(Path::new("C:\\Test").try_into().unwrap());
 +        assert_eq!(url.to_string(), "file:///c:/Test");
 +
 +        let url = url_from_abs_path(Path::new(r#"\\localhost\C$\my_dir"#).try_into().unwrap());
 +        assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
 +    }
 +}
index 72b925726479e014c18142acb6b4546bffc2b2b8,0000000000000000000000000000000000000000..996d4c023d7b2a04799033a96af490c27662b709
mode 100644,000000..100644
--- /dev/null
@@@ -1,676 -1,0 +1,702 @@@
 +[[rust-analyzer.assist.expressionFillDefault]]rust-analyzer.assist.expressionFillDefault (default: `"todo"`)::
 ++
 +--
 +Placeholder expression to use for missing expressions in assists.
 +--
 +[[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`)::
 ++
 +--
 +Warm up caches on project load.
 +--
 +[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `0`)::
 ++
 +--
 +How many worker threads to handle priming caches. The default `0` means to pick automatically.
 +--
 +[[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`)::
 ++
 +--
 +Automatically refresh project info via `cargo metadata` on
 +`Cargo.toml` or `.cargo/config.toml` changes.
 +--
 +[[rust-analyzer.cargo.buildScripts.enable]]rust-analyzer.cargo.buildScripts.enable (default: `true`)::
 ++
 +--
 +Run build scripts (`build.rs`) for more precise code analysis.
 +--
 +[[rust-analyzer.cargo.buildScripts.overrideCommand]]rust-analyzer.cargo.buildScripts.overrideCommand (default: `null`)::
 ++
 +--
 +Override the command rust-analyzer uses to run build scripts and
 +build procedural macros. The command is required to output json
 +and should therefore include `--message-format=json` or a similar
 +option.
 +
 +By default, a cargo invocation will be constructed for the configured
 +targets and features, with the following base command line:
 +
 +```bash
 +cargo check --quiet --workspace --message-format=json --all-targets
 +```
 +.
 +--
 +[[rust-analyzer.cargo.buildScripts.useRustcWrapper]]rust-analyzer.cargo.buildScripts.useRustcWrapper (default: `true`)::
 ++
 +--
 +Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
 +avoid checking unnecessary things.
 +--
++[[rust-analyzer.cargo.extraEnv]]rust-analyzer.cargo.extraEnv (default: `{}`)::
+++
++--
++Extra environment variables that will be set when running cargo, rustc
++or other commands within the workspace. Useful for setting RUSTFLAGS.
++--
 +[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
 ++
 +--
 +List of features to activate.
 +
 +Set this to `"all"` to pass `--all-features` to cargo.
 +--
 +[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`)::
 ++
 +--
 +Whether to pass `--no-default-features` to cargo.
 +--
 +[[rust-analyzer.cargo.noSysroot]]rust-analyzer.cargo.noSysroot (default: `false`)::
 ++
 +--
 +Internal config for debugging, disables loading of sysroot crates.
 +--
 +[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
 ++
 +--
 +Compilation target override (target triple).
 +--
 +[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
 ++
 +--
 +Unsets `#[cfg(test)]` for the specified crates.
 +--
 +[[rust-analyzer.checkOnSave.allTargets]]rust-analyzer.checkOnSave.allTargets (default: `true`)::
 ++
 +--
 +Check all targets and tests (`--all-targets`).
 +--
 +[[rust-analyzer.checkOnSave.command]]rust-analyzer.checkOnSave.command (default: `"check"`)::
 ++
 +--
 +Cargo command to use for `cargo check`.
 +--
 +[[rust-analyzer.checkOnSave.enable]]rust-analyzer.checkOnSave.enable (default: `true`)::
 ++
 +--
 +Run specified `cargo check` command for diagnostics on save.
 +--
 +[[rust-analyzer.checkOnSave.extraArgs]]rust-analyzer.checkOnSave.extraArgs (default: `[]`)::
 ++
 +--
 +Extra arguments for `cargo check`.
 +--
++[[rust-analyzer.checkOnSave.extraEnv]]rust-analyzer.checkOnSave.extraEnv (default: `{}`)::
+++
++--
++Extra environment variables that will be set when running `cargo check`.
++--
 +[[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`)::
 ++
 +--
 +List of features to activate. Defaults to
 +`#rust-analyzer.cargo.features#`.
 +
 +Set to `"all"` to pass `--all-features` to Cargo.
 +--
 +[[rust-analyzer.checkOnSave.noDefaultFeatures]]rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`)::
 ++
 +--
 +Whether to pass `--no-default-features` to Cargo. Defaults to
 +`#rust-analyzer.cargo.noDefaultFeatures#`.
 +--
 +[[rust-analyzer.checkOnSave.overrideCommand]]rust-analyzer.checkOnSave.overrideCommand (default: `null`)::
 ++
 +--
 +Override the command rust-analyzer uses instead of `cargo check` for
 +diagnostics on save. The command is required to output json and
 +should therefor include `--message-format=json` or a similar option.
 +
 +If you're changing this because you're using some tool wrapping
 +Cargo, you might also want to change
 +`#rust-analyzer.cargo.buildScripts.overrideCommand#`.
 +
 +If there are multiple linked projects, this command is invoked for
 +each of them, with the working directory being the project root
 +(i.e., the folder containing the `Cargo.toml`).
 +
 +An example command would be:
 +
 +```bash
 +cargo check --workspace --message-format=json --all-targets
 +```
 +.
 +--
 +[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
 ++
 +--
 +Check for a specific target. Defaults to
 +`#rust-analyzer.cargo.target#`.
 +--
 +[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 ++
 +--
 +Toggles the additional completions that automatically add imports when completed.
 +Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 +--
 +[[rust-analyzer.completion.autoself.enable]]rust-analyzer.completion.autoself.enable (default: `true`)::
 ++
 +--
 +Toggles the additional completions that automatically show method calls and field accesses
 +with `self` prefixed to them when inside a method.
 +--
 +[[rust-analyzer.completion.callable.snippets]]rust-analyzer.completion.callable.snippets (default: `"fill_arguments"`)::
 ++
 +--
 +Whether to add parenthesis and argument snippets when completing function.
 +--
 +[[rust-analyzer.completion.postfix.enable]]rust-analyzer.completion.postfix.enable (default: `true`)::
 ++
 +--
 +Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 +--
 +[[rust-analyzer.completion.privateEditable.enable]]rust-analyzer.completion.privateEditable.enable (default: `false`)::
 ++
 +--
 +Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
 +--
 +[[rust-analyzer.completion.snippets.custom]]rust-analyzer.completion.snippets.custom::
 ++
 +--
 +Default:
 +----
 +{
 +            "Arc::new": {
 +                "postfix": "arc",
 +                "body": "Arc::new(${receiver})",
 +                "requires": "std::sync::Arc",
 +                "description": "Put the expression into an `Arc`",
 +                "scope": "expr"
 +            },
 +            "Rc::new": {
 +                "postfix": "rc",
 +                "body": "Rc::new(${receiver})",
 +                "requires": "std::rc::Rc",
 +                "description": "Put the expression into an `Rc`",
 +                "scope": "expr"
 +            },
 +            "Box::pin": {
 +                "postfix": "pinbox",
 +                "body": "Box::pin(${receiver})",
 +                "requires": "std::boxed::Box",
 +                "description": "Put the expression into a pinned `Box`",
 +                "scope": "expr"
 +            },
 +            "Ok": {
 +                "postfix": "ok",
 +                "body": "Ok(${receiver})",
 +                "description": "Wrap the expression in a `Result::Ok`",
 +                "scope": "expr"
 +            },
 +            "Err": {
 +                "postfix": "err",
 +                "body": "Err(${receiver})",
 +                "description": "Wrap the expression in a `Result::Err`",
 +                "scope": "expr"
 +            },
 +            "Some": {
 +                "postfix": "some",
 +                "body": "Some(${receiver})",
 +                "description": "Wrap the expression in an `Option::Some`",
 +                "scope": "expr"
 +            }
 +        }
 +----
 +Custom completion snippets.
 +
 +--
 +[[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 ++
 +--
 +List of rust-analyzer diagnostics to disable.
 +--
 +[[rust-analyzer.diagnostics.enable]]rust-analyzer.diagnostics.enable (default: `true`)::
 ++
 +--
 +Whether to show native rust-analyzer diagnostics.
 +--
 +[[rust-analyzer.diagnostics.experimental.enable]]rust-analyzer.diagnostics.experimental.enable (default: `false`)::
 ++
 +--
 +Whether to show experimental rust-analyzer diagnostics that might
 +have more false positives than usual.
 +--
 +[[rust-analyzer.diagnostics.remapPrefix]]rust-analyzer.diagnostics.remapPrefix (default: `{}`)::
 ++
 +--
 +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`.
 +--
 +[[rust-analyzer.diagnostics.warningsAsHint]]rust-analyzer.diagnostics.warningsAsHint (default: `[]`)::
 ++
 +--
 +List of warnings that should be displayed with hint severity.
 +
 +The warnings will be indicated by faded text or three dots in code
 +and will not show up in the `Problems Panel`.
 +--
 +[[rust-analyzer.diagnostics.warningsAsInfo]]rust-analyzer.diagnostics.warningsAsInfo (default: `[]`)::
 ++
 +--
 +List of warnings that should be displayed with info severity.
 +
 +The warnings will be indicated by a blue squiggly underline in code
 +and a blue icon in the `Problems Panel`.
 +--
 +[[rust-analyzer.files.excludeDirs]]rust-analyzer.files.excludeDirs (default: `[]`)::
 ++
 +--
 +These directories will be ignored by rust-analyzer. They are
 +relative to the workspace root, and globs are not supported. You may
 +also need to add the folders to Code's `files.watcherExclude`.
 +--
 +[[rust-analyzer.files.watcher]]rust-analyzer.files.watcher (default: `"client"`)::
 ++
 +--
 +Controls file watching implementation.
 +--
 +[[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
 +--
 +[[rust-analyzer.highlightRelated.exitPoints.enable]]rust-analyzer.highlightRelated.exitPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
 +--
 +[[rust-analyzer.highlightRelated.references.enable]]rust-analyzer.highlightRelated.references.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of related references while the cursor is on any identifier.
 +--
 +[[rust-analyzer.highlightRelated.yieldPoints.enable]]rust-analyzer.highlightRelated.yieldPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
 +--
 +[[rust-analyzer.hover.actions.debug.enable]]rust-analyzer.hover.actions.debug.enable (default: `true`)::
 ++
 +--
 +Whether to show `Debug` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.enable]]rust-analyzer.hover.actions.enable (default: `true`)::
 ++
 +--
 +Whether to show HoverActions in Rust files.
 +--
 +[[rust-analyzer.hover.actions.gotoTypeDef.enable]]rust-analyzer.hover.actions.gotoTypeDef.enable (default: `true`)::
 ++
 +--
 +Whether to show `Go to Type Definition` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.implementations.enable]]rust-analyzer.hover.actions.implementations.enable (default: `true`)::
 ++
 +--
 +Whether to show `Implementations` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.references.enable]]rust-analyzer.hover.actions.references.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.run.enable]]rust-analyzer.hover.actions.run.enable (default: `true`)::
 ++
 +--
 +Whether to show `Run` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.documentation.enable]]rust-analyzer.hover.documentation.enable (default: `true`)::
 ++
 +--
 +Whether to show documentation on hover.
 +--
 +[[rust-analyzer.hover.documentation.keywords.enable]]rust-analyzer.hover.documentation.keywords.enable (default: `true`)::
 ++
 +--
 +Whether to show keyword hover popups. Only applies when
 +`#rust-analyzer.hover.documentation.enable#` is set.
 +--
 +[[rust-analyzer.hover.links.enable]]rust-analyzer.hover.links.enable (default: `true`)::
 ++
 +--
 +Use markdown syntax for links in hover.
 +--
 +[[rust-analyzer.imports.granularity.enforce]]rust-analyzer.imports.granularity.enforce (default: `false`)::
 ++
 +--
 +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.
 +--
 +[[rust-analyzer.imports.granularity.group]]rust-analyzer.imports.granularity.group (default: `"crate"`)::
 ++
 +--
 +How imports should be grouped into use statements.
 +--
 +[[rust-analyzer.imports.group.enable]]rust-analyzer.imports.group.enable (default: `true`)::
 ++
 +--
 +Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
 +--
 +[[rust-analyzer.imports.merge.glob]]rust-analyzer.imports.merge.glob (default: `true`)::
 ++
 +--
 +Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 +--
++[[rust-analyzer.imports.prefer.no.std]]rust-analyzer.imports.prefer.no.std (default: `false`)::
+++
++--
++Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
++--
 +[[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`)::
 ++
 +--
 +The path structure for newly inserted paths to use.
 +--
 +[[rust-analyzer.inlayHints.bindingModeHints.enable]]rust-analyzer.inlayHints.bindingModeHints.enable (default: `false`)::
 ++
 +--
 +Whether to show inlay type hints for binding modes.
 +--
 +[[rust-analyzer.inlayHints.chainingHints.enable]]rust-analyzer.inlayHints.chainingHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay type hints for method chains.
 +--
 +[[rust-analyzer.inlayHints.closingBraceHints.enable]]rust-analyzer.inlayHints.closingBraceHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
 +--
 +[[rust-analyzer.inlayHints.closingBraceHints.minLines]]rust-analyzer.inlayHints.closingBraceHints.minLines (default: `25`)::
 ++
 +--
 +Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
 +to always show them).
 +--
 +[[rust-analyzer.inlayHints.closureReturnTypeHints.enable]]rust-analyzer.inlayHints.closureReturnTypeHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for return types of closures.
 +--
 +[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for elided lifetimes in function signatures.
 +--
 +[[rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames]]rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames (default: `false`)::
 ++
 +--
 +Whether to prefer using parameter names as the name for elided lifetime hints if possible.
 +--
 +[[rust-analyzer.inlayHints.maxLength]]rust-analyzer.inlayHints.maxLength (default: `25`)::
 ++
 +--
 +Maximum length for inlay hints. Set to null to have an unlimited length.
 +--
 +[[rust-analyzer.inlayHints.parameterHints.enable]]rust-analyzer.inlayHints.parameterHints.enable (default: `true`)::
 ++
 +--
 +Whether to show function parameter name inlay hints at the call
 +site.
 +--
 +[[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for compiler inserted reborrows.
 +--
 +[[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`)::
 ++
 +--
 +Whether to render leading colons for type hints, and trailing colons for parameter hints.
 +--
 +[[rust-analyzer.inlayHints.typeHints.enable]]rust-analyzer.inlayHints.typeHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay type hints for variables.
 +--
 +[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`)::
 ++
 +--
 +Whether to hide inlay type hints for `let` statements that initialize to a closure.
 +Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
 +--
 +[[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`)::
 ++
 +--
 +Whether to hide inlay type hints for constructors.
 +--
 +[[rust-analyzer.joinLines.joinAssignments]]rust-analyzer.joinLines.joinAssignments (default: `true`)::
 ++
 +--
 +Join lines merges consecutive declaration and initialization of an assignment.
 +--
 +[[rust-analyzer.joinLines.joinElseIf]]rust-analyzer.joinLines.joinElseIf (default: `true`)::
 ++
 +--
 +Join lines inserts else between consecutive ifs.
 +--
 +[[rust-analyzer.joinLines.removeTrailingComma]]rust-analyzer.joinLines.removeTrailingComma (default: `true`)::
 ++
 +--
 +Join lines removes trailing commas.
 +--
 +[[rust-analyzer.joinLines.unwrapTrivialBlock]]rust-analyzer.joinLines.unwrapTrivialBlock (default: `true`)::
 ++
 +--
 +Join lines unwraps trivial blocks.
 +--
 +[[rust-analyzer.lens.debug.enable]]rust-analyzer.lens.debug.enable (default: `true`)::
 ++
 +--
 +Whether to show `Debug` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.enable]]rust-analyzer.lens.enable (default: `true`)::
 ++
 +--
 +Whether to show CodeLens in Rust files.
 +--
 +[[rust-analyzer.lens.forceCustomCommands]]rust-analyzer.lens.forceCustomCommands (default: `true`)::
 ++
 +--
 +Internal config: use custom client-side commands even when the
 +client doesn't set the corresponding capability.
 +--
 +[[rust-analyzer.lens.implementations.enable]]rust-analyzer.lens.implementations.enable (default: `true`)::
 ++
 +--
 +Whether to show `Implementations` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
++[[rust-analyzer.lens.location]]rust-analyzer.lens.location (default: `"above_name"`)::
+++
++--
++Where to render annotations.
++--
 +[[rust-analyzer.lens.references.adt.enable]]rust-analyzer.lens.references.adt.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Struct, Enum, and Union.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.enumVariant.enable]]rust-analyzer.lens.references.enumVariant.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Enum Variants.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.method.enable]]rust-analyzer.lens.references.method.enable (default: `false`)::
 ++
 +--
 +Whether to show `Method References` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.trait.enable]]rust-analyzer.lens.references.trait.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Trait.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.run.enable]]rust-analyzer.lens.run.enable (default: `true`)::
 ++
 +--
 +Whether to show `Run` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`)::
 ++
 +--
 +Disable project auto-discovery in favor of explicitly specified set
 +of projects.
 +
 +Elements must be paths pointing to `Cargo.toml`,
 +`rust-project.json`, or JSON objects in `rust-project.json` format.
 +--
 +[[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`)::
 ++
 +--
 +Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
 +--
 +[[rust-analyzer.notifications.cargoTomlNotFound]]rust-analyzer.notifications.cargoTomlNotFound (default: `true`)::
 ++
 +--
 +Whether to show `can't find Cargo.toml` error message.
 +--
 +[[rust-analyzer.procMacro.attributes.enable]]rust-analyzer.procMacro.attributes.enable (default: `true`)::
 ++
 +--
 +Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
 +--
 +[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `true`)::
 ++
 +--
 +Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
 +--
 +[[rust-analyzer.procMacro.ignored]]rust-analyzer.procMacro.ignored (default: `{}`)::
 ++
 +--
 +These proc-macros will be ignored when trying to expand them.
 +
 +This config takes a map of crate names with the exported proc-macro names to ignore as values.
 +--
 +[[rust-analyzer.procMacro.server]]rust-analyzer.procMacro.server (default: `null`)::
 ++
 +--
 +Internal config, path to proc-macro server executable (typically,
 +this is rust-analyzer itself, but we override this in tests).
 +--
++[[rust-analyzer.references.excludeImports]]rust-analyzer.references.excludeImports (default: `false`)::
+++
++--
++Exclude imports from find-all-references.
++--
 +[[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
 ++
 +--
 +Command to be executed instead of 'cargo' for runnables.
 +--
 +[[rust-analyzer.runnables.extraArgs]]rust-analyzer.runnables.extraArgs (default: `[]`)::
 ++
 +--
 +Additional arguments to be passed to cargo for runnables such as
 +tests or binaries. For example, it may be `--release`.
 +--
 +[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
 ++
 +--
 +Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
 +projects, or "discover" to try to automatically find it if the `rustc-dev` component
 +is installed.
 +
 +Any project which uses rust-analyzer with the rustcPrivate
 +crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
 +
 +This option does not take effect until rust-analyzer is restarted.
 +--
 +[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
 ++
 +--
 +Additional arguments to `rustfmt`.
 +--
 +[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
 ++
 +--
 +Advanced option, fully override the command rust-analyzer uses for
 +formatting.
 +--
 +[[rust-analyzer.rustfmt.rangeFormatting.enable]]rust-analyzer.rustfmt.rangeFormatting.enable (default: `false`)::
 ++
 +--
 +Enables the use of rustfmt's unstable range formatting command for the
 +`textDocument/rangeFormatting` request. The rustfmt option is unstable and only
 +available on a nightly build.
 +--
 +[[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`)::
 ++
 +--
 +Inject additional highlighting into doc comments.
 +
 +When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
 +doc links.
 +--
 +[[rust-analyzer.semanticHighlighting.operator.enable]]rust-analyzer.semanticHighlighting.operator.enable (default: `true`)::
 ++
 +--
 +Use semantic tokens for operators.
 +
 +When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
 +they are tagged with modifiers.
 +--
 +[[rust-analyzer.semanticHighlighting.operator.specialization.enable]]rust-analyzer.semanticHighlighting.operator.specialization.enable (default: `false`)::
 ++
 +--
 +Use specialized semantic tokens for operators.
 +
 +When enabled, rust-analyzer will emit special token types for operator tokens instead
 +of the generic `operator` token type.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.enable]]rust-analyzer.semanticHighlighting.punctuation.enable (default: `false`)::
 ++
 +--
 +Use semantic tokens for punctuations.
 +
 +When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
 +they are tagged with modifiers or have a special role.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang]]rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang (default: `false`)::
 ++
 +--
 +When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
 +calls.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.specialization.enable]]rust-analyzer.semanticHighlighting.punctuation.specialization.enable (default: `false`)::
 ++
 +--
 +Use specialized semantic tokens for punctuations.
 +
 +When enabled, rust-analyzer will emit special token types for punctuation tokens instead
 +of the generic `punctuation` token type.
 +--
 +[[rust-analyzer.semanticHighlighting.strings.enable]]rust-analyzer.semanticHighlighting.strings.enable (default: `true`)::
 ++
 +--
 +Use semantic tokens for strings.
 +
 +In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
 +By disabling semantic tokens for strings, other grammars can be used to highlight
 +their contents.
 +--
 +[[rust-analyzer.signatureInfo.detail]]rust-analyzer.signatureInfo.detail (default: `"full"`)::
 ++
 +--
 +Show full signature of the callable. Only shows parameters if disabled.
 +--
 +[[rust-analyzer.signatureInfo.documentation.enable]]rust-analyzer.signatureInfo.documentation.enable (default: `true`)::
 ++
 +--
 +Show documentation.
 +--
 +[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`)::
 ++
 +--
 +Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
 +--
 +[[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`)::
 ++
 +--
 +Workspace symbol search kind.
 +--
 +[[rust-analyzer.workspace.symbol.search.limit]]rust-analyzer.workspace.symbol.search.limit (default: `128`)::
 ++
 +--
 +Limits the number of items returned from a workspace symbol search (Defaults to 128).
 +Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
 +Other clients requires all results upfront and might require a higher limit.
 +--
 +[[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`)::
 ++
 +--
 +Workspace symbol search scope.
 +--
index 767c5875bf7e7e844c1178675ee082288ff1ac29,0000000000000000000000000000000000000000..94b41c049bc3008214ae934fbf88815e67f93d07
mode 100644,000000..100644
--- /dev/null
@@@ -1,1658 -1,0 +1,1682 @@@
-             {
-                 "command": "rust-analyzer.toggleInlayHints",
-                 "title": "Toggle inlay hints",
-                 "category": "rust-analyzer"
-             },
 +{
 +    "name": "rust-analyzer",
 +    "displayName": "rust-analyzer",
 +    "description": "Rust language support for Visual Studio Code",
 +    "private": true,
 +    "icon": "icon.png",
 +    "version": "0.5.0-dev",
 +    "releaseTag": null,
 +    "publisher": "rust-lang",
 +    "repository": {
 +        "url": "https://github.com/rust-lang/rust-analyzer.git",
 +        "type": "git"
 +    },
 +    "homepage": "https://rust-analyzer.github.io/",
 +    "license": "MIT OR Apache-2.0",
 +    "keywords": [
 +        "rust"
 +    ],
 +    "categories": [
 +        "Programming Languages"
 +    ],
 +    "engines": {
 +        "vscode": "^1.66.0"
 +    },
 +    "enabledApiProposals": [],
 +    "scripts": {
 +        "vscode:prepublish": "npm run build-base -- --minify",
 +        "package": "vsce package -o rust-analyzer.vsix",
 +        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
 +        "build": "npm run build-base -- --sourcemap",
 +        "watch": "npm run build-base -- --sourcemap --watch",
 +        "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
 +        "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
 +        "pretest": "tsc && npm run build",
 +        "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js"
 +    },
 +    "dependencies": {
 +        "d3": "^7.6.1",
 +        "d3-graphviz": "^4.1.1",
 +        "vscode-languageclient": "^8.0.0-next.14"
 +    },
 +    "devDependencies": {
 +        "@types/node": "~16.11.7",
 +        "@types/vscode": "~1.66.0",
 +        "@typescript-eslint/eslint-plugin": "^5.30.5",
 +        "@typescript-eslint/parser": "^5.30.5",
 +        "@vscode/test-electron": "^2.1.5",
 +        "cross-env": "^7.0.3",
 +        "esbuild": "^0.14.48",
 +        "eslint": "^8.19.0",
 +        "eslint-config-prettier": "^8.5.0",
 +        "ovsx": "^0.5.1",
 +        "prettier": "^2.7.1",
 +        "tslib": "^2.4.0",
 +        "typescript": "^4.7.4",
 +        "vsce": "^2.9.2"
 +    },
 +    "activationEvents": [
 +        "onLanguage:rust",
 +        "onCommand:rust-analyzer.analyzerStatus",
 +        "onCommand:rust-analyzer.memoryUsage",
 +        "onCommand:rust-analyzer.reloadWorkspace",
 +        "workspaceContains:*/Cargo.toml",
 +        "workspaceContains:*/rust-project.json"
 +    ],
 +    "main": "./out/main",
 +    "contributes": {
 +        "taskDefinitions": [
 +            {
 +                "type": "cargo",
 +                "required": [
 +                    "command"
 +                ],
 +                "properties": {
 +                    "label": {
 +                        "type": "string"
 +                    },
 +                    "command": {
 +                        "type": "string"
 +                    },
 +                    "args": {
 +                        "type": "array",
 +                        "items": {
 +                            "type": "string"
 +                        }
 +                    },
 +                    "env": {
 +                        "type": "object",
 +                        "patternProperties": {
 +                            ".+": {
 +                                "type": "string"
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        ],
 +        "commands": [
 +            {
 +                "command": "rust-analyzer.syntaxTree",
 +                "title": "Show Syntax Tree",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewHir",
 +                "title": "View Hir",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewFileText",
 +                "title": "View File Text (as seen by the server)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewItemTree",
 +                "title": "Debug ItemTree",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewCrateGraph",
 +                "title": "View Crate Graph",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewFullCrateGraph",
 +                "title": "View Crate Graph (Full)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.expandMacro",
 +                "title": "Expand macro recursively",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.matchingBrace",
 +                "title": "Find matching brace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.parentModule",
 +                "title": "Locate parent module",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.joinLines",
 +                "title": "Join lines",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.run",
 +                "title": "Run",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.copyRunCommandLine",
 +                "title": "Copy Run Command Line",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.debug",
 +                "title": "Debug",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.newDebugConfig",
 +                "title": "Generate launch configuration",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.analyzerStatus",
 +                "title": "Status",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.memoryUsage",
 +                "title": "Memory Usage (Clears Database)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.shuffleCrateGraph",
 +                "title": "Shuffle Crate Graph",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.reloadWorkspace",
 +                "title": "Reload workspace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.reload",
 +                "title": "Restart server",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.onEnter",
 +                "title": "Enhanced enter key",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.ssr",
 +                "title": "Structural Search Replace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.serverVersion",
 +                "title": "Show RA Version",
 +                "category": "rust-analyzer"
 +            },
-                 {
-                     "command": "rust-analyzer.toggleInlayHints",
-                     "when": "inRustProject"
-                 },
 +            {
 +                "command": "rust-analyzer.openDocs",
 +                "title": "Open docs under cursor",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.openCargoToml",
 +                "title": "Open Cargo.toml",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.peekTests",
 +                "title": "Peek related tests",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.moveItemUp",
 +                "title": "Move item up",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.moveItemDown",
 +                "title": "Move item down",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.cancelFlycheck",
 +                "title": "Cancel running flychecks",
 +                "category": "rust-analyzer"
 +            }
 +        ],
 +        "keybindings": [
 +            {
 +                "command": "rust-analyzer.parentModule",
 +                "key": "ctrl+shift+u",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            },
 +            {
 +                "command": "rust-analyzer.matchingBrace",
 +                "key": "ctrl+shift+m",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            },
 +            {
 +                "command": "rust-analyzer.joinLines",
 +                "key": "ctrl+shift+j",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            }
 +        ],
 +        "configuration": {
 +            "type": "object",
 +            "title": "rust-analyzer",
 +            "properties": {
 +                "rust-analyzer.cargoRunner": {
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ],
 +                    "default": null,
 +                    "description": "Custom cargo runner extension ID."
 +                },
 +                "rust-analyzer.runnableEnv": {
 +                    "anyOf": [
 +                        {
 +                            "type": "null"
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "object",
 +                                "properties": {
 +                                    "mask": {
 +                                        "type": "string",
 +                                        "description": "Runnable name mask"
 +                                    },
 +                                    "env": {
 +                                        "type": "object",
 +                                        "description": "Variables in form of { \"key\": \"value\"}"
 +                                    }
 +                                }
 +                            }
 +                        },
 +                        {
 +                            "type": "object",
 +                            "description": "Variables in form of { \"key\": \"value\"}"
 +                        }
 +                    ],
 +                    "default": null,
 +                    "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
 +                },
 +                "rust-analyzer.server.path": {
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ],
 +                    "scope": "machine-overridable",
 +                    "default": null,
 +                    "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)."
 +                },
 +                "rust-analyzer.server.extraEnv": {
 +                    "type": [
 +                        "null",
 +                        "object"
 +                    ],
 +                    "additionalProperties": {
 +                        "type": [
 +                            "string",
 +                            "number"
 +                        ]
 +                    },
 +                    "default": null,
 +                    "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
 +                },
 +                "rust-analyzer.trace.server": {
 +                    "type": "string",
 +                    "scope": "window",
 +                    "enum": [
 +                        "off",
 +                        "messages",
 +                        "verbose"
 +                    ],
 +                    "enumDescriptions": [
 +                        "No traces",
 +                        "Error only",
 +                        "Full log"
 +                    ],
 +                    "default": "off",
 +                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
 +                },
 +                "rust-analyzer.trace.extension": {
 +                    "description": "Enable logging of VS Code extensions itself.",
 +                    "type": "boolean",
 +                    "default": false
 +                },
 +                "rust-analyzer.debug.engine": {
 +                    "type": "string",
 +                    "enum": [
 +                        "auto",
 +                        "vadimcn.vscode-lldb",
 +                        "ms-vscode.cpptools"
 +                    ],
 +                    "default": "auto",
 +                    "description": "Preferred debug engine.",
 +                    "markdownEnumDescriptions": [
 +                        "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
 +                        "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
 +                        "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
 +                    ]
 +                },
 +                "rust-analyzer.debug.sourceFileMap": {
 +                    "type": [
 +                        "object",
 +                        "string"
 +                    ],
 +                    "const": "auto",
 +                    "description": "Optional source file mappings passed to the debug engine.",
 +                    "default": {
 +                        "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
 +                    }
 +                },
 +                "rust-analyzer.debug.openDebugPane": {
 +                    "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
 +                    "type": "boolean",
 +                    "default": false
 +                },
 +                "rust-analyzer.debug.engineSettings": {
 +                    "type": "object",
 +                    "default": {},
 +                    "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
 +                },
 +                "rust-analyzer.restartServerOnConfigChange": {
 +                    "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.typing.continueCommentsOnNewline": {
 +                    "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "$generated-start": {},
 +                "rust-analyzer.assist.expressionFillDefault": {
 +                    "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
 +                    "default": "todo",
 +                    "type": "string",
 +                    "enum": [
 +                        "todo",
 +                        "default"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Fill missing expressions with the `todo` macro",
 +                        "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
 +                    ]
 +                },
 +                "rust-analyzer.cachePriming.enable": {
 +                    "markdownDescription": "Warm up caches on project load.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cachePriming.numThreads": {
 +                    "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
 +                    "default": 0,
 +                    "type": "number",
 +                    "minimum": 0,
 +                    "maximum": 255
 +                },
 +                "rust-analyzer.cargo.autoreload": {
 +                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.buildScripts.enable": {
 +                    "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.buildScripts.overrideCommand": {
 +                    "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
 +                    "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
++                "rust-analyzer.cargo.extraEnv": {
++                    "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.",
++                    "default": {},
++                    "type": "object"
++                },
 +                "rust-analyzer.cargo.features": {
 +                    "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
 +                    "default": [],
 +                    "anyOf": [
 +                        {
 +                            "type": "string",
 +                            "enum": [
 +                                "all"
 +                            ],
 +                            "enumDescriptions": [
 +                                "Pass `--all-features` to cargo"
 +                            ]
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "string"
 +                            }
 +                        }
 +                    ]
 +                },
 +                "rust-analyzer.cargo.noDefaultFeatures": {
 +                    "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.noSysroot": {
 +                    "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.target": {
 +                    "markdownDescription": "Compilation target override (target triple).",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.cargo.unsetTest": {
 +                    "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
 +                    "default": [
 +                        "core"
 +                    ],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.checkOnSave.allTargets": {
 +                    "markdownDescription": "Check all targets and tests (`--all-targets`).",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.checkOnSave.command": {
 +                    "markdownDescription": "Cargo command to use for `cargo check`.",
 +                    "default": "check",
 +                    "type": "string"
 +                },
 +                "rust-analyzer.checkOnSave.enable": {
 +                    "markdownDescription": "Run specified `cargo check` command for diagnostics on save.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.checkOnSave.extraArgs": {
 +                    "markdownDescription": "Extra arguments for `cargo check`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
++                "rust-analyzer.checkOnSave.extraEnv": {
++                    "markdownDescription": "Extra environment variables that will be set when running `cargo check`.",
++                    "default": {},
++                    "type": "object"
++                },
 +                "rust-analyzer.checkOnSave.features": {
 +                    "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
 +                    "default": null,
 +                    "anyOf": [
 +                        {
 +                            "type": "string",
 +                            "enum": [
 +                                "all"
 +                            ],
 +                            "enumDescriptions": [
 +                                "Pass `--all-features` to cargo"
 +                            ]
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "string"
 +                            }
 +                        },
 +                        {
 +                            "type": "null"
 +                        }
 +                    ]
 +                },
 +                "rust-analyzer.checkOnSave.noDefaultFeatures": {
 +                    "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "boolean"
 +                    ]
 +                },
 +                "rust-analyzer.checkOnSave.overrideCommand": {
 +                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.checkOnSave.target": {
 +                    "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.completion.autoimport.enable": {
 +                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.autoself.enable": {
 +                    "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.callable.snippets": {
 +                    "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.",
 +                    "default": "fill_arguments",
 +                    "type": "string",
 +                    "enum": [
 +                        "fill_arguments",
 +                        "add_parentheses",
 +                        "none"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Add call parentheses and pre-fill arguments.",
 +                        "Add call parentheses.",
 +                        "Do no snippet completions for callables."
 +                    ]
 +                },
 +                "rust-analyzer.completion.postfix.enable": {
 +                    "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.privateEditable.enable": {
 +                    "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.snippets.custom": {
 +                    "markdownDescription": "Custom completion snippets.",
 +                    "default": {
 +                        "Arc::new": {
 +                            "postfix": "arc",
 +                            "body": "Arc::new(${receiver})",
 +                            "requires": "std::sync::Arc",
 +                            "description": "Put the expression into an `Arc`",
 +                            "scope": "expr"
 +                        },
 +                        "Rc::new": {
 +                            "postfix": "rc",
 +                            "body": "Rc::new(${receiver})",
 +                            "requires": "std::rc::Rc",
 +                            "description": "Put the expression into an `Rc`",
 +                            "scope": "expr"
 +                        },
 +                        "Box::pin": {
 +                            "postfix": "pinbox",
 +                            "body": "Box::pin(${receiver})",
 +                            "requires": "std::boxed::Box",
 +                            "description": "Put the expression into a pinned `Box`",
 +                            "scope": "expr"
 +                        },
 +                        "Ok": {
 +                            "postfix": "ok",
 +                            "body": "Ok(${receiver})",
 +                            "description": "Wrap the expression in a `Result::Ok`",
 +                            "scope": "expr"
 +                        },
 +                        "Err": {
 +                            "postfix": "err",
 +                            "body": "Err(${receiver})",
 +                            "description": "Wrap the expression in a `Result::Err`",
 +                            "scope": "expr"
 +                        },
 +                        "Some": {
 +                            "postfix": "some",
 +                            "body": "Some(${receiver})",
 +                            "description": "Wrap the expression in an `Option::Some`",
 +                            "scope": "expr"
 +                        }
 +                    },
 +                    "type": "object"
 +                },
 +                "rust-analyzer.diagnostics.disabled": {
 +                    "markdownDescription": "List of rust-analyzer diagnostics to disable.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    },
 +                    "uniqueItems": true
 +                },
 +                "rust-analyzer.diagnostics.enable": {
 +                    "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.diagnostics.experimental.enable": {
 +                    "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.diagnostics.remapPrefix": {
 +                    "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.diagnostics.warningsAsHint": {
 +                    "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.diagnostics.warningsAsInfo": {
 +                    "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.files.excludeDirs": {
 +                    "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.files.watcher": {
 +                    "markdownDescription": "Controls file watching implementation.",
 +                    "default": "client",
 +                    "type": "string",
 +                    "enum": [
 +                        "client",
 +                        "server"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Use the client (editor) to watch files for changes",
 +                        "Use server-side file watching"
 +                    ]
 +                },
 +                "rust-analyzer.highlightRelated.breakPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.exitPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.references.enable": {
 +                    "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.yieldPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.debug.enable": {
 +                    "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.enable": {
 +                    "markdownDescription": "Whether to show HoverActions in Rust files.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.gotoTypeDef.enable": {
 +                    "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.implementations.enable": {
 +                    "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.references.enable": {
 +                    "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.run.enable": {
 +                    "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.documentation.enable": {
 +                    "markdownDescription": "Whether to show documentation on hover.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.documentation.keywords.enable": {
 +                    "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.links.enable": {
 +                    "markdownDescription": "Use markdown syntax for links in hover.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.granularity.enforce": {
 +                    "markdownDescription": "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.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.granularity.group": {
 +                    "markdownDescription": "How imports should be grouped into use statements.",
 +                    "default": "crate",
 +                    "type": "string",
 +                    "enum": [
 +                        "preserve",
 +                        "crate",
 +                        "module",
 +                        "item"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Do not change the granularity of any imports and preserve the original structure written by the developer.",
 +                        "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
 +                        "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
 +                        "Flatten imports so that each has its own use statement."
 +                    ]
 +                },
 +                "rust-analyzer.imports.group.enable": {
 +                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.merge.glob": {
 +                    "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
++                "rust-analyzer.imports.prefer.no.std": {
++                    "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.",
++                    "default": false,
++                    "type": "boolean"
++                },
 +                "rust-analyzer.imports.prefix": {
 +                    "markdownDescription": "The path structure for newly inserted paths to use.",
 +                    "default": "plain",
 +                    "type": "string",
 +                    "enum": [
 +                        "plain",
 +                        "self",
 +                        "crate"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
 +                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
 +                        "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.bindingModeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for binding modes.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.chainingHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for method chains.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.closingBraceHints.enable": {
 +                    "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.closingBraceHints.minLines": {
 +                    "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
 +                    "default": 25,
 +                    "type": "integer",
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for return types of closures.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "with_block"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show type hints for return types of closures.",
 +                        "Never show type hints for return types of closures.",
 +                        "Only show type hints for return types of closures with blocks."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "skip_trivial"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show lifetime elision hints.",
 +                        "Never show lifetime elision hints.",
 +                        "Only show lifetime elision hints if a return type is involved."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": {
 +                    "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.maxLength": {
 +                    "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
 +                    "default": 25,
 +                    "type": [
 +                        "null",
 +                        "integer"
 +                    ],
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.inlayHints.parameterHints.enable": {
 +                    "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.reborrowHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "mutable"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show reborrow hints.",
 +                        "Never show reborrow hints.",
 +                        "Only show mutable reborrow hints."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.renderColons": {
 +                    "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for variables.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
 +                    "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
 +                    "markdownDescription": "Whether to hide inlay type hints for constructors.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.joinAssignments": {
 +                    "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.joinElseIf": {
 +                    "markdownDescription": "Join lines inserts else between consecutive ifs.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.removeTrailingComma": {
 +                    "markdownDescription": "Join lines removes trailing commas.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.unwrapTrivialBlock": {
 +                    "markdownDescription": "Join lines unwraps trivial blocks.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.debug.enable": {
 +                    "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.enable": {
 +                    "markdownDescription": "Whether to show CodeLens in Rust files.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.forceCustomCommands": {
 +                    "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.implementations.enable": {
 +                    "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
++                "rust-analyzer.lens.location": {
++                    "markdownDescription": "Where to render annotations.",
++                    "default": "above_name",
++                    "type": "string",
++                    "enum": [
++                        "above_name",
++                        "above_whole_item"
++                    ],
++                    "enumDescriptions": [
++                        "Render annotations above the name of the item.",
++                        "Render annotations above the whole item, including documentation comments and attributes."
++                    ]
++                },
 +                "rust-analyzer.lens.references.adt.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.enumVariant.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.method.enable": {
 +                    "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.trait.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.run.enable": {
 +                    "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.linkedProjects": {
 +                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": [
 +                            "string",
 +                            "object"
 +                        ]
 +                    }
 +                },
 +                "rust-analyzer.lru.capacity": {
 +                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "integer"
 +                    ],
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.notifications.cargoTomlNotFound": {
 +                    "markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.attributes.enable": {
 +                    "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.enable": {
 +                    "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.ignored": {
 +                    "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.procMacro.server": {
 +                    "markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
++                "rust-analyzer.references.excludeImports": {
++                    "markdownDescription": "Exclude imports from find-all-references.",
++                    "default": false,
++                    "type": "boolean"
++                },
 +                "rust-analyzer.runnables.command": {
 +                    "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.runnables.extraArgs": {
 +                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustc.source": {
 +                    "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.rustfmt.extraArgs": {
 +                    "markdownDescription": "Additional arguments to `rustfmt`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustfmt.overrideCommand": {
 +                    "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustfmt.rangeFormatting.enable": {
 +                    "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": {
 +                    "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.operator.enable": {
 +                    "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.operator.specialization.enable": {
 +                    "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.enable": {
 +                    "markdownDescription": "Use semantic tokens for punctuations.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": {
 +                    "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": {
 +                    "markdownDescription": "Use specialized semantic tokens for punctuations.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.strings.enable": {
 +                    "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.signatureInfo.detail": {
 +                    "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.",
 +                    "default": "full",
 +                    "type": "string",
 +                    "enum": [
 +                        "full",
 +                        "parameters"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Show the entire signature.",
 +                        "Show only the parameters."
 +                    ]
 +                },
 +                "rust-analyzer.signatureInfo.documentation.enable": {
 +                    "markdownDescription": "Show documentation.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.typing.autoClosingAngleBrackets.enable": {
 +                    "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.workspace.symbol.search.kind": {
 +                    "markdownDescription": "Workspace symbol search kind.",
 +                    "default": "only_types",
 +                    "type": "string",
 +                    "enum": [
 +                        "only_types",
 +                        "all_symbols"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Search for types only.",
 +                        "Search for all symbols kinds."
 +                    ]
 +                },
 +                "rust-analyzer.workspace.symbol.search.limit": {
 +                    "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.",
 +                    "default": 128,
 +                    "type": "integer",
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.workspace.symbol.search.scope": {
 +                    "markdownDescription": "Workspace symbol search scope.",
 +                    "default": "workspace",
 +                    "type": "string",
 +                    "enum": [
 +                        "workspace",
 +                        "workspace_and_dependencies"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Search in current workspace only.",
 +                        "Search in current workspace and dependencies."
 +                    ]
 +                },
 +                "$generated-end": {}
 +            }
 +        },
 +        "problemPatterns": [
 +            {
 +                "name": "rustc",
 +                "patterns": [
 +                    {
 +                        "regexp": "^(warning|warn|error)(?:\\[(.*?)\\])?: (.*)$",
 +                        "severity": 1,
 +                        "code": 2,
 +                        "message": 3
 +                    },
 +                    {
 +                        "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$",
 +                        "file": 1,
 +                        "line": 2,
 +                        "column": 3
 +                    }
 +                ]
 +            },
 +            {
 +                "name": "rustc-json",
 +                "patterns": [
 +                    {
 +                        "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$",
 +                        "message": 1,
 +                        "file": 2,
 +                        "line": 3,
 +                        "endLine": 4,
 +                        "column": 5,
 +                        "endColumn": 6
 +                    }
 +                ]
 +            }
 +        ],
 +        "languages": [
 +            {
 +                "id": "ra_syntax_tree",
 +                "extensions": [
 +                    ".rast"
 +                ]
 +            },
 +            {
 +                "id": "rust",
 +                "extensions": [
 +                    ".rs"
 +                ],
 +                "aliases": [
 +                    "Rust",
 +                    "rs"
 +                ],
 +                "configuration": "language-configuration.json"
 +            }
 +        ],
 +        "grammars": [
 +            {
 +                "language": "ra_syntax_tree",
 +                "scopeName": "source.ra_syntax_tree",
 +                "path": "ra_syntax_tree.tmGrammar.json"
 +            }
 +        ],
 +        "problemMatchers": [
 +            {
 +                "name": "rustc",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "pattern": "$rustc"
 +            },
 +            {
 +                "name": "rustc-json",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "pattern": "$rustc-json"
 +            },
 +            {
 +                "name": "rustc-watch",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "background": {
 +                    "beginsPattern": "^\\[Running\\b",
 +                    "endsPattern": "^\\[Finished running\\b"
 +                },
 +                "pattern": "$rustc"
 +            }
 +        ],
 +        "colors": [
 +            {
 +                "id": "rust_analyzer.syntaxTreeBorder",
 +                "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
 +                "defaults": {
 +                    "dark": "#ffffff",
 +                    "light": "#b700ff",
 +                    "highContrast": "#b700ff"
 +                }
 +            }
 +        ],
 +        "semanticTokenTypes": [
 +            {
 +                "id": "angle",
 +                "description": "Style for < or >",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "arithmetic",
 +                "description": "Style for arithmetic operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "attribute",
 +                "description": "Style for attributes"
 +            },
 +            {
 +                "id": "attributeBracket",
 +                "description": "Style for attribute invocation brackets, that is the `#[` and `]` tokens",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "bitwise",
 +                "description": "Style for bitwise operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "boolean",
 +                "description": "Style for boolean literals",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "brace",
 +                "description": "Style for { or }",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "bracket",
 +                "description": "Style for [ or ]",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "builtinAttribute",
 +                "description": "Style for builtin attributes",
 +                "superType": "attribute"
 +            },
 +            {
 +                "id": "builtinType",
 +                "description": "Style for builtin types",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "character",
 +                "description": "Style for character literals",
 +                "superType": "string"
 +            },
 +            {
 +                "id": "colon",
 +                "description": "Style for :",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "comma",
 +                "description": "Style for ,",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "comparison",
 +                "description": "Style for comparison operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "constParameter",
 +                "description": "Style for const generics"
 +            },
 +            {
 +                "id": "derive",
 +                "description": "Style for derives",
 +                "superType": "attribute"
 +            },
 +            {
 +                "id": "dot",
 +                "description": "Style for .",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "escapeSequence",
 +                "description": "Style for char escapes in strings"
 +            },
 +            {
 +                "id": "formatSpecifier",
 +                "description": "Style for {} placeholders in format strings"
 +            },
 +            {
 +                "id": "label",
 +                "description": "Style for labels"
 +            },
 +            {
 +                "id": "lifetime",
 +                "description": "Style for lifetimes"
 +            },
 +            {
 +                "id": "logical",
 +                "description": "Style for logic operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "macroBang",
 +                "description": "Style for the ! token of macro calls",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "operator",
 +                "description": "Style for operators",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "parenthesis",
 +                "description": "Style for ( or )",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "punctuation",
 +                "description": "Style for generic punctuation"
 +            },
 +            {
 +                "id": "selfKeyword",
 +                "description": "Style for the self keyword",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "selfTypeKeyword",
 +                "description": "Style for the self type keyword",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "semicolon",
 +                "description": "Style for ;",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "typeAlias",
 +                "description": "Style for type aliases",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "union",
 +                "description": "Style for C-style untagged unions",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "unresolvedReference",
 +                "description": "Style for names which can not be resolved due to compilation errors"
 +            }
 +        ],
 +        "semanticTokenModifiers": [
 +            {
 +                "id": "async",
 +                "description": "Style for async functions and the `async` and `await` keywords"
 +            },
 +            {
 +                "id": "attribute",
 +                "description": "Style for elements within attributes"
 +            },
 +            {
 +                "id": "callable",
 +                "description": "Style for locals whose types implements one of the `Fn*` traits"
 +            },
 +            {
 +                "id": "constant",
 +                "description": "Style for compile-time constants"
 +            },
 +            {
 +                "id": "consuming",
 +                "description": "Style for locals that are being consumed when use in a function call"
 +            },
 +            {
 +                "id": "controlFlow",
 +                "description": "Style for control-flow related tokens, this includes the `?` operator"
 +            },
 +            {
 +                "id": "crateRoot",
 +                "description": "Style for names resolving to a crate root"
 +            },
 +            {
 +                "id": "injected",
 +                "description": "Style for doc-string injected highlighting like rust source blocks in documentation"
 +            },
 +            {
 +                "id": "intraDocLink",
 +                "description": "Style for intra doc links in doc-strings"
 +            },
 +            {
 +                "id": "library",
 +                "description": "Style for items that are defined outside of the current crate"
 +            },
 +            {
 +                "id": "mutable",
 +                "description": "Style for mutable locals and statics as well as functions taking `&mut self`"
 +            },
 +            {
 +                "id": "public",
 +                "description": "Style for items that are from the current crate and are `pub`"
 +            },
 +            {
 +                "id": "reference",
 +                "description": "Style for locals behind a reference and functions taking `self` by reference"
 +            },
 +            {
 +                "id": "trait",
 +                "description": "Style for associated trait items"
 +            },
 +            {
 +                "id": "unsafe",
 +                "description": "Style for unsafe operations, like unsafe function calls, as well as the `unsafe` token"
 +            }
 +        ],
 +        "semanticTokenScopes": [
 +            {
 +                "language": "rust",
 +                "scopes": {
 +                    "attribute": [
 +                        "meta.attribute.rust"
 +                    ],
 +                    "boolean": [
 +                        "constant.language.boolean.rust"
 +                    ],
 +                    "builtinType": [
 +                        "support.type.primitive.rust"
 +                    ],
 +                    "constParameter": [
 +                        "constant.other.caps.rust"
 +                    ],
 +                    "enum": [
 +                        "entity.name.type.enum.rust"
 +                    ],
 +                    "formatSpecifier": [
 +                        "punctuation.section.embedded.rust"
 +                    ],
 +                    "function": [
 +                        "entity.name.function.rust"
 +                    ],
 +                    "interface": [
 +                        "entity.name.type.trait.rust"
 +                    ],
 +                    "keyword": [
 +                        "keyword.other.rust"
 +                    ],
 +                    "keyword.controlFlow": [
 +                        "keyword.control.rust"
 +                    ],
 +                    "lifetime": [
 +                        "storage.modifier.lifetime.rust"
 +                    ],
 +                    "macroBang": [
 +                        "entity.name.function.macro.rust"
 +                    ],
 +                    "method": [
 +                        "entity.name.function.rust"
 +                    ],
 +                    "struct": [
 +                        "entity.name.type.struct.rust"
 +                    ],
 +                    "typeAlias": [
 +                        "entity.name.type.declaration.rust"
 +                    ],
 +                    "union": [
 +                        "entity.name.type.union.rust"
 +                    ],
 +                    "variable": [
 +                        "variable.other.rust"
 +                    ],
 +                    "variable.constant": [
 +                        "variable.other.constant.rust"
 +                    ],
 +                    "*.mutable": [
 +                        "markup.underline"
 +                    ]
 +                }
 +            }
 +        ],
 +        "menus": {
 +            "commandPalette": [
 +                {
 +                    "command": "rust-analyzer.syntaxTree",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.viewHir",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.viewFileText",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.expandMacro",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.matchingBrace",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.parentModule",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.joinLines",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.run",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.debug",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.newDebugConfig",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.analyzerStatus",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.memoryUsage",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.reloadWorkspace",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.reload",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.onEnter",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.ssr",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.serverVersion",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.openDocs",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.openCargoToml",
 +                    "when": "inRustProject"
 +                }
 +            ],
 +            "editor/context": [
 +                {
 +                    "command": "rust-analyzer.peekTests",
 +                    "when": "inRustProject",
 +                    "group": "navigation@1000"
 +                }
 +            ]
 +        }
 +    }
 +}
index a21b304bbdaa0d92242924779cdc99ee995b4e27,0000000000000000000000000000000000000000..b9ad525e361f0e20e5807ac9d2b24ab306d4f716
mode 100644,000000..100644
--- /dev/null
@@@ -1,972 -1,0 +1,948 @@@
- export function toggleInlayHints(_ctx: Ctx): Cmd {
-     return async () => {
-         const config = vscode.workspace.getConfiguration("editor.inlayHints", {
-             languageId: "rust",
-         });
-         const value = config.get("enabled");
-         let stringValue;
-         if (typeof value === "string") {
-             stringValue = value;
-         } else {
-             stringValue = value ? "on" : "off";
-         }
-         const nextValues: Record<string, string> = {
-             on: "off",
-             off: "on",
-             onUnlessPressed: "offUnlessPressed",
-             offUnlessPressed: "onUnlessPressed",
-         };
-         const nextValue = nextValues[stringValue] ?? "on";
-         await config.update("enabled", nextValue, vscode.ConfigurationTarget.Global);
-     };
- }
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient";
 +import * as ra from "./lsp_ext";
 +import * as path from "path";
 +
 +import { Ctx, Cmd } from "./ctx";
 +import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
 +import { spawnSync } from "child_process";
 +import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
 +import { AstInspector } from "./ast_inspector";
 +import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util";
 +import { startDebugSession, makeDebugConfig } from "./debug";
 +import { LanguageClient } from "vscode-languageclient/node";
 +import { LINKED_COMMANDS } from "./client";
 +
 +export * from "./ast_inspector";
 +export * from "./run";
 +
 +export function analyzerStatus(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +
 +        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
 +            if (!vscode.window.activeTextEditor) return "";
 +
 +            const params: ra.AnalyzerStatusParams = {};
 +            const doc = ctx.activeRustEditor?.document;
 +            if (doc != null) {
 +                params.textDocument =
 +                    ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
 +            }
 +            return ctx.client.sendRequest(ra.analyzerStatus, params);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function memoryUsage(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +
 +        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
 +            if (!vscode.window.activeTextEditor) return "";
 +
 +            return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
 +                return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
 +            });
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp)
 +    );
 +
 +    return async () => {
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
 +    };
 +}
 +
 +export function shuffleCrateGraph(ctx: Ctx): Cmd {
 +    return async () => {
 +        const client = ctx.client;
 +        if (!client) return;
 +
 +        await client.sendRequest(ra.shuffleCrateGraph);
 +    };
 +}
 +
 +export function matchingBrace(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const response = await client.sendRequest(ra.matchingBrace, {
 +            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                editor.document
 +            ),
 +            positions: editor.selections.map((s) =>
 +                client.code2ProtocolConverter.asPosition(s.active)
 +            ),
 +        });
 +        editor.selections = editor.selections.map((sel, idx) => {
 +            const active = client.protocol2CodeConverter.asPosition(response[idx]);
 +            const anchor = sel.isEmpty ? active : sel.anchor;
 +            return new vscode.Selection(anchor, active);
 +        });
 +        editor.revealRange(editor.selection);
 +    };
 +}
 +
 +export function joinLines(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
 +            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
 +            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                editor.document
 +            ),
 +        });
 +        const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
 +        await editor.edit((builder) => {
 +            textEdits.forEach((edit: any) => {
 +                builder.replace(edit.range, edit.newText);
 +            });
 +        });
 +    };
 +}
 +
 +export function moveItemUp(ctx: Ctx): Cmd {
 +    return moveItem(ctx, ra.Direction.Up);
 +}
 +
 +export function moveItemDown(ctx: Ctx): Cmd {
 +    return moveItem(ctx, ra.Direction.Down);
 +}
 +
 +export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const lcEdits = await client.sendRequest(ra.moveItem, {
 +            range: client.code2ProtocolConverter.asRange(editor.selection),
 +            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                editor.document
 +            ),
 +            direction,
 +        });
 +
 +        if (!lcEdits) return;
 +
 +        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
 +        await applySnippetTextEdits(editor, edits);
 +    };
 +}
 +
 +export function onEnter(ctx: Ctx): Cmd {
 +    async function handleKeypress() {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +
 +        if (!editor || !client) return false;
 +
 +        const lcEdits = await client
 +            .sendRequest(ra.onEnter, {
 +                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    editor.document
 +                ),
 +                position: client.code2ProtocolConverter.asPosition(editor.selection.active),
 +            })
 +            .catch((_error: any) => {
 +                // client.handleFailedRequest(OnEnterRequest.type, error, null);
 +                return null;
 +            });
 +        if (!lcEdits) return false;
 +
 +        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
 +        await applySnippetTextEdits(editor, edits);
 +        return true;
 +    }
 +
 +    return async () => {
 +        if (await handleKeypress()) return;
 +
 +        await vscode.commands.executeCommand("default:type", { text: "\n" });
 +    };
 +}
 +
 +export function parentModule(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +        if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
 +
 +        const locations = await client.sendRequest(ra.parentModule, {
 +            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                editor.document
 +            ),
 +            position: client.code2ProtocolConverter.asPosition(editor.selection.active),
 +        });
 +        if (!locations) return;
 +
 +        if (locations.length === 1) {
 +            const loc = locations[0];
 +
 +            const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
 +            const range = client.protocol2CodeConverter.asRange(loc.targetRange);
 +
 +            const doc = await vscode.workspace.openTextDocument(uri);
 +            const e = await vscode.window.showTextDocument(doc);
 +            e.selection = new vscode.Selection(range.start, range.start);
 +            e.revealRange(range, vscode.TextEditorRevealType.InCenter);
 +        } else {
 +            const uri = editor.document.uri.toString();
 +            const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
 +            await showReferencesImpl(
 +                client,
 +                uri,
 +                position,
 +                locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange))
 +            );
 +        }
 +    };
 +}
 +
 +export function openCargoToml(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const response = await client.sendRequest(ra.openCargoToml, {
 +            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                editor.document
 +            ),
 +        });
 +        if (!response) return;
 +
 +        const uri = client.protocol2CodeConverter.asUri(response.uri);
 +        const range = client.protocol2CodeConverter.asRange(response.range);
 +
 +        const doc = await vscode.workspace.openTextDocument(uri);
 +        const e = await vscode.window.showTextDocument(doc);
 +        e.selection = new vscode.Selection(range.start, range.start);
 +        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
 +    };
 +}
 +
 +export function ssr(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const position = editor.selection.active;
 +        const selections = editor.selections;
 +        const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +            editor.document
 +        );
 +
 +        const options: vscode.InputBoxOptions = {
 +            value: "() ==>> ()",
 +            prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ",
 +            validateInput: async (x: string) => {
 +                try {
 +                    await client.sendRequest(ra.ssr, {
 +                        query: x,
 +                        parseOnly: true,
 +                        textDocument,
 +                        position,
 +                        selections,
 +                    });
 +                } catch (e) {
 +                    return e.toString();
 +                }
 +                return null;
 +            },
 +        };
 +        const request = await vscode.window.showInputBox(options);
 +        if (!request) return;
 +
 +        await vscode.window.withProgress(
 +            {
 +                location: vscode.ProgressLocation.Notification,
 +                title: "Structured search replace in progress...",
 +                cancellable: false,
 +            },
 +            async (_progress, token) => {
 +                const edit = await client.sendRequest(ra.ssr, {
 +                    query: request,
 +                    parseOnly: false,
 +                    textDocument,
 +                    position,
 +                    selections,
 +                });
 +
 +                await vscode.workspace.applyEdit(
 +                    await client.protocol2CodeConverter.asWorkspaceEdit(edit, token)
 +                );
 +            }
 +        );
 +    };
 +}
 +
 +export function serverVersion(ctx: Ctx): Cmd {
 +    return async () => {
 +        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
 +        const versionString = stdout.slice(`rust-analyzer `.length).trim();
 +
 +        void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
 +    };
 +}
 +
 +// Opens the virtual file that will show the syntax tree
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function syntaxTree(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            if (!rustEditor) return "";
 +
 +            // When the range based query is enabled we take the range of the selection
 +            const range =
 +                uri.query === "range=true" && !rustEditor.selection.isEmpty
 +                    ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
 +                    : null;
 +
 +            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
 +            return ctx.client.sendRequest(ra.syntaxTree, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    void new AstInspector(ctx);
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp)
 +    );
 +    ctx.pushCleanup(
 +        vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
 +            brackets: [["[", ")"]],
 +        })
 +    );
 +
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
 +        const rangeEnabled = !!editor && !editor.selection.isEmpty;
 +
 +        const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri;
 +
 +        const document = await vscode.workspace.openTextDocument(uri);
 +
 +        tdcp.eventEmitter.fire(uri);
 +
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +// Opens the virtual file that will show the HIR of the function containing the cursor position
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function viewHir(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            const params = {
 +                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    rustEditor.document
 +                ),
 +                position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active),
 +            };
 +            return client.sendRequest(ra.viewHir, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function viewFileText(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                rustEditor.document
 +            );
 +            return client.sendRequest(ra.viewFileText, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function viewItemTree(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            const params = {
 +                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    rustEditor.document
 +                ),
 +            };
 +            return client.sendRequest(ra.viewItemTree, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +function crateGraph(ctx: Ctx, full: boolean): Cmd {
 +    return async () => {
 +        const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules"));
 +
 +        const panel = vscode.window.createWebviewPanel(
 +            "rust-analyzer.crate-graph",
 +            "rust-analyzer crate graph",
 +            vscode.ViewColumn.Two,
 +            {
 +                enableScripts: true,
 +                retainContextWhenHidden: true,
 +                localResourceRoots: [nodeModulesPath],
 +            }
 +        );
 +        const params = {
 +            full: full,
 +        };
 +
 +        const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params);
 +        const uri = panel.webview.asWebviewUri(nodeModulesPath);
 +
 +        const html = `
 +            <!DOCTYPE html>
 +            <meta charset="utf-8">
 +            <head>
 +                <style>
 +                    /* Fill the entire view */
 +                    html, body { margin:0; padding:0; overflow:hidden }
 +                    svg { position:fixed; top:0; left:0; height:100%; width:100% }
 +
 +                    /* Disable the graphviz background and fill the polygons */
 +                    .graph > polygon { display:none; }
 +                    :is(.node,.edge) polygon { fill: white; }
 +
 +                    /* Invert the line colours for dark themes */
 +                    body:not(.vscode-light) .edge path { stroke: white; }
 +                </style>
 +            </head>
 +            <body>
 +                <script type="text/javascript" src="${uri}/d3/dist/d3.min.js"></script>
 +                <script type="text/javascript" src="${uri}/@hpcc-js/wasm/dist/index.min.js"></script>
 +                <script type="text/javascript" src="${uri}/d3-graphviz/build/d3-graphviz.min.js"></script>
 +                <div id="graph"></div>
 +                <script>
 +                    let graph = d3.select("#graph")
 +                                  .graphviz()
 +                                  .fit(true)
 +                                  .zoomScaleExtent([0.1, Infinity])
 +                                  .renderDot(\`${dot}\`);
 +
 +                    d3.select(window).on("click", (event) => {
 +                        if (event.ctrlKey) {
 +                            graph.resetZoom(d3.transition().duration(100));
 +                        }
 +                    });
 +                </script>
 +            </body>
 +            `;
 +
 +        panel.webview.html = html;
 +    };
 +}
 +
 +export function viewCrateGraph(ctx: Ctx): Cmd {
 +    return crateGraph(ctx, false);
 +}
 +
 +export function viewFullCrateGraph(ctx: Ctx): Cmd {
 +    return crateGraph(ctx, true);
 +}
 +
 +// Opens the virtual file that will show the syntax tree
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function expandMacro(ctx: Ctx): Cmd {
 +    function codeFormat(expanded: ra.ExpandedMacro): string {
 +        let result = `// Recursive expansion of ${expanded.name}! macro\n`;
 +        result += "// " + "=".repeat(result.length - 3);
 +        result += "\n\n";
 +        result += expanded.expansion;
 +
 +        return result;
 +    }
 +
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        uri = vscode.Uri.parse("rust-analyzer-expand-macro://expandMacro/[EXPANSION].rs");
 +        eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
 +            const editor = vscode.window.activeTextEditor;
 +            const client = ctx.client;
 +            if (!editor || !client) return "";
 +
 +            const position = editor.selection.active;
 +
 +            const expanded = await client.sendRequest(ra.expandMacro, {
 +                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    editor.document
 +                ),
 +                position,
 +            });
 +
 +            if (expanded == null) return "Not available";
 +
 +            return codeFormat(expanded);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
 +    };
 +}
 +
 +export function reloadWorkspace(ctx: Ctx): Cmd {
 +    return async () => ctx.client.sendRequest(ra.reloadWorkspace);
 +}
 +
 +async function showReferencesImpl(
 +    client: LanguageClient,
 +    uri: string,
 +    position: lc.Position,
 +    locations: lc.Location[]
 +) {
 +    if (client) {
 +        await vscode.commands.executeCommand(
 +            "editor.action.showReferences",
 +            vscode.Uri.parse(uri),
 +            client.protocol2CodeConverter.asPosition(position),
 +            locations.map(client.protocol2CodeConverter.asLocation)
 +        );
 +    }
 +}
 +
 +export function showReferences(ctx: Ctx): Cmd {
 +    return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
 +        await showReferencesImpl(ctx.client, uri, position, locations);
 +    };
 +}
 +
 +export function applyActionGroup(_ctx: Ctx): Cmd {
 +    return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
 +        const selectedAction = await vscode.window.showQuickPick(actions);
 +        if (!selectedAction) return;
 +        await vscode.commands.executeCommand(
 +            "rust-analyzer.resolveCodeAction",
 +            selectedAction.arguments
 +        );
 +    };
 +}
 +
 +export function gotoLocation(ctx: Ctx): Cmd {
 +    return async (locationLink: lc.LocationLink) => {
 +        const client = ctx.client;
 +        if (client) {
 +            const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
 +            let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
 +            // collapse the range to a cursor position
 +            range = range.with({ end: range.start });
 +
 +            await vscode.window.showTextDocument(uri, { selection: range });
 +        }
 +    };
 +}
 +
 +export function openDocs(ctx: Ctx): Cmd {
 +    return async () => {
 +        const client = ctx.client;
 +        const editor = vscode.window.activeTextEditor;
 +        if (!editor || !client) {
 +            return;
 +        }
 +
 +        const position = editor.selection.active;
 +        const textDocument = { uri: editor.document.uri.toString() };
 +
 +        const doclink = await client.sendRequest(ra.openDocs, { position, textDocument });
 +
 +        if (doclink != null) {
 +            await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink));
 +        }
 +    };
 +}
 +
 +export function cancelFlycheck(ctx: Ctx): Cmd {
 +    return async () => {
 +        await ctx.client.sendRequest(ra.cancelFlycheck);
 +    };
 +}
 +
 +export function resolveCodeAction(ctx: Ctx): Cmd {
 +    const client = ctx.client;
 +    return async (params: lc.CodeAction) => {
 +        params.command = undefined;
 +        const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
 +        if (!item.edit) {
 +            return;
 +        }
 +        const itemEdit = item.edit;
 +        const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
 +        // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
 +        // snippet edits on our own
 +        const lcFileSystemEdit = {
 +            ...itemEdit,
 +            documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change),
 +        };
 +        const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(
 +            lcFileSystemEdit
 +        );
 +        await vscode.workspace.applyEdit(fileSystemEdit);
 +        await applySnippetWorkspaceEdit(edit);
 +        if (item.command != null) {
 +            await vscode.commands.executeCommand(item.command.command, item.command.arguments);
 +        }
 +    };
 +}
 +
 +export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
 +    return async (edit: vscode.WorkspaceEdit) => {
 +        await applySnippetWorkspaceEdit(edit);
 +    };
 +}
 +
 +export function run(ctx: Ctx): Cmd {
 +    let prevRunnable: RunnableQuickPick | undefined;
 +
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevRunnable);
 +        if (!item) return;
 +
 +        item.detail = "rerun";
 +        prevRunnable = item;
 +        const task = await createTask(item.runnable, ctx.config);
 +        return await vscode.tasks.executeTask(task);
 +    };
 +}
 +
 +export function peekTests(ctx: Ctx): Cmd {
 +    const client = ctx.client;
 +
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        if (!editor || !client) return;
 +
 +        await vscode.window.withProgress(
 +            {
 +                location: vscode.ProgressLocation.Notification,
 +                title: "Looking for tests...",
 +                cancellable: false,
 +            },
 +            async (_progress, _token) => {
 +                const uri = editor.document.uri.toString();
 +                const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
 +
 +                const tests = await client.sendRequest(ra.relatedTests, {
 +                    textDocument: { uri: uri },
 +                    position: position,
 +                });
 +                const locations: lc.Location[] = tests.map((it) =>
 +                    lc.Location.create(
 +                        it.runnable.location!.targetUri,
 +                        it.runnable.location!.targetSelectionRange
 +                    )
 +                );
 +
 +                await showReferencesImpl(client, uri, position, locations);
 +            }
 +        );
 +    };
 +}
 +
 +export function runSingle(ctx: Ctx): Cmd {
 +    return async (runnable: ra.Runnable) => {
 +        const editor = ctx.activeRustEditor;
 +        if (!editor) return;
 +
 +        const task = await createTask(runnable, ctx.config);
 +        task.group = vscode.TaskGroup.Build;
 +        task.presentationOptions = {
 +            reveal: vscode.TaskRevealKind.Always,
 +            panel: vscode.TaskPanelKind.Dedicated,
 +            clear: true,
 +        };
 +
 +        return vscode.tasks.executeTask(task);
 +    };
 +}
 +
 +export function copyRunCommandLine(ctx: Ctx) {
 +    let prevRunnable: RunnableQuickPick | undefined;
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevRunnable);
 +        if (!item) return;
 +        const args = createArgs(item.runnable);
 +        const commandLine = ["cargo", ...args].join(" ");
 +        await vscode.env.clipboard.writeText(commandLine);
 +        await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
 +    };
 +}
 +
 +export function debug(ctx: Ctx): Cmd {
 +    let prevDebuggee: RunnableQuickPick | undefined;
 +
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevDebuggee, true);
 +        if (!item) return;
 +
 +        item.detail = "restart";
 +        prevDebuggee = item;
 +        return await startDebugSession(ctx, item.runnable);
 +    };
 +}
 +
 +export function debugSingle(ctx: Ctx): Cmd {
 +    return async (config: ra.Runnable) => {
 +        await startDebugSession(ctx, config);
 +    };
 +}
 +
 +export function newDebugConfig(ctx: Ctx): Cmd {
 +    return async () => {
 +        const item = await selectRunnable(ctx, undefined, true, false);
 +        if (!item) return;
 +
 +        await makeDebugConfig(ctx, item.runnable);
 +    };
 +}
 +
 +export function linkToCommand(ctx: Ctx): Cmd {
 +    return async (commandId: string) => {
 +        const link = LINKED_COMMANDS.get(commandId);
 +        if (ctx.client && link) {
 +            const { command, arguments: args = [] } = link;
 +            await vscode.commands.executeCommand(command, ...args);
 +        }
 +    };
 +}
index e9b62e0cc2578b876747093577439bfec057192e,0000000000000000000000000000000000000000..41bde4195e07d254da0d5532101c140969c17dc2
mode 100644,000000..100644
--- /dev/null
@@@ -1,416 -1,0 +1,415 @@@
-     ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints);
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient/node";
 +import * as os from "os";
 +
 +import * as commands from "./commands";
 +import { Ctx } from "./ctx";
 +import { Config } from "./config";
 +import { log, isValidExecutable, isRustDocument } from "./util";
 +import { PersistentState } from "./persistent_state";
 +import { activateTaskProvider } from "./tasks";
 +import { setContextValue } from "./util";
 +import { exec } from "child_process";
 +
 +let ctx: Ctx | undefined;
 +
 +const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 +
 +let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
 +export function traceOutputChannel() {
 +    if (!TRACE_OUTPUT_CHANNEL) {
 +        TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel(
 +            "Rust Analyzer Language Server Trace"
 +        );
 +    }
 +    return TRACE_OUTPUT_CHANNEL;
 +}
 +let OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
 +export function outputChannel() {
 +    if (!OUTPUT_CHANNEL) {
 +        OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rust Analyzer Language Server");
 +    }
 +    return OUTPUT_CHANNEL;
 +}
 +
 +export interface RustAnalyzerExtensionApi {
 +    client?: lc.LanguageClient;
 +}
 +
 +export async function activate(
 +    context: vscode.ExtensionContext
 +): Promise<RustAnalyzerExtensionApi> {
 +    // VS Code doesn't show a notification when an extension fails to activate
 +    // so we do it ourselves.
 +    return await tryActivate(context).catch((err) => {
 +        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
 +        throw err;
 +    });
 +}
 +
 +async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
 +    // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 +    // only those are in use.
 +    // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
 +    const folders = (vscode.workspace.workspaceFolders || []).filter(
 +        (folder) => folder.uri.scheme === "file"
 +    );
 +    const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
 +        isRustDocument(document)
 +    );
 +
 +    if (folders.length === 0 && rustDocuments.length === 0) {
 +        // FIXME: Ideally we would choose not to activate at all (and avoid registering
 +        // non-functional editor commands), but VS Code doesn't seem to have a good way of doing
 +        // that
 +        return {};
 +    }
 +
 +    const config = new Config(context);
 +    const state = new PersistentState(context.globalState);
 +    const serverPath = await bootstrap(context, config, state).catch((err) => {
 +        let message = "bootstrap error. ";
 +
 +        message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
 +        message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
 +
 +        log.error("Bootstrap error", err);
 +        throw new Error(message);
 +    });
 +
 +    if (folders.length === 0) {
 +        ctx = await Ctx.create(config, context, serverPath, {
 +            kind: "Detached Files",
 +            files: rustDocuments,
 +        });
 +    } else {
 +        // Note: we try to start the server before we activate type hints so that it
 +        // registers its `onDidChangeDocument` handler before us.
 +        //
 +        // This a horribly, horribly wrong way to deal with this problem.
 +        ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" });
 +        ctx.pushCleanup(activateTaskProvider(ctx.config));
 +    }
 +    await initCommonContext(context, ctx);
 +
 +    warnAboutExtensionConflicts();
 +
 +    if (config.typingContinueCommentsOnNewline) {
 +        ctx.pushCleanup(configureLanguage());
 +    }
 +
 +    vscode.workspace.onDidChangeConfiguration(
 +        (_) =>
 +            ctx?.client
 +                ?.sendNotification("workspace/didChangeConfiguration", { settings: "" })
 +                .catch(log.error),
 +        null,
 +        ctx.subscriptions
 +    );
 +
 +    return {
 +        client: ctx.client,
 +    };
 +}
 +
 +async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
 +    // Register a "dumb" onEnter command for the case where server fails to
 +    // start.
 +    //
 +    // FIXME: refactor command registration code such that commands are
 +    // **always** registered, even if the server does not start. Use API like
 +    // this perhaps?
 +    //
 +    // ```TypeScript
 +    // registerCommand(
 +    //    factory: (Ctx) => ((Ctx) => any),
 +    //    fallback: () => any = () => vscode.window.showErrorMessage(
 +    //        "rust-analyzer is not available"
 +    //    ),
 +    // )
 +    const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () =>
 +        vscode.commands.executeCommand("default:type", { text: "\n" })
 +    );
 +    context.subscriptions.push(defaultOnEnter);
 +
 +    await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
 +
 +    // Commands which invokes manually via command palette, shortcut, etc.
 +
 +    // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895
 +    ctx.registerCommand("reload", (_) => async () => {
 +        void vscode.window.showInformationMessage("Reloading rust-analyzer...");
 +        await doDeactivate();
 +        while (context.subscriptions.length > 0) {
 +            try {
 +                context.subscriptions.pop()!.dispose();
 +            } catch (err) {
 +                log.error("Dispose error:", err);
 +            }
 +        }
 +        await activate(context).catch(log.error);
 +    });
 +
 +    ctx.registerCommand("analyzerStatus", commands.analyzerStatus);
 +    ctx.registerCommand("memoryUsage", commands.memoryUsage);
 +    ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph);
 +    ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace);
 +    ctx.registerCommand("matchingBrace", commands.matchingBrace);
 +    ctx.registerCommand("joinLines", commands.joinLines);
 +    ctx.registerCommand("parentModule", commands.parentModule);
 +    ctx.registerCommand("syntaxTree", commands.syntaxTree);
 +    ctx.registerCommand("viewHir", commands.viewHir);
 +    ctx.registerCommand("viewFileText", commands.viewFileText);
 +    ctx.registerCommand("viewItemTree", commands.viewItemTree);
 +    ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph);
 +    ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph);
 +    ctx.registerCommand("expandMacro", commands.expandMacro);
 +    ctx.registerCommand("run", commands.run);
 +    ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine);
 +    ctx.registerCommand("debug", commands.debug);
 +    ctx.registerCommand("newDebugConfig", commands.newDebugConfig);
 +    ctx.registerCommand("openDocs", commands.openDocs);
 +    ctx.registerCommand("openCargoToml", commands.openCargoToml);
 +    ctx.registerCommand("peekTests", commands.peekTests);
 +    ctx.registerCommand("moveItemUp", commands.moveItemUp);
 +    ctx.registerCommand("moveItemDown", commands.moveItemDown);
 +    ctx.registerCommand("cancelFlycheck", commands.cancelFlycheck);
 +
 +    defaultOnEnter.dispose();
 +    ctx.registerCommand("onEnter", commands.onEnter);
 +
 +    ctx.registerCommand("ssr", commands.ssr);
 +    ctx.registerCommand("serverVersion", commands.serverVersion);
 +
 +    // Internal commands which are invoked by the server.
 +    ctx.registerCommand("runSingle", commands.runSingle);
 +    ctx.registerCommand("debugSingle", commands.debugSingle);
 +    ctx.registerCommand("showReferences", commands.showReferences);
 +    ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand);
 +    ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction);
 +    ctx.registerCommand("applyActionGroup", commands.applyActionGroup);
 +    ctx.registerCommand("gotoLocation", commands.gotoLocation);
 +
 +    ctx.registerCommand("linkToCommand", commands.linkToCommand);
 +}
 +
 +export async function deactivate() {
 +    TRACE_OUTPUT_CHANNEL?.dispose();
 +    TRACE_OUTPUT_CHANNEL = null;
 +    OUTPUT_CHANNEL?.dispose();
 +    OUTPUT_CHANNEL = null;
 +    await doDeactivate();
 +}
 +
 +async function doDeactivate() {
 +    await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
 +    await ctx?.client.stop();
 +    ctx = undefined;
 +}
 +
 +async function bootstrap(
 +    context: vscode.ExtensionContext,
 +    config: Config,
 +    state: PersistentState
 +): Promise<string> {
 +    const path = await getServer(context, config, state);
 +    if (!path) {
 +        throw new Error(
 +            "Rust Analyzer Language Server is not available. " +
 +                "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
 +        );
 +    }
 +
 +    log.info("Using server binary at", path);
 +
 +    if (!isValidExecutable(path)) {
 +        if (config.serverPath) {
 +            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
 +            Consider removing this config or making a valid server binary available at that path.`);
 +        } else {
 +            throw new Error(`Failed to execute ${path} --version`);
 +        }
 +    }
 +
 +    return path;
 +}
 +
 +async function patchelf(dest: vscode.Uri): Promise<void> {
 +    await vscode.window.withProgress(
 +        {
 +            location: vscode.ProgressLocation.Notification,
 +            title: "Patching rust-analyzer for NixOS",
 +        },
 +        async (progress, _) => {
 +            const expression = `
 +            {srcStr, pkgs ? import <nixpkgs> {}}:
 +                pkgs.stdenv.mkDerivation {
 +                    name = "rust-analyzer";
 +                    src = /. + srcStr;
 +                    phases = [ "installPhase" "fixupPhase" ];
 +                    installPhase = "cp $src $out";
 +                    fixupPhase = ''
 +                    chmod 755 $out
 +                    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
 +                    '';
 +                }
 +            `;
 +            const origFile = vscode.Uri.file(dest.fsPath + "-orig");
 +            await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
 +            try {
 +                progress.report({ message: "Patching executable", increment: 20 });
 +                await new Promise((resolve, reject) => {
 +                    const handle = exec(
 +                        `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
 +                        (err, stdout, stderr) => {
 +                            if (err != null) {
 +                                reject(Error(stderr));
 +                            } else {
 +                                resolve(stdout);
 +                            }
 +                        }
 +                    );
 +                    handle.stdin?.write(expression);
 +                    handle.stdin?.end();
 +                });
 +            } finally {
 +                await vscode.workspace.fs.delete(origFile);
 +            }
 +        }
 +    );
 +}
 +
 +async function getServer(
 +    context: vscode.ExtensionContext,
 +    config: Config,
 +    state: PersistentState
 +): Promise<string | undefined> {
 +    const explicitPath = serverPath(config);
 +    if (explicitPath) {
 +        if (explicitPath.startsWith("~/")) {
 +            return os.homedir() + explicitPath.slice("~".length);
 +        }
 +        return explicitPath;
 +    }
 +    if (config.package.releaseTag === null) return "rust-analyzer";
 +
 +    const ext = process.platform === "win32" ? ".exe" : "";
 +    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
 +    const bundledExists = await vscode.workspace.fs.stat(bundled).then(
 +        () => true,
 +        () => false
 +    );
 +    if (bundledExists) {
 +        let server = bundled;
 +        if (await isNixOs()) {
 +            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
 +            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
 +            let exists = await vscode.workspace.fs.stat(dest).then(
 +                () => true,
 +                () => false
 +            );
 +            if (exists && config.package.version !== state.serverVersion) {
 +                await vscode.workspace.fs.delete(dest);
 +                exists = false;
 +            }
 +            if (!exists) {
 +                await vscode.workspace.fs.copy(bundled, dest);
 +                await patchelf(dest);
 +            }
 +            server = dest;
 +        }
 +        await state.updateServerVersion(config.package.version);
 +        return server.fsPath;
 +    }
 +
 +    await state.updateServerVersion(undefined);
 +    await vscode.window.showErrorMessage(
 +        "Unfortunately we don't ship binaries for your platform yet. " +
 +            "You need to manually clone the rust-analyzer repository and " +
 +            "run `cargo xtask install --server` to build the language server from sources. " +
 +            "If you feel that your platform should be supported, please create an issue " +
 +            "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
 +            "will consider it."
 +    );
 +    return undefined;
 +}
 +
 +function serverPath(config: Config): string | null {
 +    return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
 +}
 +
 +async function isNixOs(): Promise<boolean> {
 +    try {
 +        const contents = (
 +            await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
 +        ).toString();
 +        const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
 +        return idString.indexOf("nixos") !== -1;
 +    } catch {
 +        return false;
 +    }
 +}
 +
 +function warnAboutExtensionConflicts() {
 +    if (vscode.extensions.getExtension("rust-lang.rust")) {
 +        vscode.window
 +            .showWarningMessage(
 +                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
 +                    "plugins enabled. These are known to conflict and cause various functions of " +
 +                    "both plugins to not work correctly. You should disable one of them.",
 +                "Got it"
 +            )
 +            .then(() => {}, console.error);
 +    }
 +}
 +
 +/**
 + * Sets up additional language configuration that's impossible to do via a
 + * separate language-configuration.json file. See [1] for more information.
 + *
 + * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
 + */
 +function configureLanguage(): vscode.Disposable {
 +    const indentAction = vscode.IndentAction.None;
 +    return vscode.languages.setLanguageConfiguration("rust", {
 +        onEnterRules: [
 +            {
 +                // Doc single-line comment
 +                // e.g. ///|
 +                beforeText: /^\s*\/{3}.*$/,
 +                action: { indentAction, appendText: "/// " },
 +            },
 +            {
 +                // Parent doc single-line comment
 +                // e.g. //!|
 +                beforeText: /^\s*\/{2}\!.*$/,
 +                action: { indentAction, appendText: "//! " },
 +            },
 +            {
 +                // Begins an auto-closed multi-line comment (standard or parent doc)
 +                // e.g. /** | */ or /*! | */
 +                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
 +                afterText: /^\s*\*\/$/,
 +                action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
 +            },
 +            {
 +                // Begins a multi-line comment (standard or parent doc)
 +                // e.g. /** ...| or /*! ...|
 +                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
 +                action: { indentAction, appendText: " * " },
 +            },
 +            {
 +                // Continues a multi-line comment
 +                // e.g.  * ...|
 +                beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
 +                action: { indentAction, appendText: "* " },
 +            },
 +            {
 +                // Dedents after closing a multi-line comment
 +                // e.g.  */|
 +                beforeText: /^(\ \ )*\ \*\/\s*$/,
 +                action: { indentAction, removeText: 1 },
 +            },
 +        ],
 +    });
 +}