]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit 'e36a20c24f35a4cee82bbdc600289104c9237c22' into ra-sync-and-pms-component
authorAmos Wenger <amoswenger@gmail.com>
Tue, 26 Jul 2022 09:53:50 +0000 (11:53 +0200)
committerAmos Wenger <amoswenger@gmail.com>
Tue, 26 Jul 2022 09:53:50 +0000 (11:53 +0200)
48 files changed:
1  2 
src/tools/rust-analyzer/Cargo.lock
src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
src/tools/rust-analyzer/crates/hir-def/src/data.rs
src/tools/rust-analyzer/crates/hir-def/src/expr.rs
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
src/tools/rust-analyzer/crates/hir-def/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/hir/src/semantics.rs
src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
src/tools/rust-analyzer/crates/ide-completion/src/item.rs
src/tools/rust-analyzer/crates/ide-completion/src/render.rs
src/tools/rust-analyzer/crates/ide-db/src/defs.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/rename.rs
src/tools/rust-analyzer/crates/ide-db/src/search.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
src/tools/rust-analyzer/crates/ide/src/doc_links.rs
src/tools/rust-analyzer/crates/ide/src/hover.rs
src/tools/rust-analyzer/crates/ide/src/hover/render.rs
src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
src/tools/rust-analyzer/crates/ide/src/signature_help.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs
src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
src/tools/rust-analyzer/crates/proc-macro-test/build.rs
src/tools/rust-analyzer/crates/project-model/src/project_json.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/load_cargo.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs

index 4c830006832c978fb8841e76a0e54afe75956d03,0000000000000000000000000000000000000000..703f0e5b8af9f3c33a03a678e30c887247ffe183
mode 100644,000000..100644
--- /dev/null
@@@ -1,2094 -1,0 +1,2101 @@@
 +# 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.58"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
 +
 +[[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.65"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
 +dependencies = [
 + "addr2line",
 + "cc",
 + "cfg-if",
 + "libc",
 + "miniz_oxide",
 + "object 0.28.4",
 + "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.0.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
 +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.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "83553c2ef7717e58aecdf42dd9e3c876229f5a1f35a16435b5ddc4addef81827"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "synstructure",
 +]
 +
 +[[package]]
 +name = "chalk-ir"
 +version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2dd42107d579d8ec2a5af20a8de62a37524a67bf6a4c0ff08a950068f0bfea91"
 +dependencies = [
 + "bitflags",
 + "chalk-derive",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "chalk-recursive"
 +version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c444031541a76c13c145e76d91f1548e9feb2240e7f0c3e77879ceb694994f2d"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "chalk-solve",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "chalk-solve"
 +version = "0.83.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c76f2db19c5e8a3d42340cf5b4d90b8c218750536fca35e2bb285ab6653c0bc8"
 +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"
 +version = "0.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-channel",
 + "crossbeam-deque",
 + "crossbeam-epoch",
 + "crossbeam-queue",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-channel"
 +version = "0.5.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-deque"
 +version = "0.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-epoch",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-epoch"
 +version = "0.9.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
 +dependencies = [
 + "autocfg",
 + "cfg-if",
 + "crossbeam-utils",
 + "memoffset",
 + "once_cell",
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "crossbeam-queue"
 +version = "0.3.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
 +version = "0.8.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
 +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.7.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
 +
 +[[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",
 + "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.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
 +
 +[[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",
 + "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",
 + "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",
 + "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.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
 +
 +[[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.126"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 +
 +[[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.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212"
 +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.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae"
 +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.15"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7"
 +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.28.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[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.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
 +
 +[[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.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
 +
 +[[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 0.29.0",
 + "paths",
 + "profile",
 + "serde",
 + "serde_json",
 + "snap",
 + "stdx",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv"
 +version = "0.0.0"
 +dependencies = [
 + "crossbeam",
 + "expect-test",
 + "libloading",
 + "mbe",
 + "memmap2",
 + "object 0.29.0",
 + "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.40"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
 +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 = "pulldown-cmark"
 +version = "0.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
 +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.20"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
 +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.13"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "regex"
 +version = "1.5.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
 +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.26"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
 +
 +[[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",
 + "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.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
 +
 +[[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 = "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.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde"
 +version = "1.0.138"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
 +version = "1.0.138"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
 +version = "1.0.82"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
 +dependencies = [
 + "indexmap",
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde_repr"
 +version = "0.1.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
 +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.98"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
 +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 = "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.35"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
 +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.28"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
 +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.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
 +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",
 +]
 +
 +[[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 c3f261122784e4b6021746469d6f380fb2aed0d9,0000000000000000000000000000000000000000..66f9c24e8724a77e10d73a0f55df2367ebb1e116
mode 100644,000000..100644
--- /dev/null
@@@ -1,997 -1,0 +1,1023 @@@
-                 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
 +//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
 +//! representation.
 +
 +use std::{mem, sync::Arc};
 +
 +use either::Either;
 +use hir_expand::{
 +    ast_id_map::AstIdMap,
 +    hygiene::Hygiene,
 +    name::{name, AsName, Name},
 +    AstId, ExpandError, HirFileId, InFile,
 +};
 +use la_arena::Arena;
 +use once_cell::unsync::OnceCell;
 +use profile::Count;
 +use rustc_hash::FxHashMap;
 +use syntax::{
 +    ast::{
 +        self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
 +        SlicePatComponents,
 +    },
 +    AstNode, AstPtr, SyntaxNodePtr,
 +};
 +
 +use crate::{
 +    adt::StructKind,
 +    body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
 +    body::{BodyDiagnostic, ExprSource, PatSource},
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    db::DefDatabase,
 +    expr::{
 +        dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
 +        Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
 +    },
 +    intern::Interned,
 +    item_scope::BuiltinShadowMode,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
 +};
 +
 +pub struct LowerCtx<'a> {
 +    pub db: &'a dyn DefDatabase,
 +    hygiene: Hygiene,
 +    ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
 +}
 +
 +impl<'a> LowerCtx<'a> {
 +    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
 +        LowerCtx {
 +            db,
 +            hygiene: Hygiene::new(db.upcast(), file_id),
 +            ast_id_map: Some((file_id, OnceCell::new())),
 +        }
 +    }
 +
 +    pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
 +        LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
 +    }
 +
 +    pub(crate) fn hygiene(&self) -> &Hygiene {
 +        &self.hygiene
 +    }
 +
 +    pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
 +        Path::from_src(ast, self)
 +    }
 +
 +    pub(crate) fn ast_id<N: AstNode>(&self, db: &dyn DefDatabase, item: &N) -> Option<AstId<N>> {
 +        let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
 +        let ast_id_map = ast_id_map.get_or_init(|| db.ast_id_map(file_id));
 +        Some(InFile::new(file_id, ast_id_map.ast_id(item)))
 +    }
 +}
 +
 +pub(super) fn lower(
 +    db: &dyn DefDatabase,
 +    expander: Expander,
 +    params: Option<ast::ParamList>,
 +    body: Option<ast::Expr>,
 +) -> (Body, BodySourceMap) {
 +    ExprCollector {
 +        db,
 +        source_map: BodySourceMap::default(),
 +        ast_id_map: db.ast_id_map(expander.current_file_id),
 +        body: Body {
 +            exprs: Arena::default(),
 +            pats: Arena::default(),
 +            labels: Arena::default(),
 +            params: Vec::new(),
 +            body_expr: dummy_expr_id(),
 +            block_scopes: Vec::new(),
 +            _c: Count::new(),
 +            or_pats: Default::default(),
 +        },
 +        expander,
 +        name_to_pat_grouping: Default::default(),
 +        is_lowering_inside_or_pat: false,
++        is_lowering_assignee_expr: false,
 +    }
 +    .collect(params, body)
 +}
 +
 +struct ExprCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    expander: Expander,
 +    ast_id_map: Arc<AstIdMap>,
 +    body: Body,
 +    source_map: BodySourceMap,
 +    // a poor-mans union-find?
 +    name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
 +    is_lowering_inside_or_pat: bool,
++    is_lowering_assignee_expr: bool,
 +}
 +
 +impl ExprCollector<'_> {
 +    fn collect(
 +        mut self,
 +        param_list: Option<ast::ParamList>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
 +        if let Some(param_list) = param_list {
 +            if let Some(self_param) = param_list.self_param() {
 +                let ptr = AstPtr::new(&self_param);
 +                let param_pat = self.alloc_pat(
 +                    Pat::Bind {
 +                        name: name![self],
 +                        mode: BindingAnnotation::new(
 +                            self_param.mut_token().is_some() && self_param.amp_token().is_none(),
 +                            false,
 +                        ),
 +                        subpat: None,
 +                    },
 +                    Either::Right(ptr),
 +                );
 +                self.body.params.push(param_pat);
 +            }
 +
 +            for pat in param_list.params().filter_map(|param| param.pat()) {
 +                let param_pat = self.collect_pat(pat);
 +                self.body.params.push(param_pat);
 +            }
 +        };
 +
 +        self.body.body_expr = self.collect_expr_opt(body);
 +        (self.body, self.source_map)
 +    }
 +
 +    fn ctx(&self) -> LowerCtx<'_> {
 +        LowerCtx::new(self.db, self.expander.current_file_id)
 +    }
 +
 +    fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_expr(expr, Ok(src.clone()));
 +        self.source_map.expr_map.insert(src, id);
 +        id
 +    }
 +    // desugared exprs don't have ptr, that's wrong and should be fixed
 +    // somehow.
 +    fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
 +        self.make_expr(expr, Err(SyntheticSyntax))
 +    }
 +    fn missing_expr(&mut self) -> ExprId {
 +        self.alloc_expr_desugared(Expr::Missing)
 +    }
 +    fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
 +        let id = self.body.exprs.alloc(expr);
 +        self.source_map.expr_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_pat(pat, Ok(src.clone()));
 +        self.source_map.pat_map.insert(src, id);
 +        id
 +    }
 +    fn missing_pat(&mut self) -> PatId {
 +        self.make_pat(Pat::Missing, Err(SyntheticSyntax))
 +    }
 +    fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
 +        let id = self.body.pats.alloc(pat);
 +        self.source_map.pat_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_label(label, src.clone());
 +        self.source_map.label_map.insert(src, id);
 +        id
 +    }
 +    fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
 +        let id = self.body.labels.alloc(label);
 +        self.source_map.label_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
 +        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
 +    }
 +
 +    /// Returns `None` if and only if the expression is `#[cfg]`d out.
 +    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
 +        let syntax_ptr = AstPtr::new(&expr);
 +        self.check_cfg(&expr)?;
 +
 +        Some(match expr {
 +            ast::Expr::IfExpr(e) => {
 +                let then_branch = self.collect_block_opt(e.then_branch());
 +
 +                let else_branch = e.else_branch().map(|b| match b {
 +                    ast::ElseBranch::Block(it) => self.collect_block(it),
 +                    ast::ElseBranch::IfExpr(elif) => {
 +                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
 +                        self.collect_expr(expr)
 +                    }
 +                });
 +
 +                let condition = self.collect_expr_opt(e.condition());
 +
 +                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
 +            }
 +            ast::Expr::LetExpr(e) => {
 +                let pat = self.collect_pat_opt(e.pat());
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
 +            }
 +            ast::Expr::BlockExpr(e) => match e.modifier() {
 +                Some(ast::BlockModifier::Try(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
 +                }
 +                Some(ast::BlockModifier::Unsafe(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
 +                }
 +                // FIXME: we need to record these effects somewhere...
 +                Some(ast::BlockModifier::Label(label)) => {
 +                    let label = self.collect_label(label);
 +                    let res = self.collect_block(e);
 +                    match &mut self.body.exprs[res] {
 +                        Expr::Block { label: block_label, .. } => {
 +                            *block_label = Some(label);
 +                        }
 +                        _ => unreachable!(),
 +                    }
 +                    res
 +                }
 +                Some(ast::BlockModifier::Async(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Async { body }, syntax_ptr)
 +                }
 +                Some(ast::BlockModifier::Const(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Const { body }, syntax_ptr)
 +                }
 +                None => self.collect_block(e),
 +            },
 +            ast::Expr::LoopExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let body = self.collect_block_opt(e.loop_body());
 +                self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
 +            }
 +            ast::Expr::WhileExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let body = self.collect_block_opt(e.loop_body());
 +
 +                let condition = self.collect_expr_opt(e.condition());
 +
 +                self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
 +            }
 +            ast::Expr::ForExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let iterable = self.collect_expr_opt(e.iterable());
 +                let pat = self.collect_pat_opt(e.pat());
 +                let body = self.collect_block_opt(e.loop_body());
 +                self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
 +            }
 +            ast::Expr::CallExpr(e) => {
 +                let callee = self.collect_expr_opt(e.expr());
 +                let args = if let Some(arg_list) = e.arg_list() {
 +                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
 +                } else {
 +                    Box::default()
 +                };
-                     Expr::RecordLit { path, fields, spread }
++                self.alloc_expr(
++                    Expr::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr },
++                    syntax_ptr,
++                )
 +            }
 +            ast::Expr::MethodCallExpr(e) => {
 +                let receiver = self.collect_expr_opt(e.receiver());
 +                let args = if let Some(arg_list) = e.arg_list() {
 +                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
 +                } else {
 +                    Box::default()
 +                };
 +                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
 +                let generic_args = e
 +                    .generic_arg_list()
 +                    .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
 +                    .map(Box::new);
 +                self.alloc_expr(
 +                    Expr::MethodCall { receiver, method_name, args, generic_args },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::MatchExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let arms = if let Some(match_arm_list) = e.match_arm_list() {
 +                    match_arm_list
 +                        .arms()
 +                        .filter_map(|arm| {
 +                            self.check_cfg(&arm).map(|()| MatchArm {
 +                                pat: self.collect_pat_opt(arm.pat()),
 +                                expr: self.collect_expr_opt(arm.expr()),
 +                                guard: arm
 +                                    .guard()
 +                                    .map(|guard| self.collect_expr_opt(guard.condition())),
 +                            })
 +                        })
 +                        .collect()
 +                } else {
 +                    Box::default()
 +                };
 +                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
 +            }
 +            ast::Expr::PathExpr(e) => {
 +                let path = e
 +                    .path()
 +                    .and_then(|path| self.expander.parse_path(self.db, path))
 +                    .map(Expr::Path)
 +                    .unwrap_or(Expr::Missing);
 +                self.alloc_expr(path, syntax_ptr)
 +            }
 +            ast::Expr::ContinueExpr(e) => self.alloc_expr(
 +                Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
 +                syntax_ptr,
 +            ),
 +            ast::Expr::BreakExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(
 +                    Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::ParenExpr(e) => {
 +                let inner = self.collect_expr_opt(e.expr());
 +                // make the paren expr point to the inner expression as well
 +                let src = self.expander.to_source(syntax_ptr);
 +                self.source_map.expr_map.insert(src, inner);
 +                inner
 +            }
 +            ast::Expr::ReturnExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(Expr::Return { expr }, syntax_ptr)
 +            }
 +            ast::Expr::YieldExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
 +            }
 +            ast::Expr::RecordExpr(e) => {
 +                let path =
 +                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
++                let is_assignee_expr = self.is_lowering_assignee_expr;
 +                let record_lit = if let Some(nfl) = e.record_expr_field_list() {
 +                    let fields = nfl
 +                        .fields()
 +                        .filter_map(|field| {
 +                            self.check_cfg(&field)?;
 +
 +                            let name = field.field_name()?.as_name();
 +
 +                            let expr = match field.expr() {
 +                                Some(e) => self.collect_expr(e),
 +                                None => self.missing_expr(),
 +                            };
 +                            let src = self.expander.to_source(AstPtr::new(&field));
 +                            self.source_map.field_map.insert(src.clone(), expr);
 +                            self.source_map.field_map_back.insert(expr, src);
 +                            Some(RecordLitField { name, expr })
 +                        })
 +                        .collect();
 +                    let spread = nfl.spread().map(|s| self.collect_expr(s));
-                     Expr::RecordLit { path, fields: Box::default(), spread: None }
++                    let ellipsis = nfl.dotdot_token().is_some();
++                    Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
 +                } else {
-                 let op = e.op_kind();
++                    Expr::RecordLit {
++                        path,
++                        fields: Box::default(),
++                        spread: None,
++                        ellipsis: false,
++                        is_assignee_expr,
++                    }
 +                };
 +
 +                self.alloc_expr(record_lit, syntax_ptr)
 +            }
 +            ast::Expr::FieldExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let name = match e.field_access() {
 +                    Some(kind) => kind.as_name(),
 +                    _ => Name::missing(),
 +                };
 +                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
 +            }
 +            ast::Expr::AwaitExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Await { expr }, syntax_ptr)
 +            }
 +            ast::Expr::TryExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Try { expr }, syntax_ptr)
 +            }
 +            ast::Expr::CastExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
 +                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
 +            }
 +            ast::Expr::RefExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let raw_tok = e.raw_token().is_some();
 +                let mutability = if raw_tok {
 +                    if e.mut_token().is_some() {
 +                        Mutability::Mut
 +                    } else if e.const_token().is_some() {
 +                        Mutability::Shared
 +                    } else {
 +                        unreachable!("parser only remaps to raw_token() if matching mutability token follows")
 +                    }
 +                } else {
 +                    Mutability::from_mutable(e.mut_token().is_some())
 +                };
 +                let rawness = Rawness::from_raw(raw_tok);
 +                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
 +            }
 +            ast::Expr::PrefixExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                match e.op_kind() {
 +                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::ClosureExpr(e) => {
 +                let mut args = Vec::new();
 +                let mut arg_types = Vec::new();
 +                if let Some(pl) = e.param_list() {
 +                    for param in pl.params() {
 +                        let pat = self.collect_pat_opt(param.pat());
 +                        let type_ref =
 +                            param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                        args.push(pat);
 +                        arg_types.push(type_ref);
 +                    }
 +                }
 +                let ret_type = e
 +                    .ret_type()
 +                    .and_then(|r| r.ty())
 +                    .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                let body = self.collect_expr_opt(e.body());
 +                self.alloc_expr(
 +                    Expr::Closure {
 +                        args: args.into(),
 +                        arg_types: arg_types.into(),
 +                        ret_type,
 +                        body,
 +                    },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::BinExpr(e) => {
++                let op = e.op_kind();
++                if let Some(ast::BinaryOp::Assignment { op: None }) = op {
++                    self.is_lowering_assignee_expr = true;
++                }
 +                let lhs = self.collect_expr_opt(e.lhs());
++                self.is_lowering_assignee_expr = false;
 +                let rhs = self.collect_expr_opt(e.rhs());
-                 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
 +                self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
 +            }
 +            ast::Expr::TupleExpr(e) => {
 +                let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
-                         let exprs = e.map(|expr| self.collect_expr(expr)).collect();
-                         self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
++                self.alloc_expr(
++                    Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr },
++                    syntax_ptr,
++                )
 +            }
 +            ast::Expr::BoxExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Box { expr }, syntax_ptr)
 +            }
 +
 +            ast::Expr::ArrayExpr(e) => {
 +                let kind = e.kind();
 +
 +                match kind {
 +                    ArrayExprKind::ElementList(e) => {
++                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
++                        self.alloc_expr(
++                            Expr::Array(Array::ElementList {
++                                elements,
++                                is_assignee_expr: self.is_lowering_assignee_expr,
++                            }),
++                            syntax_ptr,
++                        )
 +                    }
 +                    ArrayExprKind::Repeat { initializer, repeat } => {
 +                        let initializer = self.collect_expr_opt(initializer);
 +                        let repeat = self.collect_expr_opt(repeat);
 +                        self.alloc_expr(
 +                            Expr::Array(Array::Repeat { initializer, repeat }),
 +                            syntax_ptr,
 +                        )
 +                    }
 +                }
 +            }
 +
 +            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
 +            ast::Expr::IndexExpr(e) => {
 +                let base = self.collect_expr_opt(e.base());
 +                let index = self.collect_expr_opt(e.index());
 +                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
 +            }
 +            ast::Expr::RangeExpr(e) => {
 +                let lhs = e.start().map(|lhs| self.collect_expr(lhs));
 +                let rhs = e.end().map(|rhs| self.collect_expr(rhs));
 +                match e.op_kind() {
 +                    Some(range_type) => {
 +                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::MacroExpr(e) => {
 +                let e = e.macro_call()?;
 +                let macro_ptr = AstPtr::new(&e);
 +                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
 +                    expansion.map(|it| this.collect_expr(it))
 +                });
 +                match id {
 +                    Some(id) => {
 +                        // Make the macro-call point to its expanded expression so we can query
 +                        // semantics on syntax pointers to the macro
 +                        let src = self.expander.to_source(syntax_ptr);
 +                        self.source_map.expr_map.insert(src, id);
 +                        id
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::MacroStmts(e) => {
 +                let statements = e.statements().filter_map(|s| self.collect_stmt(s)).collect();
 +                let tail = e.expr().map(|e| self.collect_expr(e));
 +
 +                self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
 +            }
 +            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
 +        })
 +    }
 +
 +    fn collect_macro_call<F, T, U>(
 +        &mut self,
 +        mcall: ast::MacroCall,
 +        syntax_ptr: AstPtr<ast::MacroCall>,
 +        record_diagnostics: bool,
 +        collector: F,
 +    ) -> U
 +    where
 +        F: FnOnce(&mut Self, Option<T>) -> U,
 +        T: ast::AstNode,
 +    {
 +        // File containing the macro call. Expansion errors will be attached here.
 +        let outer_file = self.expander.current_file_id;
 +
 +        let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
 +        let res = self.expander.enter_expand(self.db, mcall);
 +
 +        let res = match res {
 +            Ok(res) => res,
 +            Err(UnresolvedMacro { path }) => {
 +                if record_diagnostics {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        path,
 +                    });
 +                }
 +                return collector(self, None);
 +            }
 +        };
 +
 +        if record_diagnostics {
 +            match &res.err {
 +                Some(ExpandError::UnresolvedProcMacro(krate)) => {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        krate: *krate,
 +                    });
 +                }
 +                Some(err) => {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        message: err.to_string(),
 +                    });
 +                }
 +                None => {}
 +            }
 +        }
 +
 +        match res.value {
 +            Some((mark, expansion)) => {
 +                self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id);
 +                let prev_ast_id_map = mem::replace(
 +                    &mut self.ast_id_map,
 +                    self.db.ast_id_map(self.expander.current_file_id),
 +                );
 +
 +                let id = collector(self, Some(expansion));
 +                self.ast_id_map = prev_ast_id_map;
 +                self.expander.exit(self.db, mark);
 +                id
 +            }
 +            None => collector(self, None),
 +        }
 +    }
 +
 +    fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
 +        match expr {
 +            Some(expr) => self.collect_expr(expr),
 +            None => self.missing_expr(),
 +        }
 +    }
 +
 +    fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
 +        match s {
 +            ast::Stmt::LetStmt(stmt) => {
 +                if self.check_cfg(&stmt).is_none() {
 +                    return None;
 +                }
 +                let pat = self.collect_pat_opt(stmt.pat());
 +                let type_ref =
 +                    stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
 +                let else_branch = stmt
 +                    .let_else()
 +                    .and_then(|let_else| let_else.block_expr())
 +                    .map(|block| self.collect_block(block));
 +                Some(Statement::Let { pat, type_ref, initializer, else_branch })
 +            }
 +            ast::Stmt::ExprStmt(stmt) => {
 +                let expr = stmt.expr();
 +                if let Some(expr) = &expr {
 +                    if self.check_cfg(expr).is_none() {
 +                        return None;
 +                    }
 +                }
 +                let has_semi = stmt.semicolon_token().is_some();
 +                // Note that macro could be expanded to multiple statements
 +                if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
 +                    let mac_call = mac.macro_call()?;
 +                    let syntax_ptr = AstPtr::new(expr);
 +                    let macro_ptr = AstPtr::new(&mac_call);
 +                    let stmt = self.collect_macro_call(
 +                        mac_call,
 +                        macro_ptr,
 +                        false,
 +                        |this, expansion: Option<ast::MacroStmts>| match expansion {
 +                            Some(expansion) => {
 +                                let statements = expansion
 +                                    .statements()
 +                                    .filter_map(|stmt| this.collect_stmt(stmt))
 +                                    .collect();
 +                                let tail = expansion.expr().map(|expr| this.collect_expr(expr));
 +
 +                                let mac_stmts = this.alloc_expr(
 +                                    Expr::MacroStmts { tail, statements },
 +                                    AstPtr::new(&ast::Expr::MacroStmts(expansion)),
 +                                );
 +
 +                                Some(mac_stmts)
 +                            }
 +                            None => None,
 +                        },
 +                    );
 +
 +                    let expr = match stmt {
 +                        Some(expr) => {
 +                            // Make the macro-call point to its expanded expression so we can query
 +                            // semantics on syntax pointers to the macro
 +                            let src = self.expander.to_source(syntax_ptr);
 +                            self.source_map.expr_map.insert(src, expr);
 +                            expr
 +                        }
 +                        None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                    };
 +                    Some(Statement::Expr { expr, has_semi })
 +                } else {
 +                    let expr = self.collect_expr_opt(expr);
 +                    Some(Statement::Expr { expr, has_semi })
 +                }
 +            }
 +            ast::Stmt::Item(_item) => None,
 +        }
 +    }
 +
 +    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
 +        let file_local_id = self.ast_id_map.ast_id(&block);
 +        let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
 +        let block_loc =
 +            BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
 +        let block_id = self.db.intern_block(block_loc);
 +
 +        let (module, def_map) = match self.db.block_def_map(block_id) {
 +            Some(def_map) => {
 +                self.body.block_scopes.push(block_id);
 +                (def_map.root(), def_map)
 +            }
 +            None => (self.expander.module, self.expander.def_map.clone()),
 +        };
 +        let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
 +        let prev_local_module = mem::replace(&mut self.expander.module, module);
 +
 +        let mut statements: Vec<_> =
 +            block.statements().filter_map(|s| self.collect_stmt(s)).collect();
 +        let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
 +        let tail = tail.or_else(|| {
 +            let stmt = statements.pop()?;
 +            if let Statement::Expr { expr, has_semi: false } = stmt {
 +                return Some(expr);
 +            }
 +            statements.push(stmt);
 +            None
 +        });
 +
 +        let syntax_node_ptr = AstPtr::new(&block.into());
 +        let expr_id = self.alloc_expr(
 +            Expr::Block {
 +                id: block_id,
 +                statements: statements.into_boxed_slice(),
 +                tail,
 +                label: None,
 +            },
 +            syntax_node_ptr,
 +        );
 +
 +        self.expander.def_map = prev_def_map;
 +        self.expander.module = prev_local_module;
 +        expr_id
 +    }
 +
 +    fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
 +        match expr {
 +            Some(block) => self.collect_block(block),
 +            None => self.missing_expr(),
 +        }
 +    }
 +
 +    fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
 +        let label = Label {
 +            name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
 +        };
 +        self.alloc_label(label, AstPtr::new(&ast_label))
 +    }
 +
 +    fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
 +        let pat_id = self.collect_pat_(pat);
 +        for (_, pats) in self.name_to_pat_grouping.drain() {
 +            let pats = Arc::<[_]>::from(pats);
 +            self.body.or_pats.extend(pats.iter().map(|&pat| (pat, pats.clone())));
 +        }
 +        self.is_lowering_inside_or_pat = false;
 +        pat_id
 +    }
 +
 +    fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
 +        match pat {
 +            Some(pat) => self.collect_pat(pat),
 +            None => self.missing_pat(),
 +        }
 +    }
 +
 +    fn collect_pat_(&mut self, pat: ast::Pat) -> PatId {
 +        let pattern = match &pat {
 +            ast::Pat::IdentPat(bp) => {
 +                let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
 +
 +                let key = self.is_lowering_inside_or_pat.then(|| name.clone());
 +                let annotation =
 +                    BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
 +                let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat));
 +                let pattern = if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
 +                    // This could also be a single-segment path pattern. To
 +                    // decide that, we need to try resolving the name.
 +                    let (resolved, _) = self.expander.def_map.resolve_path(
 +                        self.db,
 +                        self.expander.module,
 +                        &name.clone().into(),
 +                        BuiltinShadowMode::Other,
 +                    );
 +                    match resolved.take_values() {
 +                        Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
 +                        Some(ModuleDefId::EnumVariantId(_)) => {
 +                            // this is only really valid for unit variants, but
 +                            // shadowing other enum variants with a pattern is
 +                            // an error anyway
 +                            Pat::Path(name.into())
 +                        }
 +                        Some(ModuleDefId::AdtId(AdtId::StructId(s)))
 +                            if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
 +                        {
 +                            // Funnily enough, record structs *can* be shadowed
 +                            // by pattern bindings (but unit or tuple structs
 +                            // can't).
 +                            Pat::Path(name.into())
 +                        }
 +                        // shadowing statics is an error as well, so we just ignore that case here
 +                        _ => Pat::Bind { name, mode: annotation, subpat },
 +                    }
 +                } else {
 +                    Pat::Bind { name, mode: annotation, subpat }
 +                };
 +
 +                let ptr = AstPtr::new(&pat);
 +                let pat = self.alloc_pat(pattern, Either::Left(ptr));
 +                if let Some(key) = key {
 +                    self.name_to_pat_grouping.entry(key).or_default().push(pat);
 +                }
 +                return pat;
 +            }
 +            ast::Pat::TupleStructPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let (args, ellipsis) = self.collect_tuple_pat(p.fields());
 +                Pat::TupleStruct { path, args, ellipsis }
 +            }
 +            ast::Pat::RefPat(p) => {
 +                let pat = self.collect_pat_opt(p.pat());
 +                let mutability = Mutability::from_mutable(p.mut_token().is_some());
 +                Pat::Ref { pat, mutability }
 +            }
 +            ast::Pat::PathPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                path.map(Pat::Path).unwrap_or(Pat::Missing)
 +            }
 +            ast::Pat::OrPat(p) => {
 +                self.is_lowering_inside_or_pat = true;
 +                let pats = p.pats().map(|p| self.collect_pat_(p)).collect();
 +                Pat::Or(pats)
 +            }
 +            ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat()),
 +            ast::Pat::TuplePat(p) => {
 +                let (args, ellipsis) = self.collect_tuple_pat(p.fields());
 +                Pat::Tuple { args, ellipsis }
 +            }
 +            ast::Pat::WildcardPat(_) => Pat::Wild,
 +            ast::Pat::RecordPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let args = p
 +                    .record_pat_field_list()
 +                    .expect("every struct should have a field list")
 +                    .fields()
 +                    .filter_map(|f| {
 +                        let ast_pat = f.pat()?;
 +                        let pat = self.collect_pat_(ast_pat);
 +                        let name = f.field_name()?.as_name();
 +                        Some(RecordFieldPat { name, pat })
 +                    })
 +                    .collect();
 +
 +                let ellipsis = p
 +                    .record_pat_field_list()
 +                    .expect("every struct should have a field list")
 +                    .rest_pat()
 +                    .is_some();
 +
 +                Pat::Record { path, args, ellipsis }
 +            }
 +            ast::Pat::SlicePat(p) => {
 +                let SlicePatComponents { prefix, slice, suffix } = p.components();
 +
 +                // FIXME properly handle `RestPat`
 +                Pat::Slice {
 +                    prefix: prefix.into_iter().map(|p| self.collect_pat_(p)).collect(),
 +                    slice: slice.map(|p| self.collect_pat_(p)),
 +                    suffix: suffix.into_iter().map(|p| self.collect_pat_(p)).collect(),
 +                }
 +            }
 +            ast::Pat::LiteralPat(lit) => {
 +                if let Some(ast_lit) = lit.literal() {
 +                    let expr = Expr::Literal(ast_lit.kind().into());
 +                    let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
 +                    let expr_id = self.alloc_expr(expr, expr_ptr);
 +                    Pat::Lit(expr_id)
 +                } else {
 +                    Pat::Missing
 +                }
 +            }
 +            ast::Pat::RestPat(_) => {
 +                // `RestPat` requires special handling and should not be mapped
 +                // to a Pat. Here we are using `Pat::Missing` as a fallback for
 +                // when `RestPat` is mapped to `Pat`, which can easily happen
 +                // when the source code being analyzed has a malformed pattern
 +                // which includes `..` in a place where it isn't valid.
 +
 +                Pat::Missing
 +            }
 +            ast::Pat::BoxPat(boxpat) => {
 +                let inner = self.collect_pat_opt_(boxpat.pat());
 +                Pat::Box { inner }
 +            }
 +            ast::Pat::ConstBlockPat(const_block_pat) => {
 +                if let Some(expr) = const_block_pat.block_expr() {
 +                    let expr_id = self.collect_block(expr);
 +                    Pat::ConstBlock(expr_id)
 +                } else {
 +                    Pat::Missing
 +                }
 +            }
 +            ast::Pat::MacroPat(mac) => match mac.macro_call() {
 +                Some(call) => {
 +                    let macro_ptr = AstPtr::new(&call);
 +                    let src = self.expander.to_source(Either::Left(AstPtr::new(&pat)));
 +                    let pat =
 +                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
 +                            this.collect_pat_opt_(expanded_pat)
 +                        });
 +                    self.source_map.pat_map.insert(src, pat);
 +                    return pat;
 +                }
 +                None => Pat::Missing,
 +            },
 +            // FIXME: implement
 +            ast::Pat::RangePat(_) => Pat::Missing,
 +        };
 +        let ptr = AstPtr::new(&pat);
 +        self.alloc_pat(pattern, Either::Left(ptr))
 +    }
 +
 +    fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>) -> PatId {
 +        match pat {
 +            Some(pat) => self.collect_pat_(pat),
 +            None => self.missing_pat(),
 +        }
 +    }
 +
 +    fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Box<[PatId]>, Option<usize>) {
 +        // Find the location of the `..`, if there is one. Note that we do not
 +        // consider the possibility of there being multiple `..` here.
 +        let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
 +        // We want to skip the `..` pattern here, since we account for it above.
 +        let args = args
 +            .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
 +            .map(|p| self.collect_pat_(p))
 +            .collect();
 +
 +        (args, ellipsis)
 +    }
 +
 +    /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
 +    /// not.
 +    fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
 +        match self.expander.parse_attrs(self.db, owner).cfg() {
 +            Some(cfg) => {
 +                if self.expander.cfg_options().check(&cfg) != Some(false) {
 +                    return Some(());
 +                }
 +
 +                self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
 +                    node: InFile::new(
 +                        self.expander.current_file_id,
 +                        SyntaxNodePtr::new(owner.syntax()),
 +                    ),
 +                    cfg,
 +                    opts: self.expander.cfg_options().clone(),
 +                });
 +
 +                None
 +            }
 +            None => Some(()),
 +        }
 +    }
 +}
 +
 +impl From<ast::LiteralKind> for Literal {
 +    fn from(ast_lit_kind: ast::LiteralKind) -> Self {
 +        match ast_lit_kind {
 +            // FIXME: these should have actual values filled in, but unsure on perf impact
 +            LiteralKind::IntNumber(lit) => {
 +                if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
 +                    Literal::Float(
 +                        FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
 +                        builtin,
 +                    )
 +                } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
 +                    Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
 +                } else {
 +                    let builtin = lit.suffix().and_then(BuiltinUint::from_suffix);
 +                    Literal::Uint(lit.value().unwrap_or(0), builtin)
 +                }
 +            }
 +            LiteralKind::FloatNumber(lit) => {
 +                let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
 +                Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
 +            }
 +            LiteralKind::ByteString(bs) => {
 +                let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
 +                Literal::ByteString(text)
 +            }
 +            LiteralKind::String(s) => {
 +                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
 +                Literal::String(text)
 +            }
 +            LiteralKind::Byte(b) => {
 +                Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
 +            }
 +            LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
 +            LiteralKind::Bool(val) => Literal::Bool(val),
 +        }
 +    }
 +}
index 4309411419334d4a3bf358f96d15bf145aa07c5c,0000000000000000000000000000000000000000..35c8708955a77757b56635b9c28845e1c3916514
mode 100644,000000..100644
--- /dev/null
@@@ -1,572 -1,0 +1,579 @@@
-     nameres::{attr_resolution::ResolvedAttr, DefMap},
 +//! Contains basic data about various HIR declarations.
 +
 +use std::sync::Arc;
 +
 +use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind};
 +use smallvec::SmallVec;
 +use syntax::ast;
 +
 +use crate::{
 +    attr::Attrs,
 +    body::{Expander, Mark},
 +    db::DefDatabase,
 +    intern::Interned,
 +    item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
-     // FIXME: Record deriver helper here?
++    nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap},
 +    type_ref::{TraitRef, TypeBound, TypeRef},
 +    visibility::RawVisibility,
 +    AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
 +    Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, ProcMacroId,
 +    StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 +};
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct FunctionData {
 +    pub name: Name,
 +    pub params: Vec<(Option<Name>, Interned<TypeRef>)>,
 +    pub ret_type: Interned<TypeRef>,
 +    pub async_ret_type: Option<Interned<TypeRef>>,
 +    pub attrs: Attrs,
 +    pub visibility: RawVisibility,
 +    pub abi: Option<Interned<str>>,
 +    pub legacy_const_generics_indices: Box<[u32]>,
 +    flags: FnFlags,
 +}
 +
 +impl FunctionData {
 +    pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
 +        let loc = func.lookup(db);
 +        let krate = loc.container.module(db).krate;
 +        let crate_graph = db.crate_graph();
 +        let cfg_options = &crate_graph[krate].cfg_options;
 +        let item_tree = loc.id.item_tree(db);
 +        let func = &item_tree[loc.id.value];
 +        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
 +            db.trait_data(trait_id).visibility.clone()
 +        } else {
 +            item_tree[func.visibility].clone()
 +        };
 +
 +        let enabled_params = func
 +            .params
 +            .clone()
 +            .filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));
 +
 +        // If last cfg-enabled param is a `...` param, it's a varargs function.
 +        let is_varargs = enabled_params
 +            .clone()
 +            .next_back()
 +            .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
 +
 +        let mut flags = func.flags;
 +        if is_varargs {
 +            flags |= FnFlags::IS_VARARGS;
 +        }
 +        if flags.contains(FnFlags::HAS_SELF_PARAM) {
 +            // If there's a self param in the syntax, but it is cfg'd out, remove the flag.
 +            let is_cfgd_out = match func.params.clone().next() {
 +                Some(param) => {
 +                    !item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options)
 +                }
 +                None => {
 +                    stdx::never!("fn HAS_SELF_PARAM but no parameters allocated");
 +                    true
 +                }
 +            };
 +            if is_cfgd_out {
 +                cov_mark::hit!(cfgd_out_self_param);
 +                flags.remove(FnFlags::HAS_SELF_PARAM);
 +            }
 +        }
 +
 +        let legacy_const_generics_indices = item_tree
 +            .attrs(db, krate, ModItem::from(loc.id.value).into())
 +            .by_key("rustc_legacy_const_generics")
 +            .tt_values()
 +            .next()
 +            .map(parse_rustc_legacy_const_generics)
 +            .unwrap_or_default();
 +
 +        Arc::new(FunctionData {
 +            name: func.name.clone(),
 +            params: enabled_params
 +                .clone()
 +                .filter_map(|id| match &item_tree[id] {
 +                    Param::Normal(name, ty) => Some((name.clone(), ty.clone())),
 +                    Param::Varargs => None,
 +                })
 +                .collect(),
 +            ret_type: func.ret_type.clone(),
 +            async_ret_type: func.async_ret_type.clone(),
 +            attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
 +            visibility,
 +            abi: func.abi.clone(),
 +            legacy_const_generics_indices,
 +            flags,
 +        })
 +    }
 +
 +    pub fn has_body(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_BODY)
 +    }
 +
 +    /// True if the first param is `self`. This is relevant to decide whether this
 +    /// can be called as a method.
 +    pub fn has_self_param(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_SELF_PARAM)
 +    }
 +
 +    pub fn has_default_kw(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_DEFAULT_KW)
 +    }
 +
 +    pub fn has_const_kw(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_CONST_KW)
 +    }
 +
 +    pub fn has_async_kw(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_ASYNC_KW)
 +    }
 +
 +    pub fn has_unsafe_kw(&self) -> bool {
 +        self.flags.contains(FnFlags::HAS_UNSAFE_KW)
 +    }
 +
 +    pub fn is_varargs(&self) -> bool {
 +        self.flags.contains(FnFlags::IS_VARARGS)
 +    }
 +}
 +
 +fn parse_rustc_legacy_const_generics(tt: &tt::Subtree) -> Box<[u32]> {
 +    let mut indices = Vec::new();
 +    for args in tt.token_trees.chunks(2) {
 +        match &args[0] {
 +            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => match lit.text.parse() {
 +                Ok(index) => indices.push(index),
 +                Err(_) => break,
 +            },
 +            _ => break,
 +        }
 +
 +        if let Some(comma) = args.get(1) {
 +            match comma {
 +                tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.char == ',' => {}
 +                _ => break,
 +            }
 +        }
 +    }
 +
 +    indices.into_boxed_slice()
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct TypeAliasData {
 +    pub name: Name,
 +    pub type_ref: Option<Interned<TypeRef>>,
 +    pub visibility: RawVisibility,
 +    pub is_extern: bool,
 +    /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
 +    pub bounds: Vec<Interned<TypeBound>>,
 +}
 +
 +impl TypeAliasData {
 +    pub(crate) fn type_alias_data_query(
 +        db: &dyn DefDatabase,
 +        typ: TypeAliasId,
 +    ) -> Arc<TypeAliasData> {
 +        let loc = typ.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let typ = &item_tree[loc.id.value];
 +        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
 +            db.trait_data(trait_id).visibility.clone()
 +        } else {
 +            item_tree[typ.visibility].clone()
 +        };
 +
 +        Arc::new(TypeAliasData {
 +            name: typ.name.clone(),
 +            type_ref: typ.type_ref.clone(),
 +            visibility,
 +            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
 +            bounds: typ.bounds.to_vec(),
 +        })
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct TraitData {
 +    pub name: Name,
 +    pub items: Vec<(Name, AssocItemId)>,
 +    pub is_auto: bool,
 +    pub is_unsafe: bool,
 +    pub visibility: RawVisibility,
 +    /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
 +    /// method calls to this trait's methods when the receiver is an array and the crate edition is
 +    /// 2015 or 2018.
 +    pub skip_array_during_method_dispatch: bool,
 +    // box it as the vec is usually empty anyways
 +    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 +}
 +
 +impl TraitData {
 +    pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
 +        let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
 +        let item_tree = tree_id.item_tree(db);
 +        let tr_def = &item_tree[tree_id.value];
 +        let _cx = stdx::panic_context::enter(format!(
 +            "trait_data_query({:?} -> {:?} -> {:?})",
 +            tr, tr_loc, tr_def
 +        ));
 +        let name = tr_def.name.clone();
 +        let is_auto = tr_def.is_auto;
 +        let is_unsafe = tr_def.is_unsafe;
 +        let visibility = item_tree[tr_def.visibility].clone();
 +        let skip_array_during_method_dispatch = item_tree
 +            .attrs(db, module_id.krate(), ModItem::from(tree_id.value).into())
 +            .by_key("rustc_skip_array_during_method_dispatch")
 +            .exists();
 +
 +        let mut collector =
 +            AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
 +        collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
 +        let (items, attribute_calls) = collector.finish();
 +
 +        Arc::new(TraitData {
 +            name,
 +            attribute_calls,
 +            items,
 +            is_auto,
 +            is_unsafe,
 +            visibility,
 +            skip_array_during_method_dispatch,
 +        })
 +    }
 +
 +    pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
 +        self.items.iter().filter_map(|(_name, item)| match item {
 +            AssocItemId::TypeAliasId(t) => Some(*t),
 +            _ => None,
 +        })
 +    }
 +
 +    pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
 +        self.items.iter().find_map(|(item_name, item)| match item {
 +            AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
 +            _ => None,
 +        })
 +    }
 +
 +    pub fn method_by_name(&self, name: &Name) -> Option<FunctionId> {
 +        self.items.iter().find_map(|(item_name, item)| match item {
 +            AssocItemId::FunctionId(t) if item_name == name => Some(*t),
 +            _ => None,
 +        })
 +    }
 +
 +    pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
 +        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct ImplData {
 +    pub target_trait: Option<Interned<TraitRef>>,
 +    pub self_ty: Interned<TypeRef>,
 +    pub items: Vec<AssocItemId>,
 +    pub is_negative: bool,
 +    // box it as the vec is usually empty anyways
 +    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 +}
 +
 +impl ImplData {
 +    pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
 +        let _p = profile::span("impl_data_query");
 +        let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
 +
 +        let item_tree = tree_id.item_tree(db);
 +        let impl_def = &item_tree[tree_id.value];
 +        let target_trait = impl_def.target_trait.clone();
 +        let self_ty = impl_def.self_ty.clone();
 +        let is_negative = impl_def.is_negative;
 +
 +        let mut collector =
 +            AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
 +        collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
 +
 +        let (items, attribute_calls) = collector.finish();
 +        let items = items.into_iter().map(|(_, item)| item).collect();
 +
 +        Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls })
 +    }
 +
 +    pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
 +        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct Macro2Data {
 +    pub name: Name,
 +    pub visibility: RawVisibility,
 +}
 +
 +impl Macro2Data {
 +    pub(crate) fn macro2_data_query(db: &dyn DefDatabase, makro: Macro2Id) -> Arc<Macro2Data> {
 +        let loc = makro.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let makro = &item_tree[loc.id.value];
 +
 +        Arc::new(Macro2Data {
 +            name: makro.name.clone(),
 +            visibility: item_tree[makro.visibility].clone(),
 +        })
 +    }
 +}
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct MacroRulesData {
 +    pub name: Name,
 +    pub macro_export: bool,
 +}
 +
 +impl MacroRulesData {
 +    pub(crate) fn macro_rules_data_query(
 +        db: &dyn DefDatabase,
 +        makro: MacroRulesId,
 +    ) -> Arc<MacroRulesData> {
 +        let loc = makro.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let makro = &item_tree[loc.id.value];
 +
 +        let macro_export = item_tree
 +            .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
 +            .by_key("macro_export")
 +            .exists();
 +
 +        Arc::new(MacroRulesData { name: makro.name.clone(), macro_export })
 +    }
 +}
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct ProcMacroData {
 +    pub name: Name,
-         let name = if let Some(def) = item_tree
++    /// Derive helpers, if this is a derive
++    pub helpers: Option<Box<[Name]>>,
 +}
 +
 +impl ProcMacroData {
 +    pub(crate) fn proc_macro_data_query(
 +        db: &dyn DefDatabase,
 +        makro: ProcMacroId,
 +    ) -> Arc<ProcMacroData> {
 +        let loc = makro.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let makro = &item_tree[loc.id.value];
 +
-             def.name
++        let (name, helpers) = if let Some(def) = item_tree
 +            .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
 +            .parse_proc_macro_decl(&makro.name)
 +        {
-             makro.name.clone()
++            (
++                def.name,
++                match def.kind {
++                    ProcMacroKind::CustomDerive { helpers } => Some(helpers),
++                    ProcMacroKind::FnLike | ProcMacroKind::Attr => None,
++                },
++            )
 +        } else {
 +            // eeeh...
 +            stdx::never!("proc macro declaration is not a proc macro");
-         Arc::new(ProcMacroData { name })
++            (makro.name.clone(), None)
 +        };
++        Arc::new(ProcMacroData { name, helpers })
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct ConstData {
 +    /// `None` for `const _: () = ();`
 +    pub name: Option<Name>,
 +    pub type_ref: Interned<TypeRef>,
 +    pub visibility: RawVisibility,
 +}
 +
 +impl ConstData {
 +    pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
 +        let loc = konst.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let konst = &item_tree[loc.id.value];
 +        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
 +            db.trait_data(trait_id).visibility.clone()
 +        } else {
 +            item_tree[konst.visibility].clone()
 +        };
 +
 +        Arc::new(ConstData {
 +            name: konst.name.clone(),
 +            type_ref: konst.type_ref.clone(),
 +            visibility,
 +        })
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct StaticData {
 +    pub name: Name,
 +    pub type_ref: Interned<TypeRef>,
 +    pub visibility: RawVisibility,
 +    pub mutable: bool,
 +    pub is_extern: bool,
 +}
 +
 +impl StaticData {
 +    pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
 +        let loc = konst.lookup(db);
 +        let item_tree = loc.id.item_tree(db);
 +        let statik = &item_tree[loc.id.value];
 +
 +        Arc::new(StaticData {
 +            name: statik.name.clone(),
 +            type_ref: statik.type_ref.clone(),
 +            visibility: item_tree[statik.visibility].clone(),
 +            mutable: statik.mutable,
 +            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
 +        })
 +    }
 +}
 +
 +struct AssocItemCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    module_id: ModuleId,
 +    def_map: Arc<DefMap>,
 +    container: ItemContainerId,
 +    expander: Expander,
 +
 +    items: Vec<(Name, AssocItemId)>,
 +    attr_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
 +}
 +
 +impl<'a> AssocItemCollector<'a> {
 +    fn new(
 +        db: &'a dyn DefDatabase,
 +        module_id: ModuleId,
 +        file_id: HirFileId,
 +        container: ItemContainerId,
 +    ) -> Self {
 +        Self {
 +            db,
 +            module_id,
 +            def_map: module_id.def_map(db),
 +            container,
 +            expander: Expander::new(db, file_id, module_id),
 +            items: Vec::new(),
 +            attr_calls: Vec::new(),
 +        }
 +    }
 +
 +    fn finish(
 +        self,
 +    ) -> (Vec<(Name, AssocItemId)>, Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>) {
 +        (
 +            self.items,
 +            if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
 +        )
 +    }
 +
 +    // FIXME: proc-macro diagnostics
 +    fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[AssocItem]) {
 +        let container = self.container;
 +        self.items.reserve(assoc_items.len());
 +
 +        'items: for &item in assoc_items {
 +            let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
 +            if !attrs.is_cfg_enabled(self.expander.cfg_options()) {
 +                continue;
 +            }
 +
 +            'attrs: for attr in &*attrs {
 +                let ast_id =
 +                    AstId::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast());
 +                let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id };
 +
 +                if let Ok(ResolvedAttr::Macro(call_id)) = self.def_map.resolve_attr_macro(
 +                    self.db,
 +                    self.module_id.local_id,
 +                    ast_id_with_path,
 +                    attr,
 +                ) {
 +                    self.attr_calls.push((ast_id, call_id));
 +                    // If proc attribute macro expansion is disabled, skip expanding it here
 +                    if !self.db.enable_proc_attr_macros() {
 +                        continue 'attrs;
 +                    }
 +                    let loc = self.db.lookup_intern_macro_call(call_id);
 +                    if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
 +                        // If there's no expander for the proc macro (e.g. the
 +                        // proc macro is ignored, or building the proc macro
 +                        // crate failed), skip expansion like we would if it was
 +                        // disabled. This is analogous to the handling in
 +                        // `DefCollector::collect_macros`.
 +                        if exp.is_dummy() {
 +                            continue 'attrs;
 +                        }
 +                    }
 +                    match self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id) {
 +                        ExpandResult { value: Some((mark, _)), .. } => {
 +                            self.collect_macro_items(mark);
 +                            continue 'items;
 +                        }
 +                        ExpandResult { .. } => {}
 +                    }
 +                }
 +            }
 +
 +            match item {
 +                AssocItem::Function(id) => {
 +                    let item = &item_tree[id];
 +
 +                    let def =
 +                        FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
 +                    self.items.push((item.name.clone(), def.into()));
 +                }
 +                AssocItem::Const(id) => {
 +                    let item = &item_tree[id];
 +
 +                    let name = match item.name.clone() {
 +                        Some(name) => name,
 +                        None => continue,
 +                    };
 +                    let def =
 +                        ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
 +                    self.items.push((name, def.into()));
 +                }
 +                AssocItem::TypeAlias(id) => {
 +                    let item = &item_tree[id];
 +
 +                    let def = TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }
 +                        .intern(self.db);
 +                    self.items.push((item.name.clone(), def.into()));
 +                }
 +                AssocItem::MacroCall(call) => {
 +                    if let Some(root) = self.db.parse_or_expand(self.expander.current_file_id()) {
 +                        let call = &item_tree[call];
 +
 +                        let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
 +                        let call = ast_id_map.get(call.ast_id).to_node(&root);
 +                        let _cx = stdx::panic_context::enter(format!(
 +                            "collect_items MacroCall: {}",
 +                            call
 +                        ));
 +                        let res = self.expander.enter_expand::<ast::MacroItems>(self.db, call);
 +
 +                        if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res {
 +                            self.collect_macro_items(mark);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn collect_macro_items(&mut self, mark: Mark) {
 +        let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
 +        let item_tree = tree_id.item_tree(self.db);
 +        let iter: SmallVec<[_; 2]> =
 +            item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item).collect();
 +
 +        self.collect(&item_tree, tree_id, &iter);
 +
 +        self.expander.exit(self.db, mark);
 +    }
 +}
index a991365d6bf4906fd532b2154710094669835d9e,0000000000000000000000000000000000000000..c1b3788acb7d36d97a53272df8228458b139270e
mode 100644,000000..100644
--- /dev/null
@@@ -1,440 -1,0 +1,444 @@@
-     ElementList(Box<[ExprId]>),
 +//! This module describes hir-level representation of expressions.
 +//!
 +//! This representation is:
 +//!
 +//! 1. Identity-based. Each expression has an `id`, so we can distinguish
 +//!    between different `1` in `1 + 1`.
 +//! 2. Independent of syntax. Though syntactic provenance information can be
 +//!    attached separately via id-based side map.
 +//! 3. Unresolved. Paths are stored as sequences of names, and not as defs the
 +//!    names refer to.
 +//! 4. Desugared. There's no `if let`.
 +//!
 +//! See also a neighboring `body` module.
 +
 +use hir_expand::name::Name;
 +use la_arena::{Idx, RawIdx};
 +
 +use crate::{
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    intern::Interned,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    BlockId,
 +};
 +
 +pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp};
 +
 +pub type ExprId = Idx<Expr>;
 +
 +/// FIXME: this is a hacky function which should be removed
 +pub(crate) fn dummy_expr_id() -> ExprId {
 +    ExprId::from_raw(RawIdx::from(u32::MAX))
 +}
 +
 +pub type PatId = Idx<Pat>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct Label {
 +    pub name: Name,
 +}
 +pub type LabelId = Idx<Label>;
 +
 +// We convert float values into bits and that's how we don't need to deal with f32 and f64.
 +// For PartialEq, bits comparison should work, as ordering is not important
 +// https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
 +#[derive(Default, Debug, Clone, Eq, PartialEq)]
 +pub struct FloatTypeWrapper(u64);
 +
 +impl FloatTypeWrapper {
 +    pub fn new(value: f64) -> Self {
 +        Self(value.to_bits())
 +    }
 +}
 +
 +impl std::fmt::Display for FloatTypeWrapper {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{:?}", f64::from_bits(self.0))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Literal {
 +    String(Box<str>),
 +    ByteString(Box<[u8]>),
 +    Char(char),
 +    Bool(bool),
 +    Int(i128, Option<BuiltinInt>),
 +    Uint(u128, Option<BuiltinUint>),
 +    // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
 +    // could not be used directly here, to understand how the wrapper works go to definition of
 +    // FloatTypeWrapper
 +    Float(FloatTypeWrapper, Option<BuiltinFloat>),
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Expr {
 +    /// This is produced if the syntax tree does not have a required expression piece.
 +    Missing,
 +    Path(Path),
 +    If {
 +        condition: ExprId,
 +        then_branch: ExprId,
 +        else_branch: Option<ExprId>,
 +    },
 +    Let {
 +        pat: PatId,
 +        expr: ExprId,
 +    },
 +    Block {
 +        id: BlockId,
 +        statements: Box<[Statement]>,
 +        tail: Option<ExprId>,
 +        label: Option<LabelId>,
 +    },
 +    Loop {
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    While {
 +        condition: ExprId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    For {
 +        iterable: ExprId,
 +        pat: PatId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    Call {
 +        callee: ExprId,
 +        args: Box<[ExprId]>,
++        is_assignee_expr: bool,
 +    },
 +    MethodCall {
 +        receiver: ExprId,
 +        method_name: Name,
 +        args: Box<[ExprId]>,
 +        generic_args: Option<Box<GenericArgs>>,
 +    },
 +    Match {
 +        expr: ExprId,
 +        arms: Box<[MatchArm]>,
 +    },
 +    Continue {
 +        label: Option<Name>,
 +    },
 +    Break {
 +        expr: Option<ExprId>,
 +        label: Option<Name>,
 +    },
 +    Return {
 +        expr: Option<ExprId>,
 +    },
 +    Yield {
 +        expr: Option<ExprId>,
 +    },
 +    RecordLit {
 +        path: Option<Box<Path>>,
 +        fields: Box<[RecordLitField]>,
 +        spread: Option<ExprId>,
++        ellipsis: bool,
++        is_assignee_expr: bool,
 +    },
 +    Field {
 +        expr: ExprId,
 +        name: Name,
 +    },
 +    Await {
 +        expr: ExprId,
 +    },
 +    Try {
 +        expr: ExprId,
 +    },
 +    TryBlock {
 +        body: ExprId,
 +    },
 +    Async {
 +        body: ExprId,
 +    },
 +    Const {
 +        body: ExprId,
 +    },
 +    Cast {
 +        expr: ExprId,
 +        type_ref: Interned<TypeRef>,
 +    },
 +    Ref {
 +        expr: ExprId,
 +        rawness: Rawness,
 +        mutability: Mutability,
 +    },
 +    Box {
 +        expr: ExprId,
 +    },
 +    UnaryOp {
 +        expr: ExprId,
 +        op: UnaryOp,
 +    },
 +    BinaryOp {
 +        lhs: ExprId,
 +        rhs: ExprId,
 +        op: Option<BinaryOp>,
 +    },
 +    Range {
 +        lhs: Option<ExprId>,
 +        rhs: Option<ExprId>,
 +        range_type: RangeOp,
 +    },
 +    Index {
 +        base: ExprId,
 +        index: ExprId,
 +    },
 +    Closure {
 +        args: Box<[PatId]>,
 +        arg_types: Box<[Option<Interned<TypeRef>>]>,
 +        ret_type: Option<Interned<TypeRef>>,
 +        body: ExprId,
 +    },
 +    Tuple {
 +        exprs: Box<[ExprId]>,
++        is_assignee_expr: bool,
 +    },
 +    Unsafe {
 +        body: ExprId,
 +    },
 +    MacroStmts {
 +        statements: Box<[Statement]>,
 +        tail: Option<ExprId>,
 +    },
 +    Array(Array),
 +    Literal(Literal),
 +    Underscore,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Array {
-             Expr::Call { callee, args } => {
++    ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
 +    Repeat { initializer: ExprId, repeat: ExprId },
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MatchArm {
 +    pub pat: PatId,
 +    pub guard: Option<ExprId>,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordLitField {
 +    pub name: Name,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Statement {
 +    Let {
 +        pat: PatId,
 +        type_ref: Option<Interned<TypeRef>>,
 +        initializer: Option<ExprId>,
 +        else_branch: Option<ExprId>,
 +    },
 +    Expr {
 +        expr: ExprId,
 +        has_semi: bool,
 +    },
 +}
 +
 +impl Expr {
 +    pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
 +        match self {
 +            Expr::Missing => {}
 +            Expr::Path(_) => {}
 +            Expr::If { condition, then_branch, else_branch } => {
 +                f(*condition);
 +                f(*then_branch);
 +                if let &Some(else_branch) = else_branch {
 +                    f(else_branch);
 +                }
 +            }
 +            Expr::Let { expr, .. } => {
 +                f(*expr);
 +            }
 +            Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
 +                for stmt in statements.iter() {
 +                    match stmt {
 +                        Statement::Let { initializer, .. } => {
 +                            if let &Some(expr) = initializer {
 +                                f(expr);
 +                            }
 +                        }
 +                        Statement::Expr { expr: expression, .. } => f(*expression),
 +                    }
 +                }
 +                if let &Some(expr) = tail {
 +                    f(expr);
 +                }
 +            }
 +            Expr::TryBlock { body }
 +            | Expr::Unsafe { body }
 +            | Expr::Async { body }
 +            | Expr::Const { body } => f(*body),
 +            Expr::Loop { body, .. } => f(*body),
 +            Expr::While { condition, body, .. } => {
 +                f(*condition);
 +                f(*body);
 +            }
 +            Expr::For { iterable, body, .. } => {
 +                f(*iterable);
 +                f(*body);
 +            }
-             Expr::Tuple { exprs } => exprs.iter().copied().for_each(f),
++            Expr::Call { callee, args, .. } => {
 +                f(*callee);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::MethodCall { receiver, args, .. } => {
 +                f(*receiver);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::Match { expr, arms } => {
 +                f(*expr);
 +                arms.iter().map(|arm| arm.expr).for_each(f);
 +            }
 +            Expr::Continue { .. } => {}
 +            Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
 +                if let &Some(expr) = expr {
 +                    f(expr);
 +                }
 +            }
 +            Expr::RecordLit { fields, spread, .. } => {
 +                for field in fields.iter() {
 +                    f(field.expr);
 +                }
 +                if let &Some(expr) = spread {
 +                    f(expr);
 +                }
 +            }
 +            Expr::Closure { body, .. } => {
 +                f(*body);
 +            }
 +            Expr::BinaryOp { lhs, rhs, .. } => {
 +                f(*lhs);
 +                f(*rhs);
 +            }
 +            Expr::Range { lhs, rhs, .. } => {
 +                if let &Some(lhs) = rhs {
 +                    f(lhs);
 +                }
 +                if let &Some(rhs) = lhs {
 +                    f(rhs);
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                f(*base);
 +                f(*index);
 +            }
 +            Expr::Field { expr, .. }
 +            | Expr::Await { expr }
 +            | Expr::Try { expr }
 +            | Expr::Cast { expr, .. }
 +            | Expr::Ref { expr, .. }
 +            | Expr::UnaryOp { expr, .. }
 +            | Expr::Box { expr } => {
 +                f(*expr);
 +            }
-                 Array::ElementList(exprs) => exprs.iter().copied().for_each(f),
++            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
 +            Expr::Array(a) => match a {
++                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
 +                Array::Repeat { initializer, repeat } => {
 +                    f(*initializer);
 +                    f(*repeat)
 +                }
 +            },
 +            Expr::Literal(_) => {}
 +            Expr::Underscore => {}
 +        }
 +    }
 +}
 +
 +/// Explicit binding annotations given in the HIR for a binding. Note
 +/// that this is not the final binding *mode* that we infer after type
 +/// inference.
 +#[derive(Clone, PartialEq, Eq, Debug, Copy)]
 +pub enum BindingAnnotation {
 +    /// No binding annotation given: this means that the final binding mode
 +    /// will depend on whether we have skipped through a `&` reference
 +    /// when matching. For example, the `x` in `Some(x)` will have binding
 +    /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
 +    /// ultimately be inferred to be by-reference.
 +    Unannotated,
 +
 +    /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
 +    Mutable,
 +
 +    /// Annotated as `ref`, like `ref x`
 +    Ref,
 +
 +    /// Annotated as `ref mut x`.
 +    RefMut,
 +}
 +
 +impl BindingAnnotation {
 +    pub fn new(is_mutable: bool, is_ref: bool) -> Self {
 +        match (is_mutable, is_ref) {
 +            (true, true) => BindingAnnotation::RefMut,
 +            (false, true) => BindingAnnotation::Ref,
 +            (true, false) => BindingAnnotation::Mutable,
 +            (false, false) => BindingAnnotation::Unannotated,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordFieldPat {
 +    pub name: Name,
 +    pub pat: PatId,
 +}
 +
 +/// Close relative to rustc's hir::PatKind
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Pat {
 +    Missing,
 +    Wild,
 +    Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Or(Box<[PatId]>),
 +    Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
 +    Range { start: ExprId, end: ExprId },
 +    Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
 +    Path(Box<Path>),
 +    Lit(ExprId),
 +    Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
 +    TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Ref { pat: PatId, mutability: Mutability },
 +    Box { inner: PatId },
 +    ConstBlock(ExprId),
 +}
 +
 +impl Pat {
 +    pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
 +        match self {
 +            Pat::Range { .. }
 +            | Pat::Lit(..)
 +            | Pat::Path(..)
 +            | Pat::ConstBlock(..)
 +            | Pat::Wild
 +            | Pat::Missing => {}
 +            Pat::Bind { subpat, .. } => {
 +                subpat.iter().copied().for_each(f);
 +            }
 +            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
 +                args.iter().copied().for_each(f);
 +            }
 +            Pat::Ref { pat, .. } => f(*pat),
 +            Pat::Slice { prefix, slice, suffix } => {
 +                let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
 +                total_iter.copied().for_each(f);
 +            }
 +            Pat::Record { args, .. } => {
 +                args.iter().map(|f| f.pat).for_each(f);
 +            }
 +            Pat::Box { inner } => f(*inner),
 +        }
 +    }
 +}
index b98b2855cb084848aed44860d8a784bdad59ca6a,0000000000000000000000000000000000000000..579f803ea193ac94b3f4f998955e9cbf5a44ccc2
mode 100644,000000..100644
--- /dev/null
@@@ -1,449 -1,0 +1,464 @@@
-     derive_macros: FxHashMap<
-         AstId<ast::Adt>,
-         SmallVec<[(AttrId, MacroCallId, SmallVec<[Option<MacroCallId>; 1]>); 1]>,
-     >,
 +//! 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 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,
 +};
 +
 +#[derive(Copy, Clone)]
 +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.
-         attr_id: AttrId,
++    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
 +        let keys: FxHashSet<_> = self
 +            .types
 +            .keys()
 +            .chain(self.values.keys())
 +            .chain(self.macros.keys())
 +            .chain(self.unresolved.iter())
 +            .collect();
 +
 +        keys.into_iter().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,
-             if let Some((.., invocs)) = derives.iter_mut().find(|&&mut (id, ..)| id == attr_id) {
-                 invocs[idx] = Some(call);
++        id: AttrId,
 +        idx: usize,
 +    ) {
 +        if let Some(derives) = self.derive_macros.get_mut(&adt) {
-         call_id: MacroCallId,
++            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,
-         self.derive_macros.entry(adt).or_default().push((attr_id, call_id, smallvec![None; len]));
++        attr_call_id: MacroCallId,
 +        len: usize,
 +    ) {
-             (*k, v.iter().map(|&(attr_id, call_id, ref invocs)| (attr_id, call_id, &**invocs)))
++        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)
 +                            if $glob_imports.$field.contains(&$lookup)
 +                                && matches!($def_import_type, ImportType::Named) =>
 +                        {
 +                            cov_mark::hit!(import_shadowed);
 +                            $glob_imports.$field.remove(&$lookup);
 +                            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(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate),
 +        }
 +    }
 +}
index 0dd0a5861ef3cfe7b46f6a916284fbc5577069ba,0000000000000000000000000000000000000000..56603f4b154569f471e80fe6cfa807f4b13afab3
mode 100644,000000..100644
--- /dev/null
@@@ -1,980 -1,0 +1,980 @@@
-     resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
- ) -> Result<MacroCallId, UnresolvedMacro> {
-     let def: MacroDefId = resolver(item_attr.path.clone())
 +//! `hir_def` crate contains everything between macro expansion and type
 +//! inference.
 +//!
 +//! It defines various items (structs, enums, traits) which comprises Rust code,
 +//! as well as an algorithm for resolving paths to such entities.
 +//!
 +//! Note that `hir_def` is a work in progress, so not all of the above is
 +//! actually true.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +pub mod db;
 +
 +pub mod attr;
 +pub mod path;
 +pub mod type_ref;
 +pub mod builtin_type;
 +pub mod builtin_attr;
 +pub mod per_ns;
 +pub mod item_scope;
 +
 +pub mod dyn_map;
 +pub mod keys;
 +
 +pub mod item_tree;
 +pub mod intern;
 +
 +pub mod adt;
 +pub mod data;
 +pub mod generics;
 +pub mod lang_item;
 +
 +pub mod expr;
 +pub mod body;
 +pub mod resolver;
 +
 +mod trace;
 +pub mod nameres;
 +
 +pub mod src;
 +pub mod child_by_source;
 +
 +pub mod visibility;
 +pub mod find_path;
 +pub mod import_map;
 +
 +#[cfg(test)]
 +mod test_db;
 +#[cfg(test)]
 +mod macro_expansion_tests;
 +
 +use std::{
 +    hash::{Hash, Hasher},
 +    sync::Arc,
 +};
 +
 +use attr::Attr;
 +use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind};
 +use hir_expand::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::BuiltinAttrExpander,
 +    builtin_derive_macro::BuiltinDeriveExpander,
 +    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 +    eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
 +    hygiene::Hygiene,
 +    proc_macro::ProcMacroExpander,
 +    AstId, ExpandError, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
 +    MacroDefKind, UnresolvedMacro,
 +};
 +use item_tree::ExternBlock;
 +use la_arena::Idx;
 +use nameres::DefMap;
 +use stdx::impl_from;
 +use syntax::ast;
 +
 +use crate::{
 +    adt::VariantData,
 +    attr::AttrId,
 +    builtin_type::BuiltinType,
 +    item_tree::{
 +        Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem,
 +        Static, Struct, Trait, TypeAlias, Union,
 +    },
 +};
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ModuleId {
 +    krate: CrateId,
 +    /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
 +    /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
 +    /// `DefMap` of `krate`.
 +    block: Option<BlockId>,
 +    /// The module's ID in its originating `DefMap`.
 +    pub local_id: LocalModuleId,
 +}
 +
 +impl ModuleId {
 +    pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
 +        match self.block {
 +            Some(block) => {
 +                db.block_def_map(block).unwrap_or_else(|| {
 +                    // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s,
 +                    // so the `DefMap` here must exist.
 +                    unreachable!("no `block_def_map` for `ModuleId` {:?}", self);
 +                })
 +            }
 +            None => db.crate_def_map(self.krate),
 +        }
 +    }
 +
 +    pub fn krate(&self) -> CrateId {
 +        self.krate
 +    }
 +
 +    pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
 +        self.def_map(db).containing_module(self.local_id)
 +    }
 +
 +    pub fn containing_block(&self) -> Option<BlockId> {
 +        self.block
 +    }
 +}
 +
 +/// An ID of a module, **local** to a specific crate
 +pub type LocalModuleId = Idx<nameres::ModuleData>;
 +
 +#[derive(Debug)]
 +pub struct ItemLoc<N: ItemTreeNode> {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<N>,
 +}
 +
 +impl<N: ItemTreeNode> Clone for ItemLoc<N> {
 +    fn clone(&self) -> Self {
 +        Self { container: self.container, id: self.id }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.container == other.container && self.id == other.id
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.container.hash(state);
 +        self.id.hash(state);
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct AssocItemLoc<N: ItemTreeNode> {
 +    pub container: ItemContainerId,
 +    pub id: ItemTreeId<N>,
 +}
 +
 +impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
 +    fn clone(&self) -> Self {
 +        Self { container: self.container, id: self.id }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.container == other.container && self.id == other.id
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.container.hash(state);
 +        self.id.hash(state);
 +    }
 +}
 +
 +macro_rules! impl_intern {
 +    ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
 +        impl_intern_key!($id);
 +
 +        impl Intern for $loc {
 +            type ID = $id;
 +            fn intern(self, db: &dyn db::DefDatabase) -> $id {
 +                db.$intern(self)
 +            }
 +        }
 +
 +        impl Lookup for $id {
 +            type Data = $loc;
 +            fn lookup(&self, db: &dyn db::DefDatabase) -> $loc {
 +                db.$lookup(*self)
 +            }
 +        }
 +    };
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct FunctionId(salsa::InternId);
 +type FunctionLoc = AssocItemLoc<Function>;
 +impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct StructId(salsa::InternId);
 +type StructLoc = ItemLoc<Struct>;
 +impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct UnionId(salsa::InternId);
 +pub type UnionLoc = ItemLoc<Union>;
 +impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct EnumId(salsa::InternId);
 +pub type EnumLoc = ItemLoc<Enum>;
 +impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
 +
 +// FIXME: rename to `VariantId`, only enums can ave variants
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct EnumVariantId {
 +    pub parent: EnumId,
 +    pub local_id: LocalEnumVariantId,
 +}
 +
 +pub type LocalEnumVariantId = Idx<adt::EnumVariantData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct FieldId {
 +    pub parent: VariantId,
 +    pub local_id: LocalFieldId,
 +}
 +
 +pub type LocalFieldId = Idx<adt::FieldData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ConstId(salsa::InternId);
 +type ConstLoc = AssocItemLoc<Const>;
 +impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct StaticId(salsa::InternId);
 +pub type StaticLoc = AssocItemLoc<Static>;
 +impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TraitId(salsa::InternId);
 +pub type TraitLoc = ItemLoc<Trait>;
 +impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAliasId(salsa::InternId);
 +type TypeAliasLoc = AssocItemLoc<TypeAlias>;
 +impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ImplId(salsa::InternId);
 +type ImplLoc = ItemLoc<Impl>;
 +impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ExternBlockId(salsa::InternId);
 +type ExternBlockLoc = ItemLoc<ExternBlock>;
 +impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroExpander {
 +    Declarative,
 +    BuiltIn(BuiltinFnLikeExpander),
 +    BuiltInAttr(BuiltinAttrExpander),
 +    BuiltInDerive(BuiltinDeriveExpander),
 +    BuiltInEager(EagerExpander),
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct Macro2Id(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro2Loc {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<MacroDef>,
 +    pub expander: MacroExpander,
 +}
 +impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct MacroRulesId(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroRulesLoc {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<MacroRules>,
 +    pub local_inner: bool,
 +    pub expander: MacroExpander,
 +}
 +impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macro_rules);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ProcMacroId(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ProcMacroLoc {
 +    // FIXME: this should be a crate? or just a crate-root module
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<Function>,
 +    pub expander: ProcMacroExpander,
 +    pub kind: ProcMacroKind,
 +}
 +impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct BlockId(salsa::InternId);
 +#[derive(Debug, Hash, PartialEq, Eq, Clone)]
 +pub struct BlockLoc {
 +    ast_id: AstId<ast::BlockExpr>,
 +    /// The containing module.
 +    module: ModuleId,
 +}
 +impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParamId {
 +    pub parent: GenericDefId,
 +    pub local_id: LocalTypeOrConstParamId,
 +}
 +
 +/// A TypeOrConstParamId with an invariant that it actually belongs to a type
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeParamId(TypeOrConstParamId);
 +
 +impl TypeParamId {
 +    pub fn parent(&self) -> GenericDefId {
 +        self.0.parent
 +    }
 +    pub fn local_id(&self) -> LocalTypeOrConstParamId {
 +        self.0.local_id
 +    }
 +}
 +
 +impl TypeParamId {
 +    /// Caller should check if this toc id really belongs to a type
 +    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
 +        Self(x)
 +    }
 +}
 +
 +impl From<TypeParamId> for TypeOrConstParamId {
 +    fn from(x: TypeParamId) -> Self {
 +        x.0
 +    }
 +}
 +
 +/// A TypeOrConstParamId with an invariant that it actually belongs to a const
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ConstParamId(TypeOrConstParamId);
 +
 +impl ConstParamId {
 +    pub fn parent(&self) -> GenericDefId {
 +        self.0.parent
 +    }
 +    pub fn local_id(&self) -> LocalTypeOrConstParamId {
 +        self.0.local_id
 +    }
 +}
 +
 +impl ConstParamId {
 +    /// Caller should check if this toc id really belongs to a const
 +    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
 +        Self(x)
 +    }
 +}
 +
 +impl From<ConstParamId> for TypeOrConstParamId {
 +    fn from(x: ConstParamId) -> Self {
 +        x.0
 +    }
 +}
 +
 +pub type LocalTypeOrConstParamId = Idx<generics::TypeOrConstParamData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct LifetimeParamId {
 +    pub parent: GenericDefId,
 +    pub local_id: LocalLifetimeParamId,
 +}
 +pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ItemContainerId {
 +    ExternBlockId(ExternBlockId),
 +    ModuleId(ModuleId),
 +    ImplId(ImplId),
 +    TraitId(TraitId),
 +}
 +impl_from!(ModuleId for ItemContainerId);
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum AdtId {
 +    StructId(StructId),
 +    UnionId(UnionId),
 +    EnumId(EnumId),
 +}
 +impl_from!(StructId, UnionId, EnumId for AdtId);
 +
 +/// A macro
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum MacroId {
 +    Macro2Id(Macro2Id),
 +    MacroRulesId(MacroRulesId),
 +    ProcMacroId(ProcMacroId),
 +}
 +impl_from!(Macro2Id, MacroRulesId, ProcMacroId for MacroId);
 +
 +impl MacroId {
 +    pub fn is_attribute(self, db: &dyn db::DefDatabase) -> bool {
 +        match self {
 +            MacroId::ProcMacroId(it) => it.lookup(db).kind == ProcMacroKind::Attr,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +/// A generic param
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParamId {
 +    TypeParamId(TypeParamId),
 +    ConstParamId(ConstParamId),
 +    LifetimeParamId(LifetimeParamId),
 +}
 +impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId);
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDefId {
 +    ModuleId(ModuleId),
 +    FunctionId(FunctionId),
 +    AdtId(AdtId),
 +    // Can't be directly declared, but can be imported.
 +    EnumVariantId(EnumVariantId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    BuiltinType(BuiltinType),
 +    MacroId(MacroId),
 +}
 +impl_from!(
 +    MacroId(Macro2Id, MacroRulesId, ProcMacroId),
 +    ModuleId,
 +    FunctionId,
 +    AdtId(StructId, EnumId, UnionId),
 +    EnumVariantId,
 +    ConstId,
 +    StaticId,
 +    TraitId,
 +    TypeAliasId,
 +    BuiltinType
 +    for ModuleDefId
 +);
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBodyId {
 +    FunctionId(FunctionId),
 +    StaticId(StaticId),
 +    ConstId(ConstId),
 +}
 +
 +impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
 +
 +impl DefWithBodyId {
 +    pub fn as_generic_def_id(self) -> Option<GenericDefId> {
 +        match self {
 +            DefWithBodyId::FunctionId(f) => Some(f.into()),
 +            DefWithBodyId::StaticId(_) => None,
 +            DefWithBodyId::ConstId(c) => Some(c.into()),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItemId {
 +    FunctionId(FunctionId),
 +    ConstId(ConstId),
 +    TypeAliasId(TypeAliasId),
 +}
 +// FIXME: not every function, ... is actually an assoc item. maybe we should make
 +// sure that you can only turn actual assoc items into AssocItemIds. This would
 +// require not implementing From, and instead having some checked way of
 +// casting them, and somehow making the constructors private, which would be annoying.
 +impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDefId {
 +    FunctionId(FunctionId),
 +    AdtId(AdtId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    ImplId(ImplId),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    EnumVariantId(EnumVariantId),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    ConstId(ConstId),
 +}
 +impl_from!(
 +    FunctionId,
 +    AdtId(StructId, EnumId, UnionId),
 +    TraitId,
 +    TypeAliasId,
 +    ImplId,
 +    EnumVariantId,
 +    ConstId
 +    for GenericDefId
 +);
 +
 +impl From<AssocItemId> for GenericDefId {
 +    fn from(item: AssocItemId) -> Self {
 +        match item {
 +            AssocItemId::FunctionId(f) => f.into(),
 +            AssocItemId::ConstId(c) => c.into(),
 +            AssocItemId::TypeAliasId(t) => t.into(),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AttrDefId {
 +    ModuleId(ModuleId),
 +    FieldId(FieldId),
 +    AdtId(AdtId),
 +    FunctionId(FunctionId),
 +    EnumVariantId(EnumVariantId),
 +    StaticId(StaticId),
 +    ConstId(ConstId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    MacroId(MacroId),
 +    ImplId(ImplId),
 +    GenericParamId(GenericParamId),
 +    ExternBlockId(ExternBlockId),
 +}
 +
 +impl_from!(
 +    ModuleId,
 +    FieldId,
 +    AdtId(StructId, EnumId, UnionId),
 +    EnumVariantId,
 +    StaticId,
 +    ConstId,
 +    FunctionId,
 +    TraitId,
 +    TypeAliasId,
 +    MacroId(Macro2Id, MacroRulesId, ProcMacroId),
 +    ImplId,
 +    GenericParamId
 +    for AttrDefId
 +);
 +
 +impl From<ItemContainerId> for AttrDefId {
 +    fn from(acid: ItemContainerId) -> Self {
 +        match acid {
 +            ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
 +            ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
 +            ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
 +            ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum VariantId {
 +    EnumVariantId(EnumVariantId),
 +    StructId(StructId),
 +    UnionId(UnionId),
 +}
 +impl_from!(EnumVariantId, StructId, UnionId for VariantId);
 +
 +impl VariantId {
 +    pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
 +            VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
 +            VariantId::EnumVariantId(it) => {
 +                db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
 +            }
 +        }
 +    }
 +
 +    pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
 +            VariantId::StructId(it) => it.lookup(db).id.file_id(),
 +            VariantId::UnionId(it) => it.lookup(db).id.file_id(),
 +        }
 +    }
 +
 +    pub fn adt_id(self) -> AdtId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.into(),
 +            VariantId::StructId(it) => it.into(),
 +            VariantId::UnionId(it) => it.into(),
 +        }
 +    }
 +}
 +
 +trait Intern {
 +    type ID;
 +    fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
 +}
 +
 +pub trait Lookup {
 +    type Data;
 +    fn lookup(&self, db: &dyn db::DefDatabase) -> Self::Data;
 +}
 +
 +pub trait HasModule {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 +}
 +
 +impl HasModule for ItemContainerId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match *self {
 +            ItemContainerId::ModuleId(it) => it,
 +            ItemContainerId::ImplId(it) => it.lookup(db).container,
 +            ItemContainerId::TraitId(it) => it.lookup(db).container,
 +            ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.container.module(db)
 +    }
 +}
 +
 +impl HasModule for AdtId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            AdtId::StructId(it) => it.lookup(db).container,
 +            AdtId::UnionId(it) => it.lookup(db).container,
 +            AdtId::EnumId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for VariantId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.lookup(db).container,
 +            VariantId::StructId(it) => it.lookup(db).container,
 +            VariantId::UnionId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for MacroId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            MacroId::MacroRulesId(it) => it.lookup(db).container,
 +            MacroId::Macro2Id(it) => it.lookup(db).container,
 +            MacroId::ProcMacroId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for DefWithBodyId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
 +            DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
 +            DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
 +        }
 +    }
 +}
 +
 +impl DefWithBodyId {
 +    pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem {
 +        match self {
 +            DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
 +            DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
 +            DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
 +        }
 +    }
 +}
 +
 +impl HasModule for GenericDefId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            GenericDefId::FunctionId(it) => it.lookup(db).module(db),
 +            GenericDefId::AdtId(it) => it.module(db),
 +            GenericDefId::TraitId(it) => it.lookup(db).container,
 +            GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
 +            GenericDefId::ImplId(it) => it.lookup(db).container,
 +            GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container,
 +            GenericDefId::ConstId(it) => it.lookup(db).module(db),
 +        }
 +    }
 +}
 +
 +impl HasModule for TypeAliasId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.lookup(db).module(db)
 +    }
 +}
 +
 +impl HasModule for TraitId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.lookup(db).container
 +    }
 +}
 +
 +impl ModuleDefId {
 +    /// Returns the module containing `self` (or `self`, if `self` is itself a module).
 +    ///
 +    /// Returns `None` if `self` refers to a primitive type.
 +    pub fn module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
 +        Some(match self {
 +            ModuleDefId::ModuleId(id) => *id,
 +            ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
 +            ModuleDefId::AdtId(id) => id.module(db),
 +            ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
 +            ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
 +            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
 +            ModuleDefId::TraitId(id) => id.lookup(db).container,
 +            ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
 +            ModuleDefId::MacroId(id) => id.module(db),
 +            ModuleDefId::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl AttrDefId {
 +    pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
 +        match self {
 +            AttrDefId::ModuleId(it) => it.krate,
 +            AttrDefId::FieldId(it) => it.parent.module(db).krate,
 +            AttrDefId::AdtId(it) => it.module(db).krate,
 +            AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.krate,
 +            AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::TraitId(it) => it.lookup(db).container.krate,
 +            AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::ImplId(it) => it.lookup(db).container.krate,
 +            AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
 +            AttrDefId::GenericParamId(it) => {
 +                match it {
 +                    GenericParamId::TypeParamId(it) => it.parent(),
 +                    GenericParamId::ConstParamId(it) => it.parent(),
 +                    GenericParamId::LifetimeParamId(it) => it.parent,
 +                }
 +                .module(db)
 +                .krate
 +            }
 +            AttrDefId::MacroId(it) => it.module(db).krate,
 +        }
 +    }
 +}
 +
 +/// A helper trait for converting to MacroCallId
 +pub trait AsMacroCall {
 +    fn as_call_id(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +    ) -> Option<MacroCallId> {
 +        self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?.ok()
 +    }
 +
 +    fn as_call_id_with_errors(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +        error_sink: &mut dyn FnMut(ExpandError),
 +    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro>;
 +}
 +
 +impl AsMacroCall for InFile<&ast::MacroCall> {
 +    fn as_call_id_with_errors(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +        mut error_sink: &mut dyn FnMut(ExpandError),
 +    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
 +        let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
 +        let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
 +        let h = Hygiene::new(db.upcast(), self.file_id);
 +        let path =
 +            self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
 +
 +        let path = match error_sink
 +            .option(path, || ExpandError::Other("malformed macro invocation".into()))
 +        {
 +            Ok(path) => path,
 +            Err(error) => {
 +                return Ok(Err(error));
 +            }
 +        };
 +
 +        macro_call_as_call_id(
 +            db,
 +            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
 +            expands_to,
 +            krate,
 +            resolver,
 +            error_sink,
 +        )
 +    }
 +}
 +
 +/// Helper wrapper for `AstId` with `ModPath`
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +struct AstIdWithPath<T: ast::AstNode> {
 +    ast_id: AstId<T>,
 +    path: path::ModPath,
 +}
 +
 +impl<T: ast::AstNode> AstIdWithPath<T> {
 +    fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
 +        AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
 +    }
 +}
 +
 +fn macro_call_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    call: &AstIdWithPath<ast::MacroCall>,
 +    expand_to: ExpandTo,
 +    krate: CrateId,
 +    resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +    error_sink: &mut dyn FnMut(ExpandError),
 +) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
 +    let def =
 +        resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
 +
 +    let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
 +        let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
 +
 +        expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver, error_sink)?
 +    } else {
 +        Ok(def.as_lazy_macro(
 +            db.upcast(),
 +            krate,
 +            MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
 +        ))
 +    };
 +    Ok(res)
 +}
 +
 +pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
 +    match id {
 +        MacroId::Macro2Id(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            let in_file = |m: FileAstId<ast::MacroDef>| InFile::new(loc.id.file_id(), m.upcast());
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: match loc.expander {
 +                    MacroExpander::Declarative => MacroDefKind::Declarative(in_file(makro.ast_id)),
 +                    MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file(makro.ast_id)),
 +                    MacroExpander::BuiltInAttr(it) => {
 +                        MacroDefKind::BuiltInAttr(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInDerive(it) => {
 +                        MacroDefKind::BuiltInDerive(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInEager(it) => {
 +                        MacroDefKind::BuiltInEager(it, in_file(makro.ast_id))
 +                    }
 +                },
 +                local_inner: false,
 +            }
 +        }
 +        MacroId::MacroRulesId(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            let in_file = |m: FileAstId<ast::MacroRules>| InFile::new(loc.id.file_id(), m.upcast());
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: match loc.expander {
 +                    MacroExpander::Declarative => MacroDefKind::Declarative(in_file(makro.ast_id)),
 +                    MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file(makro.ast_id)),
 +                    MacroExpander::BuiltInAttr(it) => {
 +                        MacroDefKind::BuiltInAttr(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInDerive(it) => {
 +                        MacroDefKind::BuiltInDerive(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInEager(it) => {
 +                        MacroDefKind::BuiltInEager(it, in_file(makro.ast_id))
 +                    }
 +                },
 +                local_inner: loc.local_inner,
 +            }
 +        }
 +        MacroId::ProcMacroId(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: MacroDefKind::ProcMacro(
 +                    loc.expander,
 +                    loc.kind,
 +                    InFile::new(loc.id.file_id(), makro.ast_id),
 +                ),
 +                local_inner: false,
 +            }
 +        }
 +    }
 +}
 +
 +fn derive_macro_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    item_attr: &AstIdWithPath<ast::Adt>,
 +    derive_attr: AttrId,
 +    derive_pos: u32,
 +    krate: CrateId,
-     let res = def.as_lazy_macro(
++    resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
++) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
++    let (macro_id, def_id) = resolver(item_attr.path.clone())
 +        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
-     Ok(res)
++    let call_id = def_id.as_lazy_macro(
 +        db.upcast(),
 +        krate,
 +        MacroCallKind::Derive {
 +            ast_id: item_attr.ast_id,
 +            derive_index: derive_pos,
 +            derive_attr_index: derive_attr.ast_index,
 +        },
 +    );
++    Ok((macro_id, def_id, call_id))
 +}
 +
 +fn attr_macro_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    item_attr: &AstIdWithPath<ast::Item>,
 +    macro_attr: &Attr,
 +    krate: CrateId,
 +    def: MacroDefId,
 +    is_derive: bool,
 +) -> MacroCallId {
 +    let mut arg = match macro_attr.input.as_deref() {
 +        Some(attr::AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()),
 +        _ => Default::default(),
 +    };
 +
 +    // The parentheses are always disposed here.
 +    arg.0.delimiter = None;
 +
 +    let res = def.as_lazy_macro(
 +        db.upcast(),
 +        krate,
 +        MacroCallKind::Attr {
 +            ast_id: item_attr.ast_id,
 +            attr_args: Arc::new(arg),
 +            invoc_attr_index: macro_attr.id.ast_index,
 +            is_derive,
 +        },
 +    );
 +    res
 +}
index 756fd583af4d60be4df94ee47737a94b6f628944,0000000000000000000000000000000000000000..6eb530ecc54209d5e2f37ea98a8012c09ac3e87a
mode 100644,000000..100644
--- /dev/null
@@@ -1,528 -1,0 +1,545 @@@
- mod collector;
 +//! This module implements import-resolution/macro expansion algorithm.
 +//!
 +//! The result of this module is `DefMap`: a data structure which contains:
 +//!
 +//!   * a tree of modules for the crate
 +//!   * for each module, a set of items visible in the module (directly declared
 +//!     or imported)
 +//!
 +//! Note that `DefMap` contains fully macro expanded code.
 +//!
 +//! Computing `DefMap` can be partitioned into several logically
 +//! independent "phases". The phases are mutually recursive though, there's no
 +//! strict ordering.
 +//!
 +//! ## Collecting RawItems
 +//!
 +//! This happens in the `raw` module, which parses a single source file into a
 +//! set of top-level items. Nested imports are desugared to flat imports in this
 +//! phase. Macro calls are represented as a triple of (Path, Option<Name>,
 +//! TokenTree).
 +//!
 +//! ## Collecting Modules
 +//!
 +//! This happens in the `collector` module. In this phase, we recursively walk
 +//! tree of modules, collect raw items from submodules, populate module scopes
 +//! with defined items (so, we assign item ids in this phase) and record the set
 +//! of unresolved imports and macros.
 +//!
 +//! While we walk tree of modules, we also record macro_rules definitions and
 +//! expand calls to macro_rules defined macros.
 +//!
 +//! ## Resolving Imports
 +//!
 +//! We maintain a list of currently unresolved imports. On every iteration, we
 +//! try to resolve some imports from this list. If the import is resolved, we
 +//! record it, by adding an item to current module scope and, if necessary, by
 +//! recursively populating glob imports.
 +//!
 +//! ## Resolving Macros
 +//!
 +//! macro_rules from the same crate use a global mutable namespace. We expand
 +//! them immediately, when we collect modules.
 +//!
 +//! Macros from other crates (including proc-macros) can be used with
 +//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of
 +//! unexpanded macros. On every iteration, we try to resolve each macro call
 +//! path and, upon success, we run macro expansion and "collect module" phase on
 +//! the result
 +
 +pub mod attr_resolution;
- mod proc_macro;
++pub mod proc_macro;
 +pub mod diagnostics;
++mod collector;
 +mod mod_resolution;
 +mod path_resolution;
- use std::{cmp::Ord, sync::Arc};
 +
 +#[cfg(test)]
 +mod tests;
 +
- use hir_expand::{name::Name, InFile, MacroDefId};
++use std::{cmp::Ord, ops::Deref, sync::Arc};
 +
 +use base_db::{CrateId, Edition, FileId};
-     AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, ModuleId, ProcMacroId,
++use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
 +use itertools::Itertools;
 +use la_arena::Arena;
 +use profile::Count;
 +use rustc_hash::FxHashMap;
 +use stdx::format_to;
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    db::DefDatabase,
 +    item_scope::{BuiltinShadowMode, ItemScope},
 +    item_tree::{ItemTreeId, Mod, TreeId},
 +    nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
 +    path::ModPath,
 +    per_ns::PerNs,
 +    visibility::Visibility,
++    AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
 +};
 +
 +/// Contains the results of (early) name resolution.
 +///
 +/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
 +/// item-level macros have been expanded.
 +///
 +/// Every crate has a primary `DefMap` whose root is the crate's main file (`main.rs`/`lib.rs`),
 +/// computed by the `crate_def_map` query. Additionally, every block expression introduces the
 +/// opportunity to write arbitrary item and module hierarchies, and thus gets its own `DefMap` that
 +/// is computed by the `block_def_map` query.
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct DefMap {
 +    _c: Count<Self>,
 +    block: Option<BlockInfo>,
 +    root: LocalModuleId,
 +    modules: Arena<ModuleData>,
 +    krate: CrateId,
 +    /// The prelude module for this crate. This either comes from an import
 +    /// marked with the `prelude_import` attribute, or (in the normal case) from
 +    /// a dependency (`std` or `core`).
 +    prelude: Option<ModuleId>,
 +    extern_prelude: FxHashMap<Name, ModuleId>,
 +
 +    /// Side table for resolving derive helpers.
 +    exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
 +    fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
 +    /// The error that occurred when failing to load the proc-macro dll.
 +    proc_macro_loading_error: Option<Box<str>>,
++    /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
++    /// attributes.
++    derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
 +
 +    /// Custom attributes registered with `#![register_attr]`.
 +    registered_attrs: Vec<SmolStr>,
 +    /// Custom tool modules registered with `#![register_tool]`.
 +    registered_tools: Vec<SmolStr>,
 +
 +    edition: Edition,
 +    recursion_limit: Option<u32>,
 +    diagnostics: Vec<DefDiagnostic>,
 +}
 +
 +/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
 +#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 +struct BlockInfo {
 +    /// The `BlockId` this `DefMap` was created from.
 +    block: BlockId,
 +    /// The containing module.
 +    parent: ModuleId,
 +}
 +
 +impl std::ops::Index<LocalModuleId> for DefMap {
 +    type Output = ModuleData;
 +    fn index(&self, id: LocalModuleId) -> &ModuleData {
 +        &self.modules[id]
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
 +pub enum ModuleOrigin {
 +    CrateRoot {
 +        definition: FileId,
 +    },
 +    /// Note that non-inline modules, by definition, live inside non-macro file.
 +    File {
 +        is_mod_rs: bool,
 +        declaration: AstId<ast::Module>,
 +        declaration_tree_id: ItemTreeId<Mod>,
 +        definition: FileId,
 +    },
 +    Inline {
 +        definition_tree_id: ItemTreeId<Mod>,
 +        definition: AstId<ast::Module>,
 +    },
 +    /// Pseudo-module introduced by a block scope (contains only inner items).
 +    BlockExpr {
 +        block: AstId<ast::BlockExpr>,
 +    },
 +}
 +
 +impl ModuleOrigin {
 +    pub fn declaration(&self) -> Option<AstId<ast::Module>> {
 +        match self {
 +            ModuleOrigin::File { declaration: module, .. }
 +            | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
 +            ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
 +        }
 +    }
 +
 +    pub fn file_id(&self) -> Option<FileId> {
 +        match self {
 +            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
 +                Some(*definition)
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn is_inline(&self) -> bool {
 +        match self {
 +            ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true,
 +            ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false,
 +        }
 +    }
 +
 +    /// Returns a node which defines this module.
 +    /// That is, a file or a `mod foo {}` with items.
 +    fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
 +        match self {
 +            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
 +                let file_id = *definition;
 +                let sf = db.parse(file_id).tree();
 +                InFile::new(file_id.into(), ModuleSource::SourceFile(sf))
 +            }
 +            ModuleOrigin::Inline { definition, .. } => InFile::new(
 +                definition.file_id,
 +                ModuleSource::Module(definition.to_node(db.upcast())),
 +            ),
 +            ModuleOrigin::BlockExpr { block } => {
 +                InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ModuleData {
 +    /// Where does this module come from?
 +    pub origin: ModuleOrigin,
 +    /// Declared visibility of this module.
 +    pub visibility: Visibility,
 +
 +    pub parent: Option<LocalModuleId>,
 +    pub children: FxHashMap<Name, LocalModuleId>,
 +    pub scope: ItemScope,
 +}
 +
 +impl DefMap {
 +    pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
 +        let _p = profile::span("crate_def_map_query").detail(|| {
 +            db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string()
 +        });
 +
 +        let crate_graph = db.crate_graph();
 +
 +        let edition = crate_graph[krate].edition;
 +        let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id };
 +        let def_map = DefMap::empty(krate, edition, ModuleData::new(origin, Visibility::Public));
 +        let def_map = collector::collect_defs(
 +            db,
 +            def_map,
 +            TreeId::new(crate_graph[krate].root_file_id.into(), None),
 +        );
 +
 +        Arc::new(def_map)
 +    }
 +
 +    pub(crate) fn block_def_map_query(
 +        db: &dyn DefDatabase,
 +        block_id: BlockId,
 +    ) -> Option<Arc<DefMap>> {
 +        let block: BlockLoc = db.lookup_intern_block(block_id);
 +
 +        let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
 +        let item_tree = tree_id.item_tree(db);
 +        if item_tree.top_level_items().is_empty() {
 +            return None;
 +        }
 +
 +        let parent_map = block.module.def_map(db);
 +        let krate = block.module.krate;
 +        let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0));
 +        // NB: we use `None` as block here, which would be wrong for implicit
 +        // modules declared by blocks with items. At the moment, we don't use
 +        // this visibility for anything outside IDE, so that's probably OK.
 +        let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
 +        let module_data =
 +            ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
 +
 +        let mut def_map = DefMap::empty(krate, parent_map.edition, module_data);
 +        def_map.block = Some(BlockInfo { block: block_id, parent: block.module });
 +
 +        let def_map = collector::collect_defs(db, def_map, tree_id);
 +        Some(Arc::new(def_map))
 +    }
 +
 +    fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
 +        let mut modules: Arena<ModuleData> = Arena::default();
 +        let root = modules.alloc(module_data);
 +
 +        DefMap {
 +            _c: Count::new(),
 +            block: None,
 +            krate,
 +            edition,
 +            recursion_limit: None,
 +            extern_prelude: FxHashMap::default(),
 +            exported_derives: FxHashMap::default(),
 +            fn_proc_macro_mapping: FxHashMap::default(),
 +            proc_macro_loading_error: None,
++            derive_helpers_in_scope: FxHashMap::default(),
 +            prelude: None,
 +            root,
 +            modules,
 +            registered_attrs: Vec::new(),
 +            registered_tools: Vec::new(),
 +            diagnostics: Vec::new(),
 +        }
 +    }
 +
 +    pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
 +        self.modules
 +            .iter()
 +            .filter(move |(_id, data)| data.origin.file_id() == Some(file_id))
 +            .map(|(id, _data)| id)
 +    }
 +
 +    pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
 +        self.modules.iter()
 +    }
++
++    pub fn derive_helpers_in_scope(
++        &self,
++        id: AstId<ast::Adt>,
++    ) -> Option<&[(Name, MacroId, MacroCallId)]> {
++        self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
++    }
++
 +    pub fn registered_tools(&self) -> &[SmolStr] {
 +        &self.registered_tools
 +    }
++
 +    pub fn registered_attrs(&self) -> &[SmolStr] {
 +        &self.registered_attrs
 +    }
++
 +    pub fn root(&self) -> LocalModuleId {
 +        self.root
 +    }
 +
 +    pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
 +        self.fn_proc_macro_mapping.get(&id).copied()
 +    }
++
 +    pub fn proc_macro_loading_error(&self) -> Option<&str> {
 +        self.proc_macro_loading_error.as_deref()
 +    }
 +
 +    pub(crate) fn krate(&self) -> CrateId {
 +        self.krate
 +    }
 +
 +    pub(crate) fn block_id(&self) -> Option<BlockId> {
 +        self.block.as_ref().map(|block| block.block)
 +    }
 +
 +    pub(crate) fn prelude(&self) -> Option<ModuleId> {
 +        self.prelude
 +    }
 +
 +    pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleId)> + '_ {
 +        self.extern_prelude.iter()
 +    }
 +
 +    pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
 +        let block = self.block.as_ref().map(|b| b.block);
 +        ModuleId { krate: self.krate, local_id, block }
 +    }
 +
 +    pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
 +        self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
 +            if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None }
 +        })
 +        .expect("DefMap chain without root")
 +    }
 +
 +    pub(crate) fn resolve_path(
 +        &self,
 +        db: &dyn DefDatabase,
 +        original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> (PerNs, Option<usize>) {
 +        let res =
 +            self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
 +        (res.resolved_def, res.segment_index)
 +    }
 +
 +    pub(crate) fn resolve_path_locally(
 +        &self,
 +        db: &dyn DefDatabase,
 +        original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> (PerNs, Option<usize>) {
 +        let res = self.resolve_path_fp_with_macro_single(
 +            db,
 +            ResolveMode::Other,
 +            original_module,
 +            path,
 +            shadow,
 +        );
 +        (res.resolved_def, res.segment_index)
 +    }
 +
 +    /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
 +    ///
 +    /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
 +    /// `None`, iteration continues.
 +    pub fn with_ancestor_maps<T>(
 +        &self,
 +        db: &dyn DefDatabase,
 +        local_mod: LocalModuleId,
 +        f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
 +    ) -> Option<T> {
 +        if let Some(it) = f(self, local_mod) {
 +            return Some(it);
 +        }
 +        let mut block = self.block;
 +        while let Some(block_info) = block {
 +            let parent = block_info.parent.def_map(db);
 +            if let Some(it) = f(&parent, block_info.parent.local_id) {
 +                return Some(it);
 +            }
 +            block = parent.block;
 +        }
 +
 +        None
 +    }
 +
 +    /// If this `DefMap` is for a block expression, returns the module containing the block (which
 +    /// might again be a block, or a module inside a block).
 +    pub fn parent(&self) -> Option<ModuleId> {
 +        Some(self.block?.parent)
 +    }
 +
 +    /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
 +    /// the block, if `self` corresponds to a block expression.
 +    pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
 +        match &self[local_mod].parent {
 +            Some(parent) => Some(self.module_id(*parent)),
 +            None => self.block.as_ref().map(|block| block.parent),
 +        }
 +    }
 +
 +    // FIXME: this can use some more human-readable format (ideally, an IR
 +    // even), as this should be a great debugging aid.
 +    pub fn dump(&self, db: &dyn DefDatabase) -> String {
 +        let mut buf = String::new();
 +        let mut arc;
 +        let mut current_map = self;
 +        while let Some(block) = &current_map.block {
 +            go(&mut buf, current_map, "block scope", current_map.root);
 +            buf.push('\n');
 +            arc = block.parent.def_map(db);
 +            current_map = &*arc;
 +        }
 +        go(&mut buf, current_map, "crate", current_map.root);
 +        return buf;
 +
 +        fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) {
 +            format_to!(buf, "{}\n", path);
 +
 +            map.modules[module].scope.dump(buf);
 +
 +            for (name, child) in
 +                map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
 +            {
 +                let path = format!("{}::{}", path, name);
 +                buf.push('\n');
 +                go(buf, map, &path, *child);
 +            }
 +        }
 +    }
 +
 +    pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
 +        let mut buf = String::new();
 +        let mut arc;
 +        let mut current_map = self;
 +        while let Some(block) = &current_map.block {
 +            format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
 +            arc = block.parent.def_map(db);
 +            current_map = &*arc;
 +        }
 +
 +        format_to!(buf, "crate scope\n");
 +        buf
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        // Exhaustive match to require handling new fields.
 +        let Self {
 +            _c: _,
 +            exported_derives,
 +            extern_prelude,
 +            diagnostics,
 +            modules,
 +            registered_attrs,
 +            registered_tools,
 +            fn_proc_macro_mapping,
++            derive_helpers_in_scope,
 +            proc_macro_loading_error: _,
 +            block: _,
 +            edition: _,
 +            recursion_limit: _,
 +            krate: _,
 +            prelude: _,
 +            root: _,
 +        } = self;
 +
 +        extern_prelude.shrink_to_fit();
 +        exported_derives.shrink_to_fit();
 +        diagnostics.shrink_to_fit();
 +        modules.shrink_to_fit();
 +        registered_attrs.shrink_to_fit();
 +        registered_tools.shrink_to_fit();
 +        fn_proc_macro_mapping.shrink_to_fit();
++        derive_helpers_in_scope.shrink_to_fit();
 +        for (_, module) in modules.iter_mut() {
 +            module.children.shrink_to_fit();
 +            module.scope.shrink_to_fit();
 +        }
 +    }
 +
 +    /// Get a reference to the def map's diagnostics.
 +    pub fn diagnostics(&self) -> &[DefDiagnostic] {
 +        self.diagnostics.as_slice()
 +    }
 +
 +    pub fn recursion_limit(&self) -> Option<u32> {
 +        self.recursion_limit
 +    }
 +}
 +
 +impl ModuleData {
 +    pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
 +        ModuleData {
 +            origin,
 +            visibility,
 +            parent: None,
 +            children: FxHashMap::default(),
 +            scope: ItemScope::default(),
 +        }
 +    }
 +
 +    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
 +    pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
 +        self.origin.definition_source(db)
 +    }
 +
 +    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
 +    /// `None` for the crate root or block.
 +    pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
 +        let decl = self.origin.declaration()?;
 +        let value = decl.to_node(db.upcast());
 +        Some(InFile { file_id: decl.file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub enum ModuleSource {
 +    SourceFile(ast::SourceFile),
 +    Module(ast::Module),
 +    BlockExpr(ast::BlockExpr),
 +}
index 67651e06413ca21e95589c9eea86f2b1f794bf1b,0000000000000000000000000000000000000000..f394c541719f323a42f20bc7765b6a300de8b900
mode 100644,000000..100644
--- /dev/null
@@@ -1,2199 -1,0 +1,2201 @@@
- use itertools::Itertools;
 +//! 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,
 +};
-         derive_helpers_in_scope: Default::default(),
++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(),
-     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
-     /// attributes.
-     derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
 +        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>,
-             let resolver = |path| {
 +}
 +
 +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;
 +                }
 +
 +                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 = if self.def_map.edition == Edition::Edition2015 {
 +            PathKind::Plain
 +        } else {
 +            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);
 +                    return;
 +                }
 +                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 && 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| {
-                 resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(self.db, it))
++            let resolver2 = |path| {
 +                let resolved_res = self.def_map.resolve_path_fp_with_macro(
 +                    self.db,
 +                    ResolveMode::Other,
 +                    directive.module_id,
 +                    &path,
 +                    BuiltinShadowMode::Module,
 +                );
-                     let call_id = derive_macro_as_call_id(
++                resolved_res
++                    .resolved_def
++                    .take_macros()
++                    .map(|it| (it, macro_id_to_def_id(self.db, it)))
 +            };
++            let resolver = |path| resolver2(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,
 +                        &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 } => {
-                         &resolver,
++                    let id = derive_macro_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *derive_attr,
 +                        *derive_pos as u32,
 +                        self.def_map.krate,
-                     if let Ok(call_id) = call_id {
++                        &resolver2,
 +                    );
-                         if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id) {
-                             if helpers.contains(ident) {
++
++                    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() {
-                         MacroDefId {  kind:MacroDefKind::BuiltInAttr(expander, _),.. }
++                        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(path.clone()) {
 +                        Some(def) if def.is_attribute() => def,
 +                        _ => return true,
 +                    };
 +                    if matches!(
 +                        def,
-         // If we've just resolved a derive, record its helper attributes.
-         if let MacroCallKind::Derive { ast_id, .. } = &loc.kind {
-             if loc.def.krate != self.def_map.krate {
-                 let def_map = self.db.crate_def_map(loc.def.krate);
-                 if let Some(helpers) = def_map.exported_derives.get(&loc.def) {
-                     self.derive_helpers_in_scope
-                         .entry(ast_id.map(|it| it.upcast()))
-                         .or_default()
-                         .extend(helpers.iter().cloned());
-                 }
-             }
-         }
++                        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.
 +        self.unresolved_macros.extend(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);
 +        }
 +
-             derive_helpers_in_scope: Default::default(),
 +        // 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 c8d3052102f452666580f2b4d60c3b2abb29b970,0000000000000000000000000000000000000000..3163fa0f93fa573c0e2215f2ccaf5f1627340b38
mode 100644,000000..100644
--- /dev/null
@@@ -1,907 -1,0 +1,912 @@@
-                 Scope::ModuleScope(m) => Some(m.def_map.krate()),
 +//! Name resolution façade.
 +use std::{hash::BuildHasherDefault, sync::Arc};
 +
 +use base_db::CrateId;
 +use hir_expand::name::{name, Name};
 +use indexmap::IndexMap;
 +use rustc_hash::FxHashSet;
 +use smallvec::{smallvec, SmallVec};
 +
 +use crate::{
 +    body::scope::{ExprScopes, ScopeId},
 +    builtin_type::BuiltinType,
 +    db::DefDatabase,
 +    expr::{ExprId, LabelId, PatId},
 +    generics::{GenericParams, TypeOrConstParamData},
 +    intern::Interned,
 +    item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
 +    nameres::DefMap,
 +    path::{ModPath, PathKind},
 +    per_ns::PerNs,
 +    visibility::{RawVisibility, Visibility},
 +    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
 +    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId,
 +    StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId,
 +};
 +
 +#[derive(Debug, Clone)]
 +pub struct Resolver {
 +    /// The stack of scopes, where the inner-most scope is the last item.
 +    ///
 +    /// When using, you generally want to process the scopes in reverse order,
 +    /// there's `scopes` *method* for that.
 +    ///
 +    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
 +    scopes: Vec<Scope>,
 +}
 +
 +// FIXME how to store these best
 +#[derive(Debug, Clone)]
 +struct ModuleItemMap {
 +    def_map: Arc<DefMap>,
 +    module_id: LocalModuleId,
 +}
 +
 +#[derive(Debug, Clone)]
 +struct ExprScope {
 +    owner: DefWithBodyId,
 +    expr_scopes: Arc<ExprScopes>,
 +    scope_id: ScopeId,
 +}
 +
 +#[derive(Debug, Clone)]
 +enum Scope {
 +    /// All the items and imported names of a module
 +    ModuleScope(ModuleItemMap),
 +    /// Brings the generic parameters of an item into scope
 +    GenericParams { def: GenericDefId, params: Interned<GenericParams> },
 +    /// Brings `Self` in `impl` block into scope
 +    ImplDefScope(ImplId),
 +    /// Brings `Self` in enum, struct and union definitions into scope
 +    AdtScope(AdtId),
 +    /// Local bindings
 +    ExprScope(ExprScope),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum TypeNs {
 +    SelfType(ImplId),
 +    GenericParam(TypeParamId),
 +    AdtId(AdtId),
 +    AdtSelfType(AdtId),
 +    // Yup, enum variants are added to the types ns, but any usage of variant as
 +    // type is an error.
 +    EnumVariantId(EnumVariantId),
 +    TypeAliasId(TypeAliasId),
 +    BuiltinType(BuiltinType),
 +    TraitId(TraitId),
 +    // Module belong to type ns, but the resolver is used when all module paths
 +    // are fully resolved.
 +    // ModuleId(ModuleId)
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ResolveValueResult {
 +    ValueNs(ValueNs),
 +    Partial(TypeNs, usize),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ValueNs {
 +    ImplSelf(ImplId),
 +    LocalBinding(PatId),
 +    FunctionId(FunctionId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +    StructId(StructId),
 +    EnumVariantId(EnumVariantId),
 +    GenericParam(ConstParamId),
 +}
 +
 +impl Resolver {
 +    /// Resolve known trait from std, like `std::futures::Future`
 +    pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::TraitId(it) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Resolve known struct from std, like `std::boxed::Box`
 +    pub fn resolve_known_struct(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<StructId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Resolve known enum from std, like `std::result::Result`
 +    pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<EnumId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
 +    fn scopes(&self) -> impl Iterator<Item = &Scope> {
 +        self.scopes.iter().rev()
 +    }
 +
 +    fn resolve_module_path(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> PerNs {
 +        let (item_map, module) = self.module_scope();
 +        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
 +        if segment_index.is_some() {
 +            return PerNs::none();
 +        }
 +        module_res
 +    }
 +
 +    pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
 +        self.resolve_module_path(db, path, BuiltinShadowMode::Module)
 +    }
 +
++    // FIXME: This shouldn't exist
 +    pub fn resolve_module_path_in_trait_assoc_items(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<PerNs> {
 +        let (item_map, module) = self.module_scope();
 +        let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
 +        match module_res.take_types()? {
 +            ModuleDefId::TraitId(it) => {
 +                let idx = idx?;
 +                let unresolved = &path.segments()[idx..];
 +                let assoc = match unresolved {
 +                    [it] => it,
 +                    _ => return None,
 +                };
 +                let &(_, assoc) = db.trait_data(it).items.iter().find(|(n, _)| n == assoc)?;
 +                Some(match assoc {
 +                    AssocItemId::FunctionId(it) => PerNs::values(it.into(), Visibility::Public),
 +                    AssocItemId::ConstId(it) => PerNs::values(it.into(), Visibility::Public),
 +                    AssocItemId::TypeAliasId(it) => PerNs::types(it.into(), Visibility::Public),
 +                })
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn resolve_path_in_type_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<(TypeNs, Option<usize>)> {
 +        let first_name = path.segments().first()?;
 +        let skip_to_mod = path.kind != PathKind::Plain;
 +        for scope in self.scopes() {
 +            match scope {
 +                Scope::ExprScope(_) => continue,
 +                Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
 +
 +                Scope::GenericParams { params, def } => {
 +                    if let Some(id) = params.find_type_by_name(first_name, *def) {
 +                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
 +                        return Some((TypeNs::GenericParam(id), idx));
 +                    }
 +                }
 +                Scope::ImplDefScope(impl_) => {
 +                    if first_name == &name![Self] {
 +                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
 +                        return Some((TypeNs::SelfType(*impl_), idx));
 +                    }
 +                }
 +                Scope::AdtScope(adt) => {
 +                    if first_name == &name![Self] {
 +                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
 +                        return Some((TypeNs::AdtSelfType(*adt), idx));
 +                    }
 +                }
 +                Scope::ModuleScope(m) => {
 +                    if let Some(res) = m.resolve_path_in_type_ns(db, path) {
 +                        return Some(res);
 +                    }
 +                }
 +            }
 +        }
 +        None
 +    }
 +
 +    pub fn resolve_path_in_type_ns_fully(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<TypeNs> {
 +        let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
 +        if unresolved.is_some() {
 +            return None;
 +        }
 +        Some(res)
 +    }
 +
 +    pub fn resolve_visibility(
 +        &self,
 +        db: &dyn DefDatabase,
 +        visibility: &RawVisibility,
 +    ) -> Option<Visibility> {
 +        match visibility {
 +            RawVisibility::Module(_) => {
 +                let (item_map, module) = self.module_scope();
 +                item_map.resolve_visibility(db, module, visibility)
 +            }
 +            RawVisibility::Public => Some(Visibility::Public),
 +        }
 +    }
 +
 +    pub fn resolve_path_in_value_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ResolveValueResult> {
 +        let n_segments = path.segments().len();
 +        let tmp = name![self];
 +        let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
 +        let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
 +        for scope in self.scopes() {
 +            match scope {
 +                Scope::AdtScope(_)
 +                | Scope::ExprScope(_)
 +                | Scope::GenericParams { .. }
 +                | Scope::ImplDefScope(_)
 +                    if skip_to_mod =>
 +                {
 +                    continue
 +                }
 +
 +                Scope::ExprScope(scope) if n_segments <= 1 => {
 +                    let entry = scope
 +                        .expr_scopes
 +                        .entries(scope.scope_id)
 +                        .iter()
 +                        .find(|entry| entry.name() == first_name);
 +
 +                    if let Some(e) = entry {
 +                        return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
 +                    }
 +                }
 +                Scope::ExprScope(_) => continue,
 +
 +                Scope::GenericParams { params, def } if n_segments > 1 => {
 +                    if let Some(id) = params.find_type_by_name(first_name, *def) {
 +                        let ty = TypeNs::GenericParam(id);
 +                        return Some(ResolveValueResult::Partial(ty, 1));
 +                    }
 +                }
 +                Scope::GenericParams { params, def } if n_segments == 1 => {
 +                    if let Some(id) = params.find_const_by_name(first_name, *def) {
 +                        let val = ValueNs::GenericParam(id);
 +                        return Some(ResolveValueResult::ValueNs(val));
 +                    }
 +                }
 +                Scope::GenericParams { .. } => continue,
 +
 +                Scope::ImplDefScope(impl_) => {
 +                    if first_name == &name![Self] {
 +                        if n_segments > 1 {
 +                            let ty = TypeNs::SelfType(*impl_);
 +                            return Some(ResolveValueResult::Partial(ty, 1));
 +                        } else {
 +                            return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_)));
 +                        }
 +                    }
 +                }
 +                Scope::AdtScope(adt) => {
 +                    if n_segments == 1 {
 +                        // bare `Self` doesn't work in the value namespace in a struct/enum definition
 +                        continue;
 +                    }
 +                    if first_name == &name![Self] {
 +                        let ty = TypeNs::AdtSelfType(*adt);
 +                        return Some(ResolveValueResult::Partial(ty, 1));
 +                    }
 +                }
 +
 +                Scope::ModuleScope(m) => {
 +                    if let Some(def) = m.resolve_path_in_value_ns(db, path) {
 +                        return Some(def);
 +                    }
 +                }
 +            }
 +        }
 +
 +        // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
 +        // to resolving to the primitive type, to allow this to still work in the presence of
 +        // `use core::u16;`.
 +        if path.kind == PathKind::Plain && path.segments().len() > 1 {
 +            match BuiltinType::by_name(&path.segments()[0]) {
 +                Some(builtin) => {
 +                    return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
 +                }
 +                None => {}
 +            }
 +        }
 +
 +        None
 +    }
 +
 +    pub fn resolve_path_in_value_ns_fully(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ValueNs> {
 +        match self.resolve_path_in_value_ns(db, path)? {
 +            ResolveValueResult::ValueNs(it) => Some(it),
 +            ResolveValueResult::Partial(..) => None,
 +        }
 +    }
 +
 +    pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
 +        let (item_map, module) = self.module_scope();
 +        item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
 +    }
 +
 +    /// Returns a set of names available in the current scope.
 +    ///
 +    /// Note that this is a somewhat fuzzy concept -- internally, the compiler
 +    /// doesn't necessary follow a strict scoping discipline. Rather, it just
 +    /// tells for each ident what it resolves to.
 +    ///
 +    /// A good example is something like `str::from_utf8`. From scopes point of
 +    /// view, this code is erroneous -- both `str` module and `str` type occupy
 +    /// the same type namespace.
 +    ///
 +    /// We don't try to model that super-correctly -- this functionality is
 +    /// primarily exposed for completions.
 +    ///
 +    /// Note that in Rust one name can be bound to several items:
 +    ///
 +    /// ```
 +    /// macro_rules! t { () => (()) }
 +    /// type t = t!();
 +    /// const t: t = t!()
 +    /// ```
 +    ///
 +    /// That's why we return a multimap.
 +    ///
 +    /// The shadowing is accounted for: in
 +    ///
 +    /// ```
 +    /// let x = 92;
 +    /// {
 +    ///     let x = 92;
 +    ///     $0
 +    /// }
 +    /// ```
 +    ///
 +    /// there will be only one entry for `x` in the result.
 +    ///
 +    /// The result is ordered *roughly* from the innermost scope to the
 +    /// outermost: when the name is introduced in two namespaces in two scopes,
 +    /// we use the position of the first scope.
 +    pub fn names_in_scope(
 +        &self,
 +        db: &dyn DefDatabase,
 +    ) -> FxIndexMap<Name, SmallVec<[ScopeDef; 1]>> {
 +        let mut res = ScopeNames::default();
 +        for scope in self.scopes() {
 +            scope.process_names(&mut res, db);
 +        }
 +        res.map
 +    }
 +
 +    pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
 +        let mut traits = FxHashSet::default();
 +        for scope in self.scopes() {
 +            match scope {
 +                Scope::ModuleScope(m) => {
 +                    if let Some(prelude) = m.def_map.prelude() {
 +                        let prelude_def_map = prelude.def_map(db);
 +                        traits.extend(prelude_def_map[prelude.local_id].scope.traits());
 +                    }
 +                    traits.extend(m.def_map[m.module_id].scope.traits());
 +
 +                    // Add all traits that are in scope because of the containing DefMaps
 +                    m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
 +                        if let Some(prelude) = def_map.prelude() {
 +                            let prelude_def_map = prelude.def_map(db);
 +                            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
 +                        }
 +                        traits.extend(def_map[module].scope.traits());
 +                        None::<()>
 +                    });
 +                }
 +                &Scope::ImplDefScope(impl_) => {
 +                    if let Some(target_trait) = &db.impl_data(impl_).target_trait {
 +                        if let Some(TypeNs::TraitId(trait_)) =
 +                            self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path())
 +                        {
 +                            traits.insert(trait_);
 +                        }
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
 +        traits
 +    }
 +
 +    fn module_scope(&self) -> (&DefMap, LocalModuleId) {
 +        self.scopes()
 +            .find_map(|scope| match scope {
 +                Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
 +                _ => None,
 +            })
 +            .expect("module scope invariant violated")
 +    }
 +
 +    pub fn module(&self) -> ModuleId {
 +        let (def_map, local_id) = self.module_scope();
 +        def_map.module_id(local_id)
 +    }
 +
 +    pub fn krate(&self) -> CrateId {
++        self.def_map().krate()
++    }
++
++    pub fn def_map(&self) -> &DefMap {
 +        self.scopes
 +            .get(0)
 +            .and_then(|scope| match scope {
++                Scope::ModuleScope(m) => Some(&m.def_map),
 +                _ => None,
 +            })
 +            .expect("module scope invariant violated")
 +    }
 +
 +    pub fn where_predicates_in_scope(
 +        &self,
 +    ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
 +        self.scopes()
 +            .filter_map(|scope| match scope {
 +                Scope::GenericParams { params, .. } => Some(params),
 +                _ => None,
 +            })
 +            .flat_map(|params| params.where_predicates.iter())
 +    }
 +
 +    pub fn generic_def(&self) -> Option<GenericDefId> {
 +        self.scopes().find_map(|scope| match scope {
 +            Scope::GenericParams { def, .. } => Some(*def),
 +            _ => None,
 +        })
 +    }
 +
 +    pub fn body_owner(&self) -> Option<DefWithBodyId> {
 +        self.scopes().find_map(|scope| match scope {
 +            Scope::ExprScope(it) => Some(it.owner),
 +            _ => None,
 +        })
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDefId),
 +    Unknown,
 +    ImplSelfType(ImplId),
 +    AdtSelfType(AdtId),
 +    GenericParam(GenericParamId),
 +    Local(PatId),
 +    Label(LabelId),
 +}
 +
 +impl Scope {
 +    fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
 +        match self {
 +            Scope::ModuleScope(m) => {
 +                // FIXME: should we provide `self` here?
 +                // f(
 +                //     Name::self_param(),
 +                //     PerNs::types(Resolution::Def {
 +                //         def: m.module.into(),
 +                //     }),
 +                // );
 +                m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
 +                    acc.add_per_ns(name, def);
 +                });
 +                m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| {
 +                    macs.iter().for_each(|&mac| {
 +                        acc.add(
 +                            name,
 +                            ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))),
 +                        );
 +                    })
 +                });
 +                m.def_map.extern_prelude().for_each(|(name, &def)| {
 +                    acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
 +                });
 +                BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
 +                    acc.add_per_ns(name, def);
 +                });
 +                if let Some(prelude) = m.def_map.prelude() {
 +                    let prelude_def_map = prelude.def_map(db);
 +                    for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
 +                        acc.add_per_ns(name, def)
 +                    }
 +                }
 +            }
 +            Scope::GenericParams { params, def: parent } => {
 +                let parent = *parent;
 +                for (local_id, param) in params.type_or_consts.iter() {
 +                    if let Some(name) = &param.name() {
 +                        let id = TypeOrConstParamId { parent, local_id };
 +                        let data = &db.generic_params(parent).type_or_consts[local_id];
 +                        acc.add(
 +                            name,
 +                            ScopeDef::GenericParam(match data {
 +                                TypeOrConstParamData::TypeParamData(_) => {
 +                                    GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
 +                                }
 +                                TypeOrConstParamData::ConstParamData(_) => {
 +                                    GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
 +                                }
 +                            }),
 +                        );
 +                    }
 +                }
 +                for (local_id, param) in params.lifetimes.iter() {
 +                    let id = LifetimeParamId { parent, local_id };
 +                    acc.add(&param.name, ScopeDef::GenericParam(id.into()))
 +                }
 +            }
 +            Scope::ImplDefScope(i) => {
 +                acc.add(&name![Self], ScopeDef::ImplSelfType(*i));
 +            }
 +            Scope::AdtScope(i) => {
 +                acc.add(&name![Self], ScopeDef::AdtSelfType(*i));
 +            }
 +            Scope::ExprScope(scope) => {
 +                if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) {
 +                    acc.add(&name, ScopeDef::Label(label))
 +                }
 +                scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
 +                    acc.add_local(e.name(), e.pat());
 +                });
 +            }
 +        }
 +    }
 +}
 +
 +// needs arbitrary_self_types to be a method... or maybe move to the def?
 +pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
 +    let scopes = db.expr_scopes(owner);
 +    resolver_for_scope(db, owner, scopes.scope_for(expr_id))
 +}
 +
 +pub fn resolver_for_scope(
 +    db: &dyn DefDatabase,
 +    owner: DefWithBodyId,
 +    scope_id: Option<ScopeId>,
 +) -> Resolver {
 +    let mut r = owner.resolver(db);
 +    let scopes = db.expr_scopes(owner);
 +    let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
 +    r.scopes.reserve(scope_chain.len());
 +
 +    for scope in scope_chain.into_iter().rev() {
 +        if let Some(block) = scopes.block(scope) {
 +            if let Some(def_map) = db.block_def_map(block) {
 +                let root = def_map.root();
 +                r = r.push_module_scope(def_map, root);
 +                // FIXME: This adds as many module scopes as there are blocks, but resolving in each
 +                // already traverses all parents, so this is O(n²). I think we could only store the
 +                // innermost module scope instead?
 +            }
 +        }
 +
 +        r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
 +    }
 +    r
 +}
 +
 +impl Resolver {
 +    fn push_scope(mut self, scope: Scope) -> Resolver {
 +        self.scopes.push(scope);
 +        self
 +    }
 +
 +    fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver {
 +        let params = db.generic_params(def);
 +        self.push_scope(Scope::GenericParams { def, params })
 +    }
 +
 +    fn push_impl_def_scope(self, impl_def: ImplId) -> Resolver {
 +        self.push_scope(Scope::ImplDefScope(impl_def))
 +    }
 +
 +    fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
 +        self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
 +    }
 +
 +    fn push_expr_scope(
 +        self,
 +        owner: DefWithBodyId,
 +        expr_scopes: Arc<ExprScopes>,
 +        scope_id: ScopeId,
 +    ) -> Resolver {
 +        self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
 +    }
 +}
 +
 +impl ModuleItemMap {
 +    fn resolve_path_in_value_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ResolveValueResult> {
 +        let (module_def, idx) =
 +            self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
 +        match idx {
 +            None => {
 +                let value = to_value_ns(module_def)?;
 +                Some(ResolveValueResult::ValueNs(value))
 +            }
 +            Some(idx) => {
 +                let ty = match module_def.take_types()? {
 +                    ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
 +                    ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
 +                    ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
 +                    ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
 +
 +                    ModuleDefId::ModuleId(_)
 +                    | ModuleDefId::FunctionId(_)
 +                    | ModuleDefId::EnumVariantId(_)
 +                    | ModuleDefId::ConstId(_)
 +                    | ModuleDefId::MacroId(_)
 +                    | ModuleDefId::StaticId(_) => return None,
 +                };
 +                Some(ResolveValueResult::Partial(ty, idx))
 +            }
 +        }
 +    }
 +
 +    fn resolve_path_in_type_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<(TypeNs, Option<usize>)> {
 +        let (module_def, idx) =
 +            self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
 +        let res = to_type_ns(module_def)?;
 +        Some((res, idx))
 +    }
 +}
 +
 +fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
 +    let res = match per_ns.take_values()? {
 +        ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
 +        ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
 +        ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
 +        ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
 +        ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
 +
 +        ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_))
 +        | ModuleDefId::TraitId(_)
 +        | ModuleDefId::TypeAliasId(_)
 +        | ModuleDefId::BuiltinType(_)
 +        | ModuleDefId::MacroId(_)
 +        | ModuleDefId::ModuleId(_) => return None,
 +    };
 +    Some(res)
 +}
 +
 +fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
 +    let res = match per_ns.take_types()? {
 +        ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
 +        ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
 +
 +        ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
 +        ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
 +
 +        ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
 +
 +        ModuleDefId::FunctionId(_)
 +        | ModuleDefId::ConstId(_)
 +        | ModuleDefId::MacroId(_)
 +        | ModuleDefId::StaticId(_)
 +        | ModuleDefId::ModuleId(_) => return None,
 +    };
 +    Some(res)
 +}
 +
 +type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
 +#[derive(Default)]
 +struct ScopeNames {
 +    map: FxIndexMap<Name, SmallVec<[ScopeDef; 1]>>,
 +}
 +
 +impl ScopeNames {
 +    fn add(&mut self, name: &Name, def: ScopeDef) {
 +        let set = self.map.entry(name.clone()).or_default();
 +        if !set.contains(&def) {
 +            set.push(def)
 +        }
 +    }
 +    fn add_per_ns(&mut self, name: &Name, def: PerNs) {
 +        if let &Some((ty, _)) = &def.types {
 +            self.add(name, ScopeDef::ModuleDef(ty))
 +        }
 +        if let &Some((def, _)) = &def.values {
 +            self.add(name, ScopeDef::ModuleDef(def))
 +        }
 +        if let &Some((mac, _)) = &def.macros {
 +            self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)))
 +        }
 +        if def.is_none() {
 +            self.add(name, ScopeDef::Unknown)
 +        }
 +    }
 +    fn add_local(&mut self, name: &Name, pat: PatId) {
 +        let set = self.map.entry(name.clone()).or_default();
 +        // XXX: hack, account for local (and only local) shadowing.
 +        //
 +        // This should be somewhat more principled and take namespaces into
 +        // accounts, but, alas, scoping rules are a hoax. `str` type and `str`
 +        // module can be both available in the same scope.
 +        if set.iter().any(|it| matches!(it, &ScopeDef::Local(_))) {
 +            cov_mark::hit!(shadowing_shows_single_completion);
 +            return;
 +        }
 +        set.push(ScopeDef::Local(pat))
 +    }
 +}
 +
 +pub trait HasResolver: Copy {
 +    /// Builds a resolver for type references inside this def.
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver;
 +}
 +
 +impl HasResolver for ModuleId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        let mut def_map = self.def_map(db);
 +        let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
 +        while let Some(parent) = def_map.parent() {
 +            def_map = parent.def_map(db);
 +            modules.push((def_map.clone(), parent.local_id));
 +        }
 +        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
 +        for (def_map, module) in modules.into_iter().rev() {
 +            resolver = resolver.push_module_scope(def_map, module);
 +        }
 +        resolver
 +    }
 +}
 +
 +impl HasResolver for TraitId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl<T: Into<AdtId> + Copy> HasResolver for T {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        let def = self.into();
 +        def.module(db)
 +            .resolver(db)
 +            .push_generic_params_scope(db, def.into())
 +            .push_scope(Scope::AdtScope(def))
 +    }
 +}
 +
 +impl HasResolver for FunctionId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl HasResolver for ConstId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for StaticId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for TypeAliasId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl HasResolver for ImplId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db)
 +            .container
 +            .resolver(db)
 +            .push_generic_params_scope(db, self.into())
 +            .push_impl_def_scope(self)
 +    }
 +}
 +
 +impl HasResolver for ExternBlockId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        // Same as parent's
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for DefWithBodyId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            DefWithBodyId::ConstId(c) => c.resolver(db),
 +            DefWithBodyId::FunctionId(f) => f.resolver(db),
 +            DefWithBodyId::StaticId(s) => s.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for ItemContainerId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            ItemContainerId::ModuleId(it) => it.resolver(db),
 +            ItemContainerId::TraitId(it) => it.resolver(db),
 +            ItemContainerId::ImplId(it) => it.resolver(db),
 +            ItemContainerId::ExternBlockId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for GenericDefId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            GenericDefId::FunctionId(inner) => inner.resolver(db),
 +            GenericDefId::AdtId(adt) => adt.resolver(db),
 +            GenericDefId::TraitId(inner) => inner.resolver(db),
 +            GenericDefId::TypeAliasId(inner) => inner.resolver(db),
 +            GenericDefId::ImplId(inner) => inner.resolver(db),
 +            GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db),
 +            GenericDefId::ConstId(inner) => inner.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for VariantId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.resolver(db),
 +            VariantId::StructId(it) => it.resolver(db),
 +            VariantId::UnionId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for MacroId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            MacroId::Macro2Id(it) => it.resolver(db),
 +            MacroId::MacroRulesId(it) => it.resolver(db),
 +            MacroId::ProcMacroId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for Macro2Id {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for ProcMacroId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for MacroRulesId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
index 8cca522aef623877d0cd40d5706c67a546924a78,0000000000000000000000000000000000000000..642e03edd230636ca3911a0e0eee44dc8989a41e
mode 100644,000000..100644
--- /dev/null
@@@ -1,413 -1,0 +1,416 @@@
-         Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()),
 +//! Various diagnostics for expressions that are collected together in one pass
 +//! through the body using inference results: mismatched arg counts, missing
 +//! fields, etc.
 +
 +use std::fmt;
 +use std::sync::Arc;
 +
 +use hir_def::{path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
 +use hir_expand::name;
 +use itertools::Either;
 +use itertools::Itertools;
 +use rustc_hash::FxHashSet;
 +use typed_arena::Arena;
 +
 +use crate::{
 +    db::HirDatabase,
 +    diagnostics::match_check::{
 +        self,
 +        deconstruct_pat::DeconstructedPat,
 +        usefulness::{compute_match_usefulness, MatchCheckCtx},
 +    },
 +    display::HirDisplay,
 +    InferenceResult, Ty, TyExt,
 +};
 +
 +pub(crate) use hir_def::{
 +    body::Body,
 +    expr::{Expr, ExprId, MatchArm, Pat, PatId},
 +    LocalFieldId, VariantId,
 +};
 +
 +pub enum BodyValidationDiagnostic {
 +    RecordMissingFields {
 +        record: Either<ExprId, PatId>,
 +        variant: VariantId,
 +        missed_fields: Vec<LocalFieldId>,
 +    },
 +    ReplaceFilterMapNextWithFindMap {
 +        method_call_expr: ExprId,
 +    },
 +    MissingMatchArms {
 +        match_expr: ExprId,
 +        uncovered_patterns: String,
 +    },
 +}
 +
 +impl BodyValidationDiagnostic {
 +    pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> {
 +        let _p = profile::span("BodyValidationDiagnostic::collect");
 +        let infer = db.infer(owner);
 +        let mut validator = ExprValidator::new(owner, infer);
 +        validator.validate_body(db);
 +        validator.diagnostics
 +    }
 +}
 +
 +struct ExprValidator {
 +    owner: DefWithBodyId,
 +    infer: Arc<InferenceResult>,
 +    pub(super) diagnostics: Vec<BodyValidationDiagnostic>,
 +}
 +
 +impl ExprValidator {
 +    fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator {
 +        ExprValidator { owner, infer, diagnostics: Vec::new() }
 +    }
 +
 +    fn validate_body(&mut self, db: &dyn HirDatabase) {
 +        let body = db.body(self.owner);
 +        let mut filter_map_next_checker = None;
 +
 +        for (id, expr) in body.exprs.iter() {
 +            if let Some((variant, missed_fields, true)) =
 +                record_literal_missing_fields(db, &self.infer, id, expr)
 +            {
 +                self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
 +                    record: Either::Left(id),
 +                    variant,
 +                    missed_fields,
 +                });
 +            }
 +
 +            match expr {
 +                Expr::Match { expr, arms } => {
 +                    self.validate_match(id, *expr, arms, db, self.infer.clone());
 +                }
 +                Expr::Call { .. } | Expr::MethodCall { .. } => {
 +                    self.validate_call(db, id, expr, &mut filter_map_next_checker);
 +                }
 +                _ => {}
 +            }
 +        }
 +        for (id, pat) in body.pats.iter() {
 +            if let Some((variant, missed_fields, true)) =
 +                record_pattern_missing_fields(db, &self.infer, id, pat)
 +            {
 +                self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
 +                    record: Either::Right(id),
 +                    variant,
 +                    missed_fields,
 +                });
 +            }
 +        }
 +    }
 +
 +    fn validate_call(
 +        &mut self,
 +        db: &dyn HirDatabase,
 +        call_id: ExprId,
 +        expr: &Expr,
 +        filter_map_next_checker: &mut Option<FilterMapNextChecker>,
 +    ) {
 +        // Check that the number of arguments matches the number of parameters.
 +
 +        // FIXME: Due to shortcomings in the current type system implementation, only emit this
 +        // diagnostic if there are no type mismatches in the containing function.
 +        if self.infer.expr_type_mismatches().next().is_some() {
 +            return;
 +        }
 +
 +        match expr {
 +            Expr::MethodCall { receiver, .. } => {
 +                let (callee, _) = match self.infer.method_resolution(call_id) {
 +                    Some(it) => it,
 +                    None => return,
 +                };
 +
 +                if filter_map_next_checker
 +                    .get_or_insert_with(|| {
 +                        FilterMapNextChecker::new(&self.owner.resolver(db.upcast()), db)
 +                    })
 +                    .check(call_id, receiver, &callee)
 +                    .is_some()
 +                {
 +                    self.diagnostics.push(
 +                        BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
 +                            method_call_expr: call_id,
 +                        },
 +                    );
 +                }
 +            }
 +            _ => return,
 +        };
 +    }
 +
 +    fn validate_match(
 +        &mut self,
 +        id: ExprId,
 +        match_expr: ExprId,
 +        arms: &[MatchArm],
 +        db: &dyn HirDatabase,
 +        infer: Arc<InferenceResult>,
 +    ) {
 +        let body = db.body(self.owner);
 +
 +        let match_expr_ty = &infer[match_expr];
 +        if match_expr_ty.is_unknown() {
 +            return;
 +        }
 +
 +        let pattern_arena = Arena::new();
 +        let cx = MatchCheckCtx {
 +            module: self.owner.module(db.upcast()),
 +            body: self.owner,
 +            db,
 +            pattern_arena: &pattern_arena,
 +        };
 +
 +        let mut m_arms = Vec::with_capacity(arms.len());
 +        let mut has_lowering_errors = false;
 +        for arm in arms {
 +            if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
 +                // We only include patterns whose type matches the type
 +                // of the match expression. If we had an InvalidMatchArmPattern
 +                // diagnostic or similar we could raise that in an else
 +                // block here.
 +                //
 +                // When comparing the types, we also have to consider that rustc
 +                // will automatically de-reference the match expression type if
 +                // necessary.
 +                //
 +                // FIXME we should use the type checker for this.
 +                if (pat_ty == match_expr_ty
 +                    || match_expr_ty
 +                        .as_reference()
 +                        .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
 +                        .unwrap_or(false))
 +                    && types_of_subpatterns_do_match(arm.pat, &body, &infer)
 +                {
 +                    // If we had a NotUsefulMatchArm diagnostic, we could
 +                    // check the usefulness of each pattern as we added it
 +                    // to the matrix here.
 +                    let m_arm = match_check::MatchArm {
 +                        pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
 +                        has_guard: arm.guard.is_some(),
 +                    };
 +                    m_arms.push(m_arm);
 +                    if !has_lowering_errors {
 +                        continue;
 +                    }
 +                }
 +            }
 +
 +            // If we can't resolve the type of a pattern, or the pattern type doesn't
 +            // fit the match expression, we skip this diagnostic. Skipping the entire
 +            // diagnostic rather than just not including this match arm is preferred
 +            // to avoid the chance of false positives.
 +            cov_mark::hit!(validate_match_bailed_out);
 +            return;
 +        }
 +
 +        let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty);
 +
 +        // FIXME Report unreacheble arms
 +        // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
 +
 +        let witnesses = report.non_exhaustiveness_witnesses;
 +        if !witnesses.is_empty() {
 +            self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
 +                match_expr: id,
 +                uncovered_patterns: missing_match_arms(&cx, match_expr_ty, witnesses, arms),
 +            });
 +        }
 +    }
 +
 +    fn lower_pattern<'p>(
 +        &self,
 +        cx: &MatchCheckCtx<'_, 'p>,
 +        pat: PatId,
 +        db: &dyn HirDatabase,
 +        body: &Body,
 +        have_errors: &mut bool,
 +    ) -> &'p DeconstructedPat<'p> {
 +        let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
 +        let pattern = patcx.lower_pattern(pat);
 +        let pattern = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
 +        if !patcx.errors.is_empty() {
 +            *have_errors = true;
 +        }
 +        pattern
 +    }
 +}
 +
 +struct FilterMapNextChecker {
 +    filter_map_function_id: Option<hir_def::FunctionId>,
 +    next_function_id: Option<hir_def::FunctionId>,
 +    prev_filter_map_expr_id: Option<ExprId>,
 +}
 +
 +impl FilterMapNextChecker {
 +    fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
 +        // Find and store the FunctionIds for Iterator::filter_map and Iterator::next
 +        let iterator_path = path![core::iter::Iterator];
 +        let mut filter_map_function_id = None;
 +        let mut next_function_id = None;
 +
 +        if let Some(iterator_trait_id) = resolver.resolve_known_trait(db.upcast(), &iterator_path) {
 +            let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
 +            for item in iterator_trait_items.iter() {
 +                if let (name, AssocItemId::FunctionId(id)) = item {
 +                    if *name == name![filter_map] {
 +                        filter_map_function_id = Some(*id);
 +                    }
 +                    if *name == name![next] {
 +                        next_function_id = Some(*id);
 +                    }
 +                }
 +                if filter_map_function_id.is_some() && next_function_id.is_some() {
 +                    break;
 +                }
 +            }
 +        }
 +        Self { filter_map_function_id, next_function_id, prev_filter_map_expr_id: None }
 +    }
 +
 +    // check for instances of .filter_map(..).next()
 +    fn check(
 +        &mut self,
 +        current_expr_id: ExprId,
 +        receiver_expr_id: &ExprId,
 +        function_id: &hir_def::FunctionId,
 +    ) -> Option<()> {
 +        if *function_id == self.filter_map_function_id? {
 +            self.prev_filter_map_expr_id = Some(current_expr_id);
 +            return None;
 +        }
 +
 +        if *function_id == self.next_function_id? {
 +            if let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id {
 +                if *receiver_expr_id == prev_filter_map_expr_id {
 +                    return Some(());
 +                }
 +            }
 +        }
 +
 +        self.prev_filter_map_expr_id = None;
 +        None
 +    }
 +}
 +
 +pub fn record_literal_missing_fields(
 +    db: &dyn HirDatabase,
 +    infer: &InferenceResult,
 +    id: ExprId,
 +    expr: &Expr,
 +) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
 +    let (fields, exhaustive) = match expr {
++        Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => {
++            let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() };
++            (fields, exhaustive)
++        }
 +        _ => return None,
 +    };
 +
 +    let variant_def = infer.variant_resolution_for_expr(id)?;
 +    if let VariantId::UnionId(_) = variant_def {
 +        return None;
 +    }
 +
 +    let variant_data = variant_def.variant_data(db.upcast());
 +
 +    let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
 +    let missed_fields: Vec<LocalFieldId> = variant_data
 +        .fields()
 +        .iter()
 +        .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
 +        .collect();
 +    if missed_fields.is_empty() {
 +        return None;
 +    }
 +    Some((variant_def, missed_fields, exhaustive))
 +}
 +
 +pub fn record_pattern_missing_fields(
 +    db: &dyn HirDatabase,
 +    infer: &InferenceResult,
 +    id: PatId,
 +    pat: &Pat,
 +) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
 +    let (fields, exhaustive) = match pat {
 +        Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
 +        _ => return None,
 +    };
 +
 +    let variant_def = infer.variant_resolution_for_pat(id)?;
 +    if let VariantId::UnionId(_) = variant_def {
 +        return None;
 +    }
 +
 +    let variant_data = variant_def.variant_data(db.upcast());
 +
 +    let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
 +    let missed_fields: Vec<LocalFieldId> = variant_data
 +        .fields()
 +        .iter()
 +        .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
 +        .collect();
 +    if missed_fields.is_empty() {
 +        return None;
 +    }
 +    Some((variant_def, missed_fields, exhaustive))
 +}
 +
 +fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool {
 +    fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
 +        match infer.type_mismatch_for_pat(pat) {
 +            Some(_) => *has_type_mismatches = true,
 +            None => {
 +                body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
 +            }
 +        }
 +    }
 +
 +    let mut has_type_mismatches = false;
 +    walk(pat, body, infer, &mut has_type_mismatches);
 +    !has_type_mismatches
 +}
 +
 +fn missing_match_arms<'p>(
 +    cx: &MatchCheckCtx<'_, 'p>,
 +    scrut_ty: &Ty,
 +    witnesses: Vec<DeconstructedPat<'p>>,
 +    arms: &[MatchArm],
 +) -> String {
 +    struct DisplayWitness<'a, 'p>(&'a DeconstructedPat<'p>, &'a MatchCheckCtx<'a, 'p>);
 +    impl<'a, 'p> fmt::Display for DisplayWitness<'a, 'p> {
 +        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +            let DisplayWitness(witness, cx) = *self;
 +            let pat = witness.to_pat(cx);
 +            write!(f, "{}", pat.display(cx.db))
 +        }
 +    }
 +
 +    let non_empty_enum = match scrut_ty.as_adt() {
 +        Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
 +        _ => false,
 +    };
 +    if arms.is_empty() && !non_empty_enum {
 +        format!("type `{}` is non-empty", scrut_ty.display(cx.db))
 +    } else {
 +        let pat_display = |witness| DisplayWitness(witness, cx);
 +        const LIMIT: usize = 3;
 +        match &*witnesses {
 +            [witness] => format!("`{}` not covered", pat_display(witness)),
 +            [head @ .., tail] if head.len() < LIMIT => {
 +                let head = head.iter().map(pat_display);
 +                format!("`{}` and `{}` not covered", head.format("`, `"), pat_display(tail))
 +            }
 +            _ => {
 +                let (head, tail) = witnesses.split_at(LIMIT);
 +                let head = head.iter().map(pat_display);
 +                format!("`{}` and {} more not covered", head.format("`, `"), tail.len())
 +            }
 +        }
 +    }
 +}
index 2f3346707209527bc535f097d3501523508e6ef2,0000000000000000000000000000000000000000..d164e64a8be0780a0d9b5d54008b648e46b89c18
mode 100644,000000..100644
--- /dev/null
@@@ -1,1527 -1,0 +1,1527 @@@
-             Expr::Call { callee, args } => {
 +//! Type inference for expressions.
 +
 +use std::{
 +    collections::hash_map::Entry,
 +    iter::{repeat, repeat_with},
 +    mem,
 +};
 +
 +use chalk_ir::{
 +    cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 +};
 +use hir_def::{
 +    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
 +    generics::TypeOrConstParamData,
 +    path::{GenericArg, GenericArgs},
 +    resolver::resolver_for_expr,
 +    ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
 +};
 +use hir_expand::name::{name, Name};
 +use stdx::always;
 +use syntax::ast::RangeOp;
 +
 +use crate::{
 +    autoderef::{self, Autoderef},
 +    consteval,
 +    infer::coerce::CoerceMany,
 +    lower::{
 +        const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
 +    },
 +    mapping::{from_chalk, ToChalk},
 +    method_resolution::{self, VisibleFromModule},
 +    primitive::{self, UintTy},
 +    static_lifetime, to_chalk_trait_id,
 +    utils::{generics, Generics},
 +    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
 +    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +use super::{
 +    coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
 +    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
 +};
 +
 +impl<'a> InferenceContext<'a> {
 +    pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(tgt_expr, expected);
 +        if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
 +            let could_unify = self.unify(&ty, &expected_ty);
 +            if !could_unify {
 +                self.result.type_mismatches.insert(
 +                    tgt_expr.into(),
 +                    TypeMismatch { expected: expected_ty, actual: ty.clone() },
 +                );
 +            }
 +        }
 +        ty
 +    }
 +
 +    /// Infer type of expression with possibly implicit coerce to the expected type.
 +    /// Return the type after possible coercion.
 +    pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(expr, expected);
 +        if let Some(target) = expected.only_has_type(&mut self.table) {
 +            match self.coerce(Some(expr), &ty, &target) {
 +                Ok(res) => res,
 +                Err(_) => {
 +                    self.result.type_mismatches.insert(
 +                        expr.into(),
 +                        TypeMismatch { expected: target.clone(), actual: ty.clone() },
 +                    );
 +                    target
 +                }
 +            }
 +        } else {
 +            ty
 +        }
 +    }
 +
 +    fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        self.db.unwind_if_cancelled();
 +
 +        let ty = match &self.body[tgt_expr] {
 +            Expr::Missing => self.err_ty(),
 +            &Expr::If { condition, then_branch, else_branch } => {
 +                self.infer_expr(
 +                    condition,
 +                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                );
 +
 +                let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut both_arms_diverge = Diverges::Always;
 +
 +                let result_ty = self.table.new_type_var();
 +                let then_ty = self.infer_expr_inner(then_branch, expected);
 +                both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut coerce = CoerceMany::new(result_ty);
 +                coerce.coerce(self, Some(then_branch), &then_ty);
 +                let else_ty = match else_branch {
 +                    Some(else_branch) => self.infer_expr_inner(else_branch, expected),
 +                    None => TyBuilder::unit(),
 +                };
 +                both_arms_diverge &= self.diverges;
 +                // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
 +                coerce.coerce(self, else_branch, &else_ty);
 +
 +                self.diverges = condition_diverges | both_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            &Expr::Let { pat, expr } => {
 +                let input_ty = self.infer_expr(expr, &Expectation::none());
 +                self.infer_pat(pat, &input_ty, BindingMode::default());
 +                TyKind::Scalar(Scalar::Bool).intern(Interner)
 +            }
 +            Expr::Block { statements, tail, label, id: _ } => {
 +                let old_resolver = mem::replace(
 +                    &mut self.resolver,
 +                    resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
 +                );
 +                let ty = match label {
 +                    Some(_) => {
 +                        let break_ty = self.table.new_type_var();
 +                        self.breakables.push(BreakableContext {
 +                            may_break: false,
 +                            coerce: CoerceMany::new(break_ty.clone()),
 +                            label: label.map(|label| self.body[label].name.clone()),
 +                        });
 +                        let ty = self.infer_block(
 +                            tgt_expr,
 +                            statements,
 +                            *tail,
 +                            &Expectation::has_type(break_ty),
 +                        );
 +                        let ctxt = self.breakables.pop().expect("breakable stack broken");
 +                        if ctxt.may_break {
 +                            ctxt.coerce.complete()
 +                        } else {
 +                            ty
 +                        }
 +                    }
 +                    None => self.infer_block(tgt_expr, statements, *tail, expected),
 +                };
 +                self.resolver = old_resolver;
 +                ty
 +            }
 +            Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
 +            Expr::TryBlock { body } => {
 +                let _inner = self.infer_expr(*body, expected);
 +                // FIXME should be std::result::Result<{inner}, _>
 +                self.err_ty()
 +            }
 +            Expr::Async { body } => {
 +                let ret_ty = self.table.new_type_var();
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +
 +                let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +
 +                // Use the first type parameter as the output type of future.
 +                // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
 +                let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
 +                let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
 +                TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
 +                    .intern(Interner)
 +            }
 +            Expr::Loop { body, label } => {
 +                self.breakables.push(BreakableContext {
 +                    may_break: false,
 +                    coerce: CoerceMany::new(self.table.new_type_var()),
 +                    label: label.map(|label| self.body[label].name.clone()),
 +                });
 +                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
 +
 +                let ctxt = self.breakables.pop().expect("breakable stack broken");
 +
 +                if ctxt.may_break {
 +                    self.diverges = Diverges::Maybe;
 +                    ctxt.coerce.complete()
 +                } else {
 +                    TyKind::Never.intern(Interner)
 +                }
 +            }
 +            Expr::While { condition, body, label } => {
 +                self.breakables.push(BreakableContext {
 +                    may_break: false,
 +                    coerce: CoerceMany::new(self.err_ty()),
 +                    label: label.map(|label| self.body[label].name.clone()),
 +                });
 +                self.infer_expr(
 +                    *condition,
 +                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                );
 +                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
 +                let _ctxt = self.breakables.pop().expect("breakable stack broken");
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            Expr::For { iterable, body, pat, label } => {
 +                let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
 +
 +                self.breakables.push(BreakableContext {
 +                    may_break: false,
 +                    coerce: CoerceMany::new(self.err_ty()),
 +                    label: label.map(|label| self.body[label].name.clone()),
 +                });
 +                let pat_ty =
 +                    self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 +
 +                self.infer_pat(*pat, &pat_ty, BindingMode::default());
 +
 +                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
 +                let _ctxt = self.breakables.pop().expect("breakable stack broken");
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            Expr::Closure { body, args, ret_type, arg_types } => {
 +                assert_eq!(args.len(), arg_types.len());
 +
 +                let mut sig_tys = Vec::new();
 +
 +                // collect explicitly written argument types
 +                for arg_type in arg_types.iter() {
 +                    let arg_ty = match arg_type {
 +                        Some(type_ref) => self.make_ty(type_ref),
 +                        None => self.table.new_type_var(),
 +                    };
 +                    sig_tys.push(arg_ty);
 +                }
 +
 +                // add return type
 +                let ret_ty = match ret_type {
 +                    Some(type_ref) => self.make_ty(type_ref),
 +                    None => self.table.new_type_var(),
 +                };
 +                sig_tys.push(ret_ty.clone());
 +                let sig_ty = TyKind::Function(FnPointer {
 +                    num_binders: 0,
 +                    sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
 +                    substitution: FnSubst(
 +                        Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
 +                    ),
 +                })
 +                .intern(Interner);
 +                let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
 +                let closure_ty =
 +                    TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
 +                        .intern(Interner);
 +
 +                // Eagerly try to relate the closure type with the expected
 +                // type, otherwise we often won't have enough information to
 +                // infer the body.
 +                self.deduce_closure_type_from_expectations(
 +                    tgt_expr,
 +                    &closure_ty,
 +                    &sig_ty,
 +                    expected,
 +                );
 +
 +                // Now go through the argument patterns
 +                for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
 +                    self.infer_pat(*arg_pat, &arg_ty, BindingMode::default());
 +                }
 +
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +
 +                self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +
 +                closure_ty
 +            }
-             Expr::RecordLit { path, fields, spread } => {
++            Expr::Call { callee, args, .. } => {
 +                let callee_ty = self.infer_expr(*callee, &Expectation::none());
 +                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
 +                let mut res = None;
 +                let mut derefed_callee = callee_ty.clone();
 +                // manual loop to be able to access `derefs.table`
 +                while let Some((callee_deref_ty, _)) = derefs.next() {
 +                    res = derefs.table.callable_sig(&callee_deref_ty, args.len());
 +                    if res.is_some() {
 +                        derefed_callee = callee_deref_ty;
 +                        break;
 +                    }
 +                }
 +                // if the function is unresolved, we use is_varargs=true to
 +                // suppress the arg count diagnostic here
 +                let is_varargs =
 +                    derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs)
 +                        || res.is_none();
 +                let (param_tys, ret_ty) = match res {
 +                    Some(res) => {
 +                        let adjustments = auto_deref_adjust_steps(&derefs);
 +                        self.write_expr_adj(*callee, adjustments);
 +                        res
 +                    }
 +                    None => (Vec::new(), self.err_ty()), // FIXME diagnostic
 +                };
 +                let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
 +                self.register_obligations_for_call(&callee_ty);
 +
 +                let expected_inputs = self.expected_inputs_for_expected_output(
 +                    expected,
 +                    ret_ty.clone(),
 +                    param_tys.clone(),
 +                );
 +
 +                self.check_call_arguments(
 +                    tgt_expr,
 +                    args,
 +                    &expected_inputs,
 +                    &param_tys,
 +                    &indices_to_skip,
 +                    is_varargs,
 +                );
 +                self.normalize_associated_types_in(ret_ty)
 +            }
 +            Expr::MethodCall { receiver, args, method_name, generic_args } => self
 +                .infer_method_call(
 +                    tgt_expr,
 +                    *receiver,
 +                    args,
 +                    method_name,
 +                    generic_args.as_deref(),
 +                    expected,
 +                ),
 +            Expr::Match { expr, arms } => {
 +                let input_ty = self.infer_expr(*expr, &Expectation::none());
 +
 +                let expected = expected.adjust_for_branches(&mut self.table);
 +
 +                let result_ty = if arms.is_empty() {
 +                    TyKind::Never.intern(Interner)
 +                } else {
 +                    match &expected {
 +                        Expectation::HasType(ty) => ty.clone(),
 +                        _ => self.table.new_type_var(),
 +                    }
 +                };
 +                let mut coerce = CoerceMany::new(result_ty);
 +
 +                let matchee_diverges = self.diverges;
 +                let mut all_arms_diverge = Diverges::Always;
 +
 +                for arm in arms.iter() {
 +                    self.diverges = Diverges::Maybe;
 +                    let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
 +                    if let Some(guard_expr) = arm.guard {
 +                        self.infer_expr(
 +                            guard_expr,
 +                            &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                        );
 +                    }
 +
 +                    let arm_ty = self.infer_expr_inner(arm.expr, &expected);
 +                    all_arms_diverge &= self.diverges;
 +                    coerce.coerce(self, Some(arm.expr), &arm_ty);
 +                }
 +
 +                self.diverges = matchee_diverges | all_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            Expr::Path(p) => {
 +                // FIXME this could be more efficient...
 +                let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
 +                self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
 +            }
 +            Expr::Continue { .. } => TyKind::Never.intern(Interner),
 +            Expr::Break { expr, label } => {
 +                let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
 +                    Some(ctxt) => {
 +                        // avoiding the borrowck
 +                        mem::replace(
 +                            &mut ctxt.coerce,
 +                            CoerceMany::new(self.result.standard_types.unknown.clone()),
 +                        )
 +                    }
 +                    None => CoerceMany::new(self.result.standard_types.unknown.clone()),
 +                };
 +
 +                let val_ty = if let Some(expr) = *expr {
 +                    self.infer_expr(expr, &Expectation::none())
 +                } else {
 +                    TyBuilder::unit()
 +                };
 +
 +                // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
 +                coerce.coerce(self, *expr, &val_ty);
 +
 +                if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
 +                    ctxt.coerce = coerce;
 +                    ctxt.may_break = true;
 +                } else {
 +                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
 +                        expr: tgt_expr,
 +                    });
 +                };
 +
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Return { expr } => {
 +                if let Some(expr) = expr {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
 +                } else {
 +                    let unit = TyBuilder::unit();
 +                    let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Yield { expr } => {
 +                // FIXME: track yield type for coercion
 +                if let Some(expr) = expr {
 +                    self.infer_expr(*expr, &Expectation::none());
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
-             Expr::Tuple { exprs } => {
++            Expr::RecordLit { path, fields, spread, .. } => {
 +                let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
 +                if let Some(variant) = def_id {
 +                    self.write_variant_resolution(tgt_expr.into(), variant);
 +                }
 +
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    self.unify(&ty, &t);
 +                }
 +
 +                let substs = ty
 +                    .as_adt()
 +                    .map(|(_, s)| s.clone())
 +                    .unwrap_or_else(|| Substitution::empty(Interner));
 +                let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
 +                let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
 +                for field in fields.iter() {
 +                    let field_def =
 +                        variant_data.as_ref().and_then(|it| match it.field(&field.name) {
 +                            Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
 +                            None => {
 +                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
 +                                    expr: field.expr,
 +                                });
 +                                None
 +                            }
 +                        });
 +                    let field_ty = field_def.map_or(self.err_ty(), |it| {
 +                        field_types[it.local_id].clone().substitute(Interner, &substs)
 +                    });
 +                    self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
 +                }
 +                if let Some(expr) = spread {
 +                    self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +                ty
 +            }
 +            Expr::Field { expr, name } => {
 +                let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +
 +                let mut autoderef = Autoderef::new(&mut self.table, receiver_ty);
 +                let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
 +                    let (field_id, parameters) = match derefed_ty.kind(Interner) {
 +                        TyKind::Tuple(_, substs) => {
 +                            return name.as_tuple_index().and_then(|idx| {
 +                                substs
 +                                    .as_slice(Interner)
 +                                    .get(idx)
 +                                    .map(|a| a.assert_ty_ref(Interner))
 +                                    .cloned()
 +                            });
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
 +                            let local_id = self.db.struct_data(*s).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*s).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
 +                            let local_id = self.db.union_data(*u).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*u).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        _ => return None,
 +                    };
 +                    let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
 +                        .is_visible_from(self.db.upcast(), self.resolver.module());
 +                    if !is_visible {
 +                        // Write down the first field resolution even if it is not visible
 +                        // This aids IDE features for private fields like goto def and in
 +                        // case of autoderef finding an applicable field, this will be
 +                        // overwritten in a following cycle
 +                        if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr)
 +                        {
 +                            entry.insert(field_id);
 +                        }
 +                        return None;
 +                    }
 +                    // can't have `write_field_resolution` here because `self.table` is borrowed :(
 +                    self.result.field_resolutions.insert(tgt_expr, field_id);
 +                    let ty = self.db.field_types(field_id.parent)[field_id.local_id]
 +                        .clone()
 +                        .substitute(Interner, &parameters);
 +                    Some(ty)
 +                });
 +                let ty = match ty {
 +                    Some(ty) => {
 +                        let adjustments = auto_deref_adjust_steps(&autoderef);
 +                        self.write_expr_adj(*expr, adjustments);
 +                        let ty = self.insert_type_vars(ty);
 +                        let ty = self.normalize_associated_types_in(ty);
 +                        ty
 +                    }
 +                    _ => self.err_ty(),
 +                };
 +                ty
 +            }
 +            Expr::Await { expr } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
 +            }
 +            Expr::Try { expr } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
 +            }
 +            Expr::Cast { expr, type_ref } => {
 +                // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
 +                let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let cast_ty = self.make_ty(type_ref);
 +                // FIXME check the cast...
 +                cast_ty
 +            }
 +            Expr::Ref { expr, rawness, mutability } => {
 +                let mutability = lower_to_chalk_mutability(*mutability);
 +                let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .and_then(|t| t.as_reference_or_ptr())
 +                {
 +                    if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
 +                        // FIXME: record type error - expected mut reference but found shared ref,
 +                        // which cannot be coerced
 +                    }
 +                    if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
 +                        // FIXME: record type error - expected reference but found ptr,
 +                        // which cannot be coerced
 +                    }
 +                    Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
 +                } else {
 +                    Expectation::none()
 +                };
 +                let inner_ty = self.infer_expr_inner(*expr, &expectation);
 +                match rawness {
 +                    Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
 +                    Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
 +                }
 +                .intern(Interner)
 +            }
 +            &Expr::Box { expr } => self.infer_expr_box(expr, expected),
 +            Expr::UnaryOp { expr, op } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let inner_ty = self.resolve_ty_shallow(&inner_ty);
 +                match op {
 +                    UnaryOp::Deref => {
 +                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
 +                    }
 +                    UnaryOp::Neg => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
 +                            | TyKind::InferenceVar(
 +                                _,
 +                                TyVariableKind::Integer | TyVariableKind::Float,
 +                            ) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Neg trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
 +                        }
 +                    }
 +                    UnaryOp::Not => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
 +                            | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Not trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
 +                        }
 +                    }
 +                }
 +            }
 +            Expr::BinaryOp { lhs, rhs, op } => match op {
 +                Some(BinaryOp::Assignment { op: None }) => {
 +                    let lhs = *lhs;
 +                    let is_ordinary = match &self.body[lhs] {
 +                        Expr::Array(_)
 +                        | Expr::RecordLit { .. }
 +                        | Expr::Tuple { .. }
 +                        | Expr::Underscore => false,
 +                        Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
 +                        _ => true,
 +                    };
 +
 +                    // In ordinary (non-destructuring) assignments, the type of
 +                    // `lhs` must be inferred first so that the ADT fields
 +                    // instantiations in RHS can be coerced to it. Note that this
 +                    // cannot happen in destructuring assignments because of how
 +                    // they are desugared.
 +                    if is_ordinary {
 +                        let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +                        self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
 +                    } else {
 +                        let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
 +                        self.infer_assignee_expr(lhs, &rhs_ty);
 +                    }
 +                    self.result.standard_types.unit.clone()
 +                }
 +                Some(BinaryOp::LogicOp(_)) => {
 +                    let bool_ty = self.result.standard_types.bool_.clone();
 +                    self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty.clone()));
 +                    let lhs_diverges = self.diverges;
 +                    self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty.clone()));
 +                    // Depending on the LHS' value, the RHS can never execute.
 +                    self.diverges = lhs_diverges;
 +                    bool_ty
 +                }
 +                Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
 +                _ => self.err_ty(),
 +            },
 +            Expr::Range { lhs, rhs, range_type } => {
 +                let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
 +                let rhs_expect = lhs_ty
 +                    .as_ref()
 +                    .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
 +                let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
 +                match (range_type, lhs_ty, rhs_ty) {
 +                    (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, None, Some(ty)) => {
 +                        match self.resolve_range_to_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, Some(_), Some(ty)) => {
 +                        match self.resolve_range_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, _, None) => self.err_ty(),
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                let base_ty = self.infer_expr_inner(*base, &Expectation::none());
 +                let index_ty = self.infer_expr(*index, &Expectation::none());
 +
 +                if let Some(index_trait) = self.resolve_ops_index() {
 +                    let canonicalized = self.canonicalize(base_ty.clone());
 +                    let receiver_adjustments = method_resolution::resolve_indexing_op(
 +                        self.db,
 +                        self.trait_env.clone(),
 +                        canonicalized.value,
 +                        index_trait,
 +                    );
 +                    let (self_ty, adj) = receiver_adjustments
 +                        .map_or((self.err_ty(), Vec::new()), |adj| {
 +                            adj.apply(&mut self.table, base_ty)
 +                        });
 +                    self.write_expr_adj(*base, adj);
 +                    self.resolve_associated_type_with_params(
 +                        self_ty,
 +                        self.resolve_ops_index_output(),
 +                        &[GenericArgData::Ty(index_ty).intern(Interner)],
 +                    )
 +                } else {
 +                    self.err_ty()
 +                }
 +            }
-                     Array::ElementList(items) => {
-                         for &expr in items.iter() {
++            Expr::Tuple { exprs, .. } => {
 +                let mut tys = match expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .map(|t| t.kind(Interner))
 +                {
 +                    Some(TyKind::Tuple(_, substs)) => substs
 +                        .iter(Interner)
 +                        .map(|a| a.assert_ty_ref(Interner).clone())
 +                        .chain(repeat_with(|| self.table.new_type_var()))
 +                        .take(exprs.len())
 +                        .collect::<Vec<_>>(),
 +                    _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
 +                };
 +
 +                for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +
 +                TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
 +            }
 +            Expr::Array(array) => {
 +                let elem_ty =
 +                    match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) {
 +                        Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
 +                        _ => self.table.new_type_var(),
 +                    };
 +                let mut coerce = CoerceMany::new(elem_ty.clone());
 +
 +                let expected = Expectation::has_type(elem_ty.clone());
 +                let len = match array {
-                         consteval::usize_const(Some(items.len() as u128))
++                    Array::ElementList { elements, .. } => {
++                        for &expr in elements.iter() {
 +                            let cur_elem_ty = self.infer_expr_inner(expr, &expected);
 +                            coerce.coerce(self, Some(expr), &cur_elem_ty);
 +                        }
-             Expr::Tuple { exprs } => {
++                        consteval::usize_const(Some(elements.len() as u128))
 +                    }
 +                    &Array::Repeat { initializer, repeat } => {
 +                        self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
 +                        self.infer_expr(
 +                            repeat,
 +                            &Expectation::has_type(
 +                                TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
 +                            ),
 +                        );
 +
 +                        if let Some(g_def) = self.owner.as_generic_def_id() {
 +                            let generics = generics(self.db.upcast(), g_def);
 +                            consteval::eval_to_const(
 +                                repeat,
 +                                ParamLoweringMode::Placeholder,
 +                                self,
 +                                || generics,
 +                                DebruijnIndex::INNERMOST,
 +                            )
 +                        } else {
 +                            consteval::usize_const(None)
 +                        }
 +                    }
 +                };
 +
 +                TyKind::Array(coerce.complete(), len).intern(Interner)
 +            }
 +            Expr::Literal(lit) => match lit {
 +                Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +                Literal::String(..) => {
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
 +                        .intern(Interner)
 +                }
 +                Literal::ByteString(bs) => {
 +                    let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
 +
 +                    let len = consteval::usize_const(Some(bs.len() as u128));
 +
 +                    let array_type = TyKind::Array(byte_type, len).intern(Interner);
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
 +                }
 +                Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
 +                Literal::Int(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Uint(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Float(_v, ty) => match ty {
 +                    Some(float_ty) => {
 +                        TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_float_var(),
 +                },
 +            },
 +            Expr::MacroStmts { tail, statements } => {
 +                self.infer_block(tgt_expr, statements, *tail, expected)
 +            }
 +            Expr::Underscore => {
 +                // Underscore expressions may only appear in assignee expressions,
 +                // which are handled by `infer_assignee_expr()`, so any underscore
 +                // expression reaching this branch is an error.
 +                self.err_ty()
 +            }
 +        };
 +        // use a new type variable if we got unknown here
 +        let ty = self.insert_type_vars_shallow(ty);
 +        self.write_expr_ty(tgt_expr, ty.clone());
 +        if self.resolve_ty_shallow(&ty).is_never() {
 +            // Any expression that produces a value of type `!` must have diverged
 +            self.diverges = Diverges::Always;
 +        }
 +        ty
 +    }
 +
 +    fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
 +        if let Some(box_id) = self.resolve_boxed_box() {
 +            let table = &mut self.table;
 +            let inner_exp = expected
 +                .to_option(table)
 +                .as_ref()
 +                .map(|e| e.as_adt())
 +                .flatten()
 +                .filter(|(e_adt, _)| e_adt == &box_id)
 +                .map(|(_, subts)| {
 +                    let g = subts.at(Interner, 0);
 +                    Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
 +                })
 +                .unwrap_or_else(Expectation::none);
 +
 +            let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp);
 +            TyBuilder::adt(self.db, box_id)
 +                .push(inner_ty)
 +                .fill_with_defaults(self.db, || self.table.new_type_var())
 +                .build()
 +        } else {
 +            self.err_ty()
 +        }
 +    }
 +
 +    pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
 +        let is_rest_expr = |expr| {
 +            matches!(
 +                &self.body[expr],
 +                Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
 +            )
 +        };
 +
 +        let rhs_ty = self.resolve_ty_shallow(rhs_ty);
 +
 +        let ty = match &self.body[lhs] {
-             Expr::Call { callee, args } => {
++            Expr::Tuple { exprs, .. } => {
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = exprs.iter().position(|e| is_rest_expr(*e));
 +                let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
 +            }
-             Expr::Array(Array::ElementList(elements)) => {
++            Expr::Call { callee, args, .. } => {
 +                // Tuple structs
 +                let path = match &self.body[*callee] {
 +                    Expr::Path(path) => Some(path),
 +                    _ => None,
 +                };
 +
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = args.iter().position(|e| is_rest_expr(*e));
 +                let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
 +            }
++            Expr::Array(Array::ElementList { elements, .. }) => {
 +                let elem_ty = match rhs_ty.kind(Interner) {
 +                    TyKind::Array(st, _) => st.clone(),
 +                    _ => self.err_ty(),
 +                };
 +
 +                // There's no need to handle `..` as it cannot be bound.
 +                let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
 +
 +                for e in sub_exprs {
 +                    self.infer_assignee_expr(*e, &elem_ty);
 +                }
 +
 +                match rhs_ty.kind(Interner) {
 +                    TyKind::Array(_, _) => rhs_ty.clone(),
 +                    // Even when `rhs_ty` is not an array type, this assignee
 +                    // expression is inferred to be an array (of unknown element
 +                    // type and length). This should not be just an error type,
 +                    // because we are to compute the unifiability of this type and
 +                    // `rhs_ty` in the end of this function to issue type mismatches.
 +                    _ => TyKind::Array(self.err_ty(), crate::consteval::usize_const(None))
 +                        .intern(Interner),
 +                }
 +            }
 +            Expr::RecordLit { path, fields, .. } => {
 +                let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
 +
 +                self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs)
 +            }
 +            Expr::Underscore => rhs_ty.clone(),
 +            _ => {
 +                // `lhs` is a place expression, a unit struct, or an enum variant.
 +                let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +
 +                // This is the only branch where this function may coerce any type.
 +                // We are returning early to avoid the unifiability check below.
 +                let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
 +                let ty = match self.coerce(None, &rhs_ty, &lhs_ty) {
 +                    Ok(ty) => ty,
 +                    Err(_) => {
 +                        self.result.type_mismatches.insert(
 +                            lhs.into(),
 +                            TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
 +                        );
 +                        // `rhs_ty` is returned so no further type mismatches are
 +                        // reported because of this mismatch.
 +                        rhs_ty
 +                    }
 +                };
 +                self.write_expr_ty(lhs, ty.clone());
 +                return ty;
 +            }
 +        };
 +
 +        let ty = self.insert_type_vars_shallow(ty);
 +        if !self.unify(&ty, &rhs_ty) {
 +            self.result
 +                .type_mismatches
 +                .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
 +        }
 +        self.write_expr_ty(lhs, ty.clone());
 +        ty
 +    }
 +
 +    fn infer_overloadable_binop(
 +        &mut self,
 +        lhs: ExprId,
 +        op: BinaryOp,
 +        rhs: ExprId,
 +        tgt_expr: ExprId,
 +    ) -> Ty {
 +        let lhs_expectation = Expectation::none();
 +        let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
 +        let rhs_ty = self.table.new_type_var();
 +
 +        let func = self.resolve_binop_method(op);
 +        let func = match func {
 +            Some(func) => func,
 +            None => {
 +                let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
 +                let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
 +                return self
 +                    .builtin_binary_op_return_ty(op, lhs_ty, rhs_ty)
 +                    .unwrap_or_else(|| self.err_ty());
 +            }
 +        };
 +
 +        let subst = TyBuilder::subst_for_def(self.db, func)
 +            .push(lhs_ty.clone())
 +            .push(rhs_ty.clone())
 +            .build();
 +        self.write_method_resolution(tgt_expr, func, subst.clone());
 +
 +        let method_ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
 +        self.register_obligations_for_call(&method_ty);
 +
 +        self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()));
 +
 +        let ret_ty = match method_ty.callable_sig(self.db) {
 +            Some(sig) => sig.ret().clone(),
 +            None => self.err_ty(),
 +        };
 +
 +        let ret_ty = self.normalize_associated_types_in(ret_ty);
 +
 +        // FIXME: record autoref adjustments
 +
 +        // use knowledge of built-in binary ops, which can sometimes help inference
 +        if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) {
 +            self.unify(&builtin_rhs, &rhs_ty);
 +        }
 +        if let Some(builtin_ret) = self.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) {
 +            self.unify(&builtin_ret, &ret_ty);
 +        }
 +
 +        ret_ty
 +    }
 +
 +    fn infer_block(
 +        &mut self,
 +        expr: ExprId,
 +        statements: &[Statement],
 +        tail: Option<ExprId>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        for stmt in statements {
 +            match stmt {
 +                Statement::Let { pat, type_ref, initializer, else_branch } => {
 +                    let decl_ty = type_ref
 +                        .as_ref()
 +                        .map(|tr| self.make_ty(tr))
 +                        .unwrap_or_else(|| self.err_ty());
 +
 +                    // Always use the declared type when specified
 +                    let mut ty = decl_ty.clone();
 +
 +                    if let Some(expr) = initializer {
 +                        let actual_ty =
 +                            self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
 +                        if decl_ty.is_unknown() {
 +                            ty = actual_ty;
 +                        }
 +                    }
 +
 +                    if let Some(expr) = else_branch {
 +                        self.infer_expr_coerce(
 +                            *expr,
 +                            &Expectation::has_type(Ty::new(Interner, TyKind::Never)),
 +                        );
 +                    }
 +
 +                    self.infer_pat(*pat, &ty, BindingMode::default());
 +                }
 +                Statement::Expr { expr, .. } => {
 +                    self.infer_expr(*expr, &Expectation::none());
 +                }
 +            }
 +        }
 +
 +        if let Some(expr) = tail {
 +            self.infer_expr_coerce(expr, expected)
 +        } else {
 +            // Citing rustc: if there is no explicit tail expression,
 +            // that is typically equivalent to a tail expression
 +            // of `()` -- except if the block diverges. In that
 +            // case, there is no value supplied from the tail
 +            // expression (assuming there are no other breaks,
 +            // this implies that the type of the block will be
 +            // `!`).
 +            if self.diverges.is_always() {
 +                // we don't even make an attempt at coercion
 +                self.table.new_maybe_never_var()
 +            } else {
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            expr.into(),
 +                            TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
 +                        );
 +                    }
 +                    t
 +                } else {
 +                    TyBuilder::unit()
 +                }
 +            }
 +        }
 +    }
 +
 +    fn infer_method_call(
 +        &mut self,
 +        tgt_expr: ExprId,
 +        receiver: ExprId,
 +        args: &[ExprId],
 +        method_name: &Name,
 +        generic_args: Option<&GenericArgs>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        let receiver_ty = self.infer_expr(receiver, &Expectation::none());
 +        let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
 +
 +        let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
 +
 +        let resolved = method_resolution::lookup_method(
 +            &canonicalized_receiver.value,
 +            self.db,
 +            self.trait_env.clone(),
 +            &traits_in_scope,
 +            VisibleFromModule::Filter(self.resolver.module()),
 +            method_name,
 +        );
 +        let (receiver_ty, method_ty, substs) = match resolved {
 +            Some((adjust, func)) => {
 +                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
 +                let generics = generics(self.db.upcast(), func.into());
 +                let substs = self.substs_for_method_call(generics, generic_args);
 +                self.write_expr_adj(receiver, adjustments);
 +                self.write_method_resolution(tgt_expr, func, substs.clone());
 +                (ty, self.db.value_ty(func.into()), substs)
 +            }
 +            None => (
 +                receiver_ty,
 +                Binders::empty(Interner, self.err_ty()),
 +                Substitution::empty(Interner),
 +            ),
 +        };
 +        let method_ty = method_ty.substitute(Interner, &substs);
 +        self.register_obligations_for_call(&method_ty);
 +        let (formal_receiver_ty, param_tys, ret_ty, is_varargs) =
 +            match method_ty.callable_sig(self.db) {
 +                Some(sig) => {
 +                    if !sig.params().is_empty() {
 +                        (
 +                            sig.params()[0].clone(),
 +                            sig.params()[1..].to_vec(),
 +                            sig.ret().clone(),
 +                            sig.is_varargs,
 +                        )
 +                    } else {
 +                        (self.err_ty(), Vec::new(), sig.ret().clone(), sig.is_varargs)
 +                    }
 +                }
 +                None => (self.err_ty(), Vec::new(), self.err_ty(), true),
 +            };
 +        self.unify(&formal_receiver_ty, &receiver_ty);
 +
 +        let expected_inputs =
 +            self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone());
 +
 +        self.check_call_arguments(tgt_expr, args, &expected_inputs, &param_tys, &[], is_varargs);
 +        self.normalize_associated_types_in(ret_ty)
 +    }
 +
 +    fn expected_inputs_for_expected_output(
 +        &mut self,
 +        expected_output: &Expectation,
 +        output: Ty,
 +        inputs: Vec<Ty>,
 +    ) -> Vec<Ty> {
 +        if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
 +            self.table.fudge_inference(|table| {
 +                if table.try_unify(&expected_ty, &output).is_ok() {
 +                    table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind {
 +                        chalk_ir::VariableKind::Ty(tk) => var.to_ty(Interner, tk).cast(Interner),
 +                        chalk_ir::VariableKind::Lifetime => {
 +                            var.to_lifetime(Interner).cast(Interner)
 +                        }
 +                        chalk_ir::VariableKind::Const(ty) => {
 +                            var.to_const(Interner, ty).cast(Interner)
 +                        }
 +                    })
 +                } else {
 +                    Vec::new()
 +                }
 +            })
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    fn check_call_arguments(
 +        &mut self,
 +        expr: ExprId,
 +        args: &[ExprId],
 +        expected_inputs: &[Ty],
 +        param_tys: &[Ty],
 +        skip_indices: &[u32],
 +        is_varargs: bool,
 +    ) {
 +        if args.len() != param_tys.len() + skip_indices.len() && !is_varargs {
 +            self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount {
 +                call_expr: expr,
 +                expected: param_tys.len() + skip_indices.len(),
 +                found: args.len(),
 +            });
 +        }
 +
 +        // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
 +        // We do this in a pretty awful way: first we type-check any arguments
 +        // that are not closures, then we type-check the closures. This is so
 +        // that we have more information about the types of arguments when we
 +        // type-check the functions. This isn't really the right way to do this.
 +        for &check_closures in &[false, true] {
 +            let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable();
 +            let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty()));
 +            let expected_iter = expected_inputs
 +                .iter()
 +                .cloned()
 +                .chain(param_iter.clone().skip(expected_inputs.len()));
 +            for (idx, ((&arg, param_ty), expected_ty)) in
 +                args.iter().zip(param_iter).zip(expected_iter).enumerate()
 +            {
 +                let is_closure = matches!(&self.body[arg], Expr::Closure { .. });
 +                if is_closure != check_closures {
 +                    continue;
 +                }
 +
 +                while skip_indices.peek().map_or(false, |i| *i < idx as u32) {
 +                    skip_indices.next();
 +                }
 +                if skip_indices.peek().copied() == Some(idx as u32) {
 +                    continue;
 +                }
 +
 +                // the difference between param_ty and expected here is that
 +                // expected is the parameter when the expected *return* type is
 +                // taken into account. So in `let _: &[i32] = identity(&[1, 2])`
 +                // the expected type is already `&[i32]`, whereas param_ty is
 +                // still an unbound type variable. We don't always want to force
 +                // the parameter to coerce to the expected type (for example in
 +                // `coerce_unsize_expected_type_4`).
 +                let param_ty = self.normalize_associated_types_in(param_ty);
 +                let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
 +                // infer with the expected type we have...
 +                let ty = self.infer_expr_inner(arg, &expected);
 +
 +                // then coerce to either the expected type or just the formal parameter type
 +                let coercion_target = if let Some(ty) = expected.only_has_type(&mut self.table) {
 +                    // if we are coercing to the expectation, unify with the
 +                    // formal parameter type to connect everything
 +                    self.unify(&ty, &param_ty);
 +                    ty
 +                } else {
 +                    param_ty
 +                };
 +                if !coercion_target.is_unknown() {
 +                    if self.coerce(Some(arg), &ty, &coercion_target).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            arg.into(),
 +                            TypeMismatch { expected: coercion_target, actual: ty.clone() },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn substs_for_method_call(
 +        &mut self,
 +        def_generics: Generics,
 +        generic_args: Option<&GenericArgs>,
 +    ) -> Substitution {
 +        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
 +            def_generics.provenance_split();
 +        assert_eq!(self_params, 0); // method shouldn't have another Self param
 +        let total_len = parent_params + type_params + const_params + impl_trait_params;
 +        let mut substs = Vec::with_capacity(total_len);
 +        // Parent arguments are unknown
 +        for (id, param) in def_generics.iter_parent() {
 +            match param {
 +                TypeOrConstParamData::TypeParamData(_) => {
 +                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
 +                }
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
 +                    substs
 +                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
 +                }
 +            }
 +        }
 +        // handle provided arguments
 +        if let Some(generic_args) = generic_args {
 +            // if args are provided, it should be all of them, but we can't rely on that
 +            for (arg, kind_id) in generic_args
 +                .args
 +                .iter()
 +                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
 +                .take(type_params + const_params)
 +                .zip(def_generics.iter_id().skip(parent_params))
 +            {
 +                if let Some(g) = generic_arg_to_chalk(
 +                    self.db,
 +                    kind_id,
 +                    arg,
 +                    self,
 +                    |this, type_ref| this.make_ty(type_ref),
 +                    |this, c, ty| {
 +                        const_or_path_to_chalk(
 +                            this.db,
 +                            &this.resolver,
 +                            ty,
 +                            c,
 +                            ParamLoweringMode::Placeholder,
 +                            || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
 +                            DebruijnIndex::INNERMOST,
 +                        )
 +                    },
 +                ) {
 +                    substs.push(g);
 +                }
 +            }
 +        };
 +        for (id, data) in def_generics.iter().skip(substs.len()) {
 +            match data {
 +                TypeOrConstParamData::TypeParamData(_) => {
 +                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner))
 +                }
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    substs.push(
 +                        GenericArgData::Const(self.table.new_const_var(
 +                            self.db.const_param_ty(ConstParamId::from_unchecked(id)),
 +                        ))
 +                        .intern(Interner),
 +                    )
 +                }
 +            }
 +        }
 +        assert_eq!(substs.len(), total_len);
 +        Substitution::from_iter(Interner, substs)
 +    }
 +
 +    fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
 +        let callable_ty = self.resolve_ty_shallow(callable_ty);
 +        if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
 +            let def: CallableDefId = from_chalk(self.db, *fn_def);
 +            let generic_predicates = self.db.generic_predicates(def.into());
 +            for predicate in generic_predicates.iter() {
 +                let (predicate, binders) = predicate
 +                    .clone()
 +                    .substitute(Interner, parameters)
 +                    .into_value_and_skipped_binders();
 +                always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                self.push_obligation(predicate.cast(Interner));
 +            }
 +            // add obligation for trait implementation, if this is a trait method
 +            match def {
 +                CallableDefId::FunctionId(f) => {
 +                    if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
 +                        // construct a TraitRef
 +                        let substs = crate::subst_prefix(
 +                            &*parameters,
 +                            generics(self.db.upcast(), trait_.into()).len(),
 +                        );
 +                        self.push_obligation(
 +                            TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
 +                                .cast(Interner),
 +                        );
 +                    }
 +                }
 +                CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
 +            }
 +        }
 +    }
 +
 +    /// Returns the argument indices to skip.
 +    fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> {
 +        let (func, subst) = match callee.kind(Interner) {
 +            TyKind::FnDef(fn_id, subst) => {
 +                let callable = CallableDefId::from_chalk(self.db, *fn_id);
 +                let func = match callable {
 +                    CallableDefId::FunctionId(f) => f,
 +                    _ => return Default::default(),
 +                };
 +                (func, subst)
 +            }
 +            _ => return Default::default(),
 +        };
 +
 +        let data = self.db.function_data(func);
 +        if data.legacy_const_generics_indices.is_empty() {
 +            return Default::default();
 +        }
 +
 +        // only use legacy const generics if the param count matches with them
 +        if data.params.len() + data.legacy_const_generics_indices.len() != args.len() {
 +            if args.len() <= data.params.len() {
 +                return Default::default();
 +            } else {
 +                // there are more parameters than there should be without legacy
 +                // const params; use them
 +                let mut indices = data.legacy_const_generics_indices.clone();
 +                indices.sort();
 +                return indices;
 +            }
 +        }
 +
 +        // check legacy const parameters
 +        for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() {
 +            let arg = match subst.at(Interner, subst_idx).constant(Interner) {
 +                Some(c) => c,
 +                None => continue, // not a const parameter?
 +            };
 +            if arg_idx >= args.len() as u32 {
 +                continue;
 +            }
 +            let _ty = arg.data(Interner).ty.clone();
 +            let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
 +            self.infer_expr(args[arg_idx as usize], &expected);
 +            // FIXME: evaluate and unify with the const
 +        }
 +        let mut indices = data.legacy_const_generics_indices.clone();
 +        indices.sort();
 +        indices
 +    }
 +
 +    fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
 +        let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
 +        let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
 +        match op {
 +            BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
 +                Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
 +            }
 +            BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
 +                // all integer combinations are valid here
 +                if matches!(
 +                    lhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) && matches!(
 +                    rhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) {
 +                    Some(lhs_ty)
 +                } else {
 +                    None
 +                }
 +            }
 +            BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
 +                // (int, int) | (uint, uint) | (float, float)
 +                (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
 +                | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
 +                | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
 +                    Some(rhs_ty)
 +                }
 +                // ({int}, int) | ({int}, uint)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                ) => Some(rhs_ty),
 +                // (int, {int}) | (uint, {int})
 +                (
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                ) => Some(lhs_ty),
 +                // ({float} | float)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                ) => Some(rhs_ty),
 +                // (float, {float})
 +                (
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(lhs_ty),
 +                // ({int}, {int}) | ({float}, {float})
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                )
 +                | (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(rhs_ty),
 +                _ => None,
 +            },
 +        }
 +    }
 +
 +    fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
 +        Some(match op {
 +            BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            BinaryOp::Assignment { op: None } => lhs_ty,
 +            BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
 +                .resolve_ty_shallow(&lhs_ty)
 +                .kind(Interner)
 +            {
 +                TyKind::Scalar(_) | TyKind::Str => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
 +            BinaryOp::CmpOp(CmpOp::Ord { .. })
 +            | BinaryOp::Assignment { op: Some(_) }
 +            | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
 +                TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +        })
 +    }
 +
 +    fn resolve_binop_method(&self, op: BinaryOp) -> Option<FunctionId> {
 +        let (name, lang_item) = 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,
 +        };
 +
 +        let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?;
 +
 +        self.db.trait_data(trait_).method_by_name(&name)
 +    }
 +}
index 9ffbb3964cf1134e5c89193a7bb9f2238ef5da4b,0000000000000000000000000000000000000000..d4925455d7bd2dcf4c7d90df5a0d2d6bfb41e9bc
mode 100644,000000..100644
--- /dev/null
@@@ -1,3609 -1,0 +1,3635 @@@
 +//! 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,
 +    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,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
 +use stdx::{format_to, 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()
 +    }
 +
 +    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)
 +                    }
 +                }
 +                _ => acc.extend(decl.diagnostics(db)),
 +            }
 +        }
 +
 +        for impl_def in self.impl_defs(db) {
 +            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.
 +    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())
 +    }
 +
 +    /// 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,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
 +    }
 +}
 +
 +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),
 +        }
 +    }
 +
 +    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 } => {
 +                    let expr = source_map
 +                        .expr_syntax(*expr)
 +                        .expect("break outside of loop in synthetic syntax");
 +                    acc.push(BreakOutsideOfLoop { expr }.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() })
 +    }
 +
 +    /// A textual representation of the HIR of this function for debugging purposes.
 +    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
 +        let body = db.body(self.id.into());
 +
 +        let mut result = String::new();
 +        format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
 +        for (id, expr) in body.exprs.iter() {
 +            format_to!(result, "{:?}: {:?}\n", id, expr);
 +        }
 +
 +        result
 +    }
 +}
 +
 +// 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 is_unknown(&self) -> bool {
 +        self.ty.is_unknown()
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::future::Future`.
 +    /// This function is used in `.await` syntax completion.
 +    pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
 +        let std_future_trait = db
 +            .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
 +            .and_then(|it| it.as_trait());
 +        let std_future_trait = match std_future_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(), std_future_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();
 +        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(),
 +        );
 +
 +        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,
 +        }
 +    }
 +
 +    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 043f2b7c24dcb42adbf82307e9341543d5f91460,0000000000000000000000000000000000000000..fc8f23f19ab9112839303e2f33c022e056567891
mode 100644,000000..100644
--- /dev/null
@@@ -1,1481 -1,0 +1,1517 @@@
-     Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
-     HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
-     ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
 +//! See `Semantics`.
 +
 +mod source_to_def;
 +
 +use std::{cell::RefCell, fmt, iter, ops};
 +
 +use base_db::{FileId, FileRange};
 +use hir_def::{
 +    body, macro_id_to_def_id,
 +    resolver::{self, HasResolver, Resolver, TypeNs},
 +    type_ref::Mutability,
 +    AsMacroCall, FunctionId, MacroId, TraitId, VariantId,
 +};
 +use hir_expand::{
 +    db::AstDatabase,
 +    name::{known, AsName},
 +    ExpansionInfo, MacroCallId,
 +};
 +use itertools::Itertools;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use smallvec::{smallvec, SmallVec};
 +use syntax::{
 +    algo::skip_trivia_token,
 +    ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
 +    match_ast, AstNode, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
 +};
 +
 +use crate::{
 +    db::HirDatabase,
 +    semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
 +    source_analyzer::{resolve_hir_path, SourceAnalyzer},
-                 // are we inside an attribute macro call
++    Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function,
++    HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
++    Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
 +};
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub enum PathResolution {
 +    /// An item
 +    Def(ModuleDef),
 +    /// A local binding (only value namespace)
 +    Local(Local),
 +    /// A type parameter
 +    TypeParam(TypeParam),
 +    /// A const parameter
 +    ConstParam(ConstParam),
 +    SelfType(Impl),
 +    BuiltinAttr(BuiltinAttr),
 +    ToolModule(ToolModule),
++    DeriveHelper(DeriveHelper),
 +}
 +
 +impl PathResolution {
 +    pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
 +        match self {
 +            PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
 +            PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
 +                Some(TypeNs::BuiltinType((*builtin).into()))
 +            }
 +            PathResolution::Def(
 +                ModuleDef::Const(_)
 +                | ModuleDef::Variant(_)
 +                | ModuleDef::Macro(_)
 +                | ModuleDef::Function(_)
 +                | ModuleDef::Module(_)
 +                | ModuleDef::Static(_)
 +                | ModuleDef::Trait(_),
 +            ) => None,
 +            PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
 +                Some(TypeNs::TypeAliasId((*alias).into()))
 +            }
 +            PathResolution::BuiltinAttr(_)
 +            | PathResolution::ToolModule(_)
 +            | PathResolution::Local(_)
++            | PathResolution::DeriveHelper(_)
 +            | PathResolution::ConstParam(_) => None,
 +            PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
 +            PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct TypeInfo {
 +    /// The original type of the expression or pattern.
 +    pub original: Type,
 +    /// The adjusted type, if an adjustment happened.
 +    pub adjusted: Option<Type>,
 +}
 +
 +impl TypeInfo {
 +    pub fn original(self) -> Type {
 +        self.original
 +    }
 +
 +    pub fn has_adjustment(&self) -> bool {
 +        self.adjusted.is_some()
 +    }
 +
 +    /// The adjusted type, or the original in case no adjustments occurred.
 +    pub fn adjusted(self) -> Type {
 +        self.adjusted.unwrap_or(self.original)
 +    }
 +}
 +
 +/// Primary API to get semantic information, like types, from syntax trees.
 +pub struct Semantics<'db, DB> {
 +    pub db: &'db DB,
 +    imp: SemanticsImpl<'db>,
 +}
 +
 +pub struct SemanticsImpl<'db> {
 +    pub db: &'db dyn HirDatabase,
 +    s2d_cache: RefCell<SourceToDefCache>,
 +    expansion_info_cache: RefCell<FxHashMap<HirFileId, Option<ExpansionInfo>>>,
 +    // Rootnode to HirFileId cache
 +    cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
 +    // MacroCall to its expansion's HirFileId cache
 +    macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, HirFileId>>,
 +}
 +
 +impl<DB> fmt::Debug for Semantics<'_, DB> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "Semantics {{ ... }}")
 +    }
 +}
 +
 +impl<'db, DB: HirDatabase> Semantics<'db, DB> {
 +    pub fn new(db: &DB) -> Semantics<'_, DB> {
 +        let impl_ = SemanticsImpl::new(db);
 +        Semantics { db, imp: impl_ }
 +    }
 +
 +    pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
 +        self.imp.parse(file_id)
 +    }
 +
 +    pub fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
 +        self.imp.parse_or_expand(file_id)
 +    }
 +
 +    pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
 +        self.imp.expand(macro_call)
 +    }
 +
 +    /// If `item` has an attribute macro attached to it, expands it.
 +    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
 +        self.imp.expand_attr_macro(item)
 +    }
 +
 +    pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
 +        self.imp.expand_derive_as_pseudo_attr_macro(attr)
 +    }
 +
 +    pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<Macro>>> {
 +        self.imp.resolve_derive_macro(derive)
 +    }
 +
 +    pub fn expand_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<SyntaxNode>> {
 +        self.imp.expand_derive_macro(derive)
 +    }
 +
 +    pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
 +        self.imp.is_attr_macro_call(item)
 +    }
 +
 +    pub fn is_derive_annotated(&self, item: &ast::Adt) -> bool {
 +        self.imp.is_derive_annotated(item)
 +    }
 +
 +    pub fn speculative_expand(
 +        &self,
 +        actual_macro_call: &ast::MacroCall,
 +        speculative_args: &ast::TokenTree,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map)
 +    }
 +
 +    pub fn speculative_expand_attr_macro(
 +        &self,
 +        actual_macro_call: &ast::Item,
 +        speculative_args: &ast::Item,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map)
 +    }
 +
 +    pub fn speculative_expand_derive_as_pseudo_attr_macro(
 +        &self,
 +        actual_macro_call: &ast::Attr,
 +        speculative_args: &ast::Attr,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        self.imp.speculative_expand_derive_as_pseudo_attr_macro(
 +            actual_macro_call,
 +            speculative_args,
 +            token_to_map,
 +        )
 +    }
 +
 +    /// Descend the token into macrocalls to its first mapped counterpart.
 +    pub fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
 +        self.imp.descend_into_macros_single(token)
 +    }
 +
 +    /// Descend the token into macrocalls to all its mapped counterparts.
 +    pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
 +        self.imp.descend_into_macros(token)
 +    }
 +
 +    /// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token.
 +    ///
 +    /// Returns the original non descended token if none of the mapped counterparts have the same text.
 +    pub fn descend_into_macros_with_same_text(
 +        &self,
 +        token: SyntaxToken,
 +    ) -> SmallVec<[SyntaxToken; 1]> {
 +        self.imp.descend_into_macros_with_same_text(token)
 +    }
 +
 +    pub fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
 +        self.imp.descend_into_macros_with_kind_preference(token)
 +    }
 +
 +    /// Maps a node down by mapping its first and last token down.
 +    pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
 +        self.imp.descend_node_into_attributes(node)
 +    }
 +
 +    /// Search for a definition's source and cache its syntax tree
 +    pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
 +    where
 +        Def::Ast: AstNode,
 +    {
 +        self.imp.source(def)
 +    }
 +
 +    pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
 +        self.imp.find_file(syntax_node).file_id
 +    }
 +
 +    /// Attempts to map the node out of macro expanded files returning the original file range.
 +    /// If upmapping is not possible, this will fall back to the range of the macro call of the
 +    /// macro file the node resides in.
 +    pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
 +        self.imp.original_range(node)
 +    }
 +
 +    /// Attempts to map the node out of macro expanded files returning the original file range.
 +    pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
 +        self.imp.original_range_opt(node)
 +    }
 +
 +    /// Attempts to map the node out of macro expanded files.
 +    /// This only work for attribute expansions, as other ones do not have nodes as input.
 +    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
 +        self.imp.original_ast_node(node)
 +    }
 +
 +    pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
 +        self.imp.diagnostics_display_range(diagnostics)
 +    }
 +
 +    pub fn token_ancestors_with_macros(
 +        &self,
 +        token: SyntaxToken,
 +    ) -> impl Iterator<Item = SyntaxNode> + '_ {
 +        token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
 +    }
 +
 +    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
 +    pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
 +        self.imp.ancestors_with_macros(node)
 +    }
 +
 +    pub fn ancestors_at_offset_with_macros(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> impl Iterator<Item = SyntaxNode> + '_ {
 +        self.imp.ancestors_at_offset_with_macros(node, offset)
 +    }
 +
 +    /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
 +    /// search up until it is of the target AstNode type
 +    pub fn find_node_at_offset_with_macros<N: AstNode>(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> Option<N> {
 +        self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
 +    }
 +
 +    /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
 +    /// descend it and find again
 +    pub fn find_node_at_offset_with_descend<N: AstNode>(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> Option<N> {
 +        self.imp.descend_node_at_offset(node, offset).flatten().find_map(N::cast)
 +    }
 +
 +    /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
 +    /// descend it and find again
 +    pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>(
 +        &'slf self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> impl Iterator<Item = N> + 'slf {
 +        self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
 +    }
 +
 +    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
 +        self.imp.resolve_lifetime_param(lifetime)
 +    }
 +
 +    pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
 +        self.imp.resolve_label(lifetime)
 +    }
 +
 +    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
 +        self.imp.resolve_type(ty)
 +    }
 +
 +    // FIXME: Figure out a nice interface to inspect adjustments
 +    pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
 +        self.imp.is_implicit_reborrow(expr)
 +    }
 +
 +    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
 +        self.imp.type_of_expr(expr)
 +    }
 +
 +    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
 +        self.imp.type_of_pat(pat)
 +    }
 +
 +    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
 +        self.imp.type_of_self(param)
 +    }
 +
 +    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
 +        self.imp.pattern_adjustments(pat)
 +    }
 +
 +    pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
 +        self.imp.binding_mode_of_pat(pat)
 +    }
 +
 +    pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
 +        self.imp.resolve_method_call(call).map(Function::from)
 +    }
 +
 +    pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
 +        self.imp.resolve_method_call_as_callable(call)
 +    }
 +
 +    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
 +        self.imp.resolve_field(field)
 +    }
 +
 +    pub fn resolve_record_field(
 +        &self,
 +        field: &ast::RecordExprField,
 +    ) -> Option<(Field, Option<Local>, Type)> {
 +        self.imp.resolve_record_field(field)
 +    }
 +
 +    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
 +        self.imp.resolve_record_pat_field(field)
 +    }
 +
 +    pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
 +        self.imp.resolve_macro_call(macro_call)
 +    }
 +
 +    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
 +        self.imp.is_unsafe_macro_call(macro_call)
 +    }
 +
 +    pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
 +        self.imp.resolve_attr_macro_call(item)
 +    }
 +
 +    pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
 +        self.imp.resolve_path(path)
 +    }
 +
 +    pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
 +        self.imp.resolve_extern_crate(extern_crate)
 +    }
 +
 +    pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
 +        self.imp.resolve_variant(record_lit).map(VariantDef::from)
 +    }
 +
 +    pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
 +        self.imp.resolve_bind_pat_to_const(pat)
 +    }
 +
 +    pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
 +        self.imp.record_literal_missing_fields(literal)
 +    }
 +
 +    pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
 +        self.imp.record_pattern_missing_fields(pattern)
 +    }
 +
 +    pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
 +        let src = self.imp.find_file(src.syntax()).with_value(src).cloned();
 +        T::to_def(&self.imp, src)
 +    }
 +
 +    pub fn to_module_def(&self, file: FileId) -> Option<Module> {
 +        self.imp.to_module_def(file).next()
 +    }
 +
 +    pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
 +        self.imp.to_module_def(file)
 +    }
 +
 +    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
 +        self.imp.scope(node)
 +    }
 +
 +    pub fn scope_at_offset(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> Option<SemanticsScope<'db>> {
 +        self.imp.scope_at_offset(node, offset)
 +    }
 +
 +    pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
 +        self.imp.scope_for_def(def)
 +    }
 +
 +    pub fn assert_contains_node(&self, node: &SyntaxNode) {
 +        self.imp.assert_contains_node(node)
 +    }
 +
 +    pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
 +        self.imp.is_unsafe_method_call(method_call_expr)
 +    }
 +
 +    pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
 +        self.imp.is_unsafe_ref_expr(ref_expr)
 +    }
 +
 +    pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
 +        self.imp.is_unsafe_ident_pat(ident_pat)
 +    }
 +}
 +
 +impl<'db> SemanticsImpl<'db> {
 +    fn new(db: &'db dyn HirDatabase) -> Self {
 +        SemanticsImpl {
 +            db,
 +            s2d_cache: Default::default(),
 +            cache: Default::default(),
 +            expansion_info_cache: Default::default(),
 +            macro_call_cache: Default::default(),
 +        }
 +    }
 +
 +    fn parse(&self, file_id: FileId) -> ast::SourceFile {
 +        let tree = self.db.parse(file_id).tree();
 +        self.cache(tree.syntax().clone(), file_id.into());
 +        tree
 +    }
 +
 +    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
 +        let node = self.db.parse_or_expand(file_id)?;
 +        self.cache(node.clone(), file_id);
 +        Some(node)
 +    }
 +
 +    fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
 +        let sa = self.analyze_no_infer(macro_call.syntax())?;
 +        let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
 +        let node = self.parse_or_expand(file_id)?;
 +        Some(node)
 +    }
 +
 +    fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
 +        let src = self.wrap_node_infile(item.clone());
 +        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
 +        self.parse_or_expand(macro_call_id.as_file())
 +    }
 +
 +    fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
 +        let src = self.wrap_node_infile(attr.clone());
 +        let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
 +        let call_id = self.with_ctx(|ctx| {
 +            ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
 +        })?;
 +        self.parse_or_expand(call_id.as_file())
 +    }
 +
 +    fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
 +        let calls = self.derive_macro_calls(attr)?;
 +        self.with_ctx(|ctx| {
 +            Some(
 +                calls
 +                    .into_iter()
 +                    .map(|call| {
 +                        macro_call_to_macro_id(ctx, self.db.upcast(), call?).map(|id| Macro { id })
 +                    })
 +                    .collect(),
 +            )
 +        })
 +    }
 +
 +    fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
 +        let res: Vec<_> = self
 +            .derive_macro_calls(attr)?
 +            .into_iter()
 +            .flat_map(|call| {
 +                let file_id = call?.as_file();
 +                let node = self.db.parse_or_expand(file_id)?;
 +                self.cache(node.clone(), file_id);
 +                Some(node)
 +            })
 +            .collect();
 +        Some(res)
 +    }
 +
 +    fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>>> {
 +        let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
 +        let file_id = self.find_file(adt.syntax()).file_id;
 +        let adt = InFile::new(file_id, &adt);
 +        let src = InFile::new(file_id, attr.clone());
 +        self.with_ctx(|ctx| {
 +            let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?;
 +            Some(res.to_vec())
 +        })
 +    }
 +
 +    fn is_derive_annotated(&self, adt: &ast::Adt) -> bool {
 +        let file_id = self.find_file(adt.syntax()).file_id;
 +        let adt = InFile::new(file_id, adt);
 +        self.with_ctx(|ctx| ctx.has_derives(adt))
 +    }
 +
 +    fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
 +        let file_id = self.find_file(item.syntax()).file_id;
 +        let src = InFile::new(file_id, item.clone());
 +        self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
 +    }
 +
 +    fn speculative_expand(
 +        &self,
 +        actual_macro_call: &ast::MacroCall,
 +        speculative_args: &ast::TokenTree,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        let SourceAnalyzer { file_id, resolver, .. } =
 +            self.analyze_no_infer(actual_macro_call.syntax())?;
 +        let macro_call = InFile::new(file_id, actual_macro_call);
 +        let krate = resolver.krate();
 +        let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
 +            resolver
 +                .resolve_path_as_macro(self.db.upcast(), &path)
 +                .map(|it| macro_id_to_def_id(self.db.upcast(), it))
 +        })?;
 +        hir_expand::db::expand_speculative(
 +            self.db.upcast(),
 +            macro_call_id,
 +            speculative_args.syntax(),
 +            token_to_map,
 +        )
 +    }
 +
 +    fn speculative_expand_attr(
 +        &self,
 +        actual_macro_call: &ast::Item,
 +        speculative_args: &ast::Item,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        let macro_call = self.wrap_node_infile(actual_macro_call.clone());
 +        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call))?;
 +        hir_expand::db::expand_speculative(
 +            self.db.upcast(),
 +            macro_call_id,
 +            speculative_args.syntax(),
 +            token_to_map,
 +        )
 +    }
 +
 +    fn speculative_expand_derive_as_pseudo_attr_macro(
 +        &self,
 +        actual_macro_call: &ast::Attr,
 +        speculative_args: &ast::Attr,
 +        token_to_map: SyntaxToken,
 +    ) -> Option<(SyntaxNode, SyntaxToken)> {
 +        let attr = self.wrap_node_infile(actual_macro_call.clone());
 +        let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
 +        let macro_call_id = self.with_ctx(|ctx| {
 +            ctx.attr_to_derive_macro_call(attr.with_value(&adt), attr).map(|(_, it, _)| it)
 +        })?;
 +        hir_expand::db::expand_speculative(
 +            self.db.upcast(),
 +            macro_call_id,
 +            speculative_args.syntax(),
 +            token_to_map,
 +        )
 +    }
 +
 +    // This might not be the correct way to do this, but it works for now
 +    fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
 +        let mut res = smallvec![];
 +        let tokens = (|| {
 +            let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?;
 +            let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?;
 +            Some((first, last))
 +        })();
 +        let (first, last) = match tokens {
 +            Some(it) => it,
 +            None => return res,
 +        };
 +
 +        if first == last {
 +            self.descend_into_macros_impl(first, &mut |InFile { value, .. }| {
 +                if let Some(node) = value.parent_ancestors().find_map(N::cast) {
 +                    res.push(node)
 +                }
 +                false
 +            });
 +        } else {
 +            // Descend first and last token, then zip them to look for the node they belong to
 +            let mut scratch: SmallVec<[_; 1]> = smallvec![];
 +            self.descend_into_macros_impl(first, &mut |token| {
 +                scratch.push(token);
 +                false
 +            });
 +
 +            let mut scratch = scratch.into_iter();
 +            self.descend_into_macros_impl(
 +                last,
 +                &mut |InFile { value: last, file_id: last_fid }| {
 +                    if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
 +                        if first_fid == last_fid {
 +                            if let Some(p) = first.parent() {
 +                                let range = first.text_range().cover(last.text_range());
 +                                let node = find_root(&p)
 +                                    .covering_element(range)
 +                                    .ancestors()
 +                                    .take_while(|it| it.text_range() == range)
 +                                    .find_map(N::cast);
 +                                if let Some(node) = node {
 +                                    res.push(node);
 +                                }
 +                            }
 +                        }
 +                    }
 +                    false
 +                },
 +            );
 +        }
 +        res
 +    }
 +
 +    fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
 +        let mut res = smallvec![];
 +        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
 +            res.push(value);
 +            false
 +        });
 +        res
 +    }
 +
 +    fn descend_into_macros_with_same_text(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
 +        let text = token.text();
 +        let mut res = smallvec![];
 +        self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
 +            if value.text() == text {
 +                res.push(value);
 +            }
 +            false
 +        });
 +        if res.is_empty() {
 +            res.push(token);
 +        }
 +        res
 +    }
 +
 +    fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
 +        let fetch_kind = |token: &SyntaxToken| match token.parent() {
 +            Some(node) => match node.kind() {
 +                kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => {
 +                    node.parent().map_or(kind, |it| it.kind())
 +                }
 +                _ => token.kind(),
 +            },
 +            None => token.kind(),
 +        };
 +        let preferred_kind = fetch_kind(&token);
 +        let mut res = None;
 +        self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
 +            if fetch_kind(&value) == preferred_kind {
 +                res = Some(value);
 +                true
 +            } else {
 +                if let None = res {
 +                    res = Some(value)
 +                }
 +                false
 +            }
 +        });
 +        res.unwrap_or(token)
 +    }
 +
 +    fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
 +        let mut res = token.clone();
 +        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
 +            res = value;
 +            true
 +        });
 +        res
 +    }
 +
 +    fn descend_into_macros_impl(
 +        &self,
 +        token: SyntaxToken,
 +        f: &mut dyn FnMut(InFile<SyntaxToken>) -> bool,
 +    ) {
 +        let _p = profile::span("descend_into_macros");
 +        let parent = match token.parent() {
 +            Some(it) => it,
 +            None => return,
 +        };
 +        let sa = match self.analyze_no_infer(&parent) {
 +            Some(it) => it,
 +            None => return,
 +        };
++        let def_map = sa.resolver.def_map();
++
 +        let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
 +        let mut cache = self.expansion_info_cache.borrow_mut();
 +        let mut mcache = self.macro_call_cache.borrow_mut();
 +
 +        let mut process_expansion_for_token =
 +            |stack: &mut SmallVec<_>, macro_file, item, token: InFile<&_>| {
 +                let expansion_info = cache
 +                    .entry(macro_file)
 +                    .or_insert_with(|| macro_file.expansion_info(self.db.upcast()))
 +                    .as_ref()?;
 +
 +                {
 +                    let InFile { file_id, value } = expansion_info.expanded();
 +                    self.cache(value, file_id);
 +                }
 +
 +                let mapped_tokens = expansion_info.map_token_down(self.db.upcast(), item, token)?;
 +                let len = stack.len();
 +
 +                // requeue the tokens we got from mapping our current token down
 +                stack.extend(mapped_tokens);
 +                // if the length changed we have found a mapping for the token
 +                (stack.len() != len).then(|| ())
 +            };
 +
 +        // Remap the next token in the queue into a macro call its in, if it is not being remapped
 +        // either due to not being in a macro-call or because its unused push it into the result vec,
 +        // otherwise push the remapped tokens back into the queue as they can potentially be remapped again.
 +        while let Some(token) = stack.pop() {
 +            self.db.unwind_if_cancelled();
 +            let was_not_remapped = (|| {
-                 // or are we inside a function-like macro call
-                 if let Some(tt) =
-                     // FIXME replace map.while_some with take_while once stable
-                     token
-                         .value
-                         .parent_ancestors()
-                         .map(ast::TokenTree::cast)
-                         .while_some()
-                         .last()
-                 {
-                     let parent = tt.syntax().parent()?;
-                     // check for derive attribute here
-                     let macro_call = match_ast! {
-                         match parent {
-                             ast::MacroCall(mcall) => mcall,
-                             // attribute we failed expansion for earlier, this might be a derive invocation
++                // First expand into attribute invocations
 +                let containing_attribute_macro_call = self.with_ctx(|ctx| {
 +                    token.value.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
 +                        if item.attrs().next().is_none() {
 +                            // Don't force populate the dyn cache for items that don't have an attribute anyways
 +                            return None;
 +                        }
 +                        Some((ctx.item_to_macro_call(token.with_value(item.clone()))?, item))
 +                    })
 +                });
 +                if let Some((call_id, item)) = containing_attribute_macro_call {
 +                    let file_id = call_id.as_file();
 +                    return process_expansion_for_token(
 +                        &mut stack,
 +                        file_id,
 +                        Some(item),
 +                        token.as_ref(),
 +                    );
 +                }
 +
-                             ast::Meta(meta) => {
-                                 let attr = meta.parent_attr()?;
-                                 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
-                                 let call_id = self.with_ctx(|ctx| {
-                                     let (_, call_id, _) = ctx.attr_to_derive_macro_call(
-                                         token.with_value(&adt),
-                                         token.with_value(attr),
-                                     )?;
-                                     Some(call_id)
-                                 })?;
++                // Then check for token trees, that means we are either in a function-like macro or
++                // secondary attribute inputs
++                let tt = token.value.parent_ancestors().map_while(ast::TokenTree::cast).last()?;
++                let parent = tt.syntax().parent()?;
++
++                if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
++                    return None;
++                }
++                if tt.right_delimiter_token().map_or(false, |it| it == token.value) {
++                    return None;
++                }
++
++                if let Some(macro_call) = ast::MacroCall::cast(parent.clone()) {
++                    let mcall = token.with_value(macro_call);
++                    let file_id = match mcache.get(&mcall) {
++                        Some(&it) => it,
++                        None => {
++                            let it = sa.expand(self.db, mcall.as_ref())?;
++                            mcache.insert(mcall, it);
++                            it
++                        }
++                    };
++                    process_expansion_for_token(&mut stack, file_id, None, token.as_ref())
++                } else if let Some(meta) = ast::Meta::cast(parent.clone()) {
++                    // attribute we failed expansion for earlier, this might be a derive invocation
++                    // or derive helper attribute
++                    let attr = meta.parent_attr()?;
++
++                    let adt = if let Some(adt) = attr.syntax().parent().and_then(ast::Adt::cast) {
++                        // this might be a derive, or a derive helper on an ADT
++                        let derive_call = self.with_ctx(|ctx| {
 +                            // so try downmapping the token into the pseudo derive expansion
 +                            // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
-                             },
-                             _ => return None,
++                            ctx.attr_to_derive_macro_call(
++                                token.with_value(&adt),
++                                token.with_value(attr.clone()),
++                            )
++                            .map(|(_, call_id, _)| call_id)
++                        });
++
++                        match derive_call {
++                            Some(call_id) => {
++                                // resolved to a derive
 +                                let file_id = call_id.as_file();
 +                                return process_expansion_for_token(
 +                                    &mut stack,
 +                                    file_id,
 +                                    Some(adt.into()),
 +                                    token.as_ref(),
 +                                );
-                     };
-                     if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
++                            }
++                            None => Some(adt),
 +                        }
-                     if tt.right_delimiter_token().map_or(false, |it| it == token.value) {
-                         return None;
++                    } else {
++                        // Otherwise this could be a derive helper on a variant or field
++                        if let Some(field) = attr.syntax().parent().and_then(ast::RecordField::cast)
++                        {
++                            field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
++                        } else if let Some(field) =
++                            attr.syntax().parent().and_then(ast::TupleField::cast)
++                        {
++                            field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
++                        } else if let Some(variant) =
++                            attr.syntax().parent().and_then(ast::Variant::cast)
++                        {
++                            variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
++                        } else {
++                            None
++                        }
++                    }?;
++                    if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(token.file_id, &adt))) {
 +                        return None;
 +                    }
-                     let mcall = token.with_value(macro_call);
-                     let file_id = match mcache.get(&mcall) {
-                         Some(&it) => it,
-                         None => {
-                             let it = sa.expand(self.db, mcall.as_ref())?;
-                             mcache.insert(mcall, it);
-                             it
-                         }
-                     };
-                     return process_expansion_for_token(&mut stack, file_id, None, token.as_ref());
++                    // Not an attribute, nor a derive, so it's either a builtin or a derive helper
++                    // Try to resolve to a derive helper and downmap
++                    let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
++                    let id = self.db.ast_id_map(token.file_id).ast_id(&adt);
++                    let helpers =
++                        def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?;
++                    let item = Some(adt.into());
++                    let mut res = None;
++                    for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) {
++                        res = res.or(process_expansion_for_token(
++                            &mut stack,
++                            derive.as_file(),
++                            item.clone(),
++                            token.as_ref(),
++                        ));
 +                    }
-                 // outside of a macro invocation so this is a "final" token
-                 None
++                    res
++                } else {
++                    None
 +                }
 +            })()
 +            .is_none();
 +
 +            if was_not_remapped && f(token) {
 +                break;
 +            }
 +        }
 +    }
 +
 +    // Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
 +    // traversing the inner iterator when it finds a node.
 +    // The outer iterator is over the tokens descendants
 +    // The inner iterator is the ancestors of a descendant
 +    fn descend_node_at_offset(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ {
 +        node.token_at_offset(offset)
 +            .map(move |token| self.descend_into_macros(token))
 +            .map(|descendants| {
 +                descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it))
 +            })
 +            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
 +            // See algo::ancestors_at_offset, which uses the same approach
 +            .kmerge_by(|left, right| {
 +                left.clone()
 +                    .map(|node| node.text_range().len())
 +                    .lt(right.clone().map(|node| node.text_range().len()))
 +            })
 +    }
 +
 +    fn original_range(&self, node: &SyntaxNode) -> FileRange {
 +        let node = self.find_file(node);
 +        node.original_file_range(self.db.upcast())
 +    }
 +
 +    fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
 +        let node = self.find_file(node);
 +        node.original_file_range_opt(self.db.upcast())
 +    }
 +
 +    fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
 +        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
 +    }
 +
 +    fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
 +        let root = self.parse_or_expand(src.file_id).unwrap();
 +        let node = src.map(|it| it.to_node(&root));
 +        node.as_ref().original_file_range(self.db.upcast())
 +    }
 +
 +    fn token_ancestors_with_macros(
 +        &self,
 +        token: SyntaxToken,
 +    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
 +        token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent))
 +    }
 +
 +    fn ancestors_with_macros(
 +        &self,
 +        node: SyntaxNode,
 +    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
 +        let node = self.find_file(&node);
 +        let db = self.db.upcast();
 +        iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| {
 +            match value.parent() {
 +                Some(parent) => Some(InFile::new(file_id, parent)),
 +                None => {
 +                    self.cache(value.clone(), file_id);
 +                    file_id.call_node(db)
 +                }
 +            }
 +        })
 +        .map(|it| it.value)
 +    }
 +
 +    fn ancestors_at_offset_with_macros(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> impl Iterator<Item = SyntaxNode> + '_ {
 +        node.token_at_offset(offset)
 +            .map(|token| self.token_ancestors_with_macros(token))
 +            .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
 +    }
 +
 +    fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
 +        let text = lifetime.text();
 +        let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
 +            let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?;
 +            gpl.lifetime_params()
 +                .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
 +        })?;
 +        let src = self.wrap_node_infile(lifetime_param);
 +        ToDef::to_def(self, src)
 +    }
 +
 +    fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
 +        let text = lifetime.text();
 +        let label = lifetime.syntax().ancestors().find_map(|syn| {
 +            let label = match_ast! {
 +                match syn {
 +                    ast::ForExpr(it) => it.label(),
 +                    ast::WhileExpr(it) => it.label(),
 +                    ast::LoopExpr(it) => it.label(),
 +                    ast::BlockExpr(it) => it.label(),
 +                    _ => None,
 +                }
 +            };
 +            label.filter(|l| {
 +                l.lifetime()
 +                    .and_then(|lt| lt.lifetime_ident_token())
 +                    .map_or(false, |lt| lt.text() == text)
 +            })
 +        })?;
 +        let src = self.wrap_node_infile(label);
 +        ToDef::to_def(self, src)
 +    }
 +
 +    fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
 +        let analyze = self.analyze(ty.syntax())?;
 +        let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id);
 +        let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver)
 +            .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
 +        Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
 +    }
 +
 +    fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
 +        self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
 +    }
 +
 +    fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
 +        self.analyze(expr.syntax())?
 +            .type_of_expr(self.db, expr)
 +            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
 +    }
 +
 +    fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
 +        self.analyze(pat.syntax())?
 +            .type_of_pat(self.db, pat)
 +            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
 +    }
 +
 +    fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
 +        self.analyze(param.syntax())?.type_of_self(self.db, param)
 +    }
 +
 +    fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
 +        self.analyze(pat.syntax())
 +            .and_then(|it| it.pattern_adjustments(self.db, pat))
 +            .unwrap_or_default()
 +    }
 +
 +    fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
 +        self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
 +    }
 +
 +    fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
 +        self.analyze(call.syntax())?.resolve_method_call(self.db, call)
 +    }
 +
 +    fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
 +        self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
 +    }
 +
 +    fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
 +        self.analyze(field.syntax())?.resolve_field(self.db, field)
 +    }
 +
 +    fn resolve_record_field(
 +        &self,
 +        field: &ast::RecordExprField,
 +    ) -> Option<(Field, Option<Local>, Type)> {
 +        self.analyze(field.syntax())?.resolve_record_field(self.db, field)
 +    }
 +
 +    fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
 +        self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
 +    }
 +
 +    fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
 +        let sa = self.analyze(macro_call.syntax())?;
 +        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
 +        sa.resolve_macro_call(self.db, macro_call)
 +    }
 +
 +    fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
 +        let sa = match self.analyze(macro_call.syntax()) {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
 +        sa.is_unsafe_macro_call(self.db, macro_call)
 +    }
 +
 +    fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
 +        let item_in_file = self.wrap_node_infile(item.clone());
 +        let id = self.with_ctx(|ctx| {
 +            let macro_call_id = ctx.item_to_macro_call(item_in_file)?;
 +            macro_call_to_macro_id(ctx, self.db.upcast(), macro_call_id)
 +        })?;
 +        Some(Macro { id })
 +    }
 +
 +    fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
 +        self.analyze(path.syntax())?.resolve_path(self.db, path)
 +    }
 +
 +    fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
 +        let krate = self.scope(extern_crate.syntax())?.krate();
 +        let name = extern_crate.name_ref()?.as_name();
 +        if name == known::SELF_PARAM {
 +            return Some(krate);
 +        }
 +        krate
 +            .dependencies(self.db)
 +            .into_iter()
 +            .find_map(|dep| (dep.name == name).then(|| dep.krate))
 +    }
 +
 +    fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
 +        self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
 +    }
 +
 +    fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
 +        self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
 +    }
 +
 +    fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
 +        self.analyze(literal.syntax())
 +            .and_then(|it| it.record_literal_missing_fields(self.db, literal))
 +            .unwrap_or_default()
 +    }
 +
 +    fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
 +        self.analyze(pattern.syntax())
 +            .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
 +            .unwrap_or_default()
 +    }
 +
 +    fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T {
 +        let mut cache = self.s2d_cache.borrow_mut();
 +        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
 +        f(&mut ctx)
 +    }
 +
 +    fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
 +        self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
 +    }
 +
 +    fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
 +        self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
 +            db: self.db,
 +            file_id,
 +            resolver,
 +        })
 +    }
 +
 +    fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> Option<SemanticsScope<'db>> {
 +        self.analyze_with_offset_no_infer(node, offset).map(
 +            |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
 +                db: self.db,
 +                file_id,
 +                resolver,
 +            },
 +        )
 +    }
 +
 +    fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
 +        let file_id = self.db.lookup_intern_trait(def.id).id.file_id();
 +        let resolver = def.id.resolver(self.db.upcast());
 +        SemanticsScope { db: self.db, file_id, resolver }
 +    }
 +
 +    fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
 +    where
 +        Def::Ast: AstNode,
 +    {
 +        let res = def.source(self.db)?;
 +        self.cache(find_root(res.value.syntax()), res.file_id);
 +        Some(res)
 +    }
 +
 +    /// Returns none if the file of the node is not part of a crate.
 +    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
 +        self.analyze_impl(node, None, true)
 +    }
 +
 +    /// Returns none if the file of the node is not part of a crate.
 +    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
 +        self.analyze_impl(node, None, false)
 +    }
 +
 +    fn analyze_with_offset_no_infer(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: TextSize,
 +    ) -> Option<SourceAnalyzer> {
 +        self.analyze_impl(node, Some(offset), false)
 +    }
 +
 +    fn analyze_impl(
 +        &self,
 +        node: &SyntaxNode,
 +        offset: Option<TextSize>,
 +        infer_body: bool,
 +    ) -> Option<SourceAnalyzer> {
 +        let _p = profile::span("Semantics::analyze_impl");
 +        let node = self.find_file(node);
 +
 +        let container = match self.with_ctx(|ctx| ctx.find_container(node)) {
 +            Some(it) => it,
 +            None => return None,
 +        };
 +
 +        let resolver = match container {
 +            ChildContainer::DefWithBodyId(def) => {
 +                return Some(if infer_body {
 +                    SourceAnalyzer::new_for_body(self.db, def, node, offset)
 +                } else {
 +                    SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
 +                })
 +            }
 +            ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::EnumId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::VariantId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
 +            ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
 +        };
 +        Some(SourceAnalyzer::new_for_resolver(resolver, node))
 +    }
 +
 +    fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
 +        assert!(root_node.parent().is_none());
 +        let mut cache = self.cache.borrow_mut();
 +        let prev = cache.insert(root_node, file_id);
 +        assert!(prev == None || prev == Some(file_id))
 +    }
 +
 +    fn assert_contains_node(&self, node: &SyntaxNode) {
 +        self.find_file(node);
 +    }
 +
 +    fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
 +        let cache = self.cache.borrow();
 +        cache.get(root_node).copied()
 +    }
 +
 +    fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
 +        let InFile { file_id, .. } = self.find_file(node.syntax());
 +        InFile::new(file_id, node)
 +    }
 +
 +    /// Wraps the node in a [`InFile`] with the file id it belongs to.
 +    fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
 +        let root_node = find_root(node);
 +        let file_id = self.lookup(&root_node).unwrap_or_else(|| {
 +            panic!(
 +                "\n\nFailed to lookup {:?} in this Semantics.\n\
 +                 Make sure to use only query nodes, derived from this instance of Semantics.\n\
 +                 root node:   {:?}\n\
 +                 known nodes: {}\n\n",
 +                node,
 +                root_node,
 +                self.cache
 +                    .borrow()
 +                    .keys()
 +                    .map(|it| format!("{:?}", it))
 +                    .collect::<Vec<_>>()
 +                    .join(", ")
 +            )
 +        });
 +        InFile::new(file_id, node)
 +    }
 +
 +    fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
 +        method_call_expr
 +            .receiver()
 +            .and_then(|expr| {
 +                let field_expr = match expr {
 +                    ast::Expr::FieldExpr(field_expr) => field_expr,
 +                    _ => return None,
 +                };
 +                let ty = self.type_of_expr(&field_expr.expr()?)?.original;
 +                if !ty.is_packed(self.db) {
 +                    return None;
 +                }
 +
 +                let func = self.resolve_method_call(method_call_expr).map(Function::from)?;
 +                let res = match func.self_param(self.db)?.access(self.db) {
 +                    Access::Shared | Access::Exclusive => true,
 +                    Access::Owned => false,
 +                };
 +                Some(res)
 +            })
 +            .unwrap_or(false)
 +    }
 +
 +    fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
 +        ref_expr
 +            .expr()
 +            .and_then(|expr| {
 +                let field_expr = match expr {
 +                    ast::Expr::FieldExpr(field_expr) => field_expr,
 +                    _ => return None,
 +                };
 +                let expr = field_expr.expr()?;
 +                self.type_of_expr(&expr)
 +            })
 +            // Binding a reference to a packed type is possibly unsafe.
 +            .map(|ty| ty.original.is_packed(self.db))
 +            .unwrap_or(false)
 +
 +        // FIXME This needs layout computation to be correct. It will highlight
 +        // more than it should with the current implementation.
 +    }
 +
 +    fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
 +        if ident_pat.ref_token().is_none() {
 +            return false;
 +        }
 +
 +        ident_pat
 +            .syntax()
 +            .parent()
 +            .and_then(|parent| {
 +                // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
 +                // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
 +                // so this tries to lookup the `IdentPat` anywhere along that structure to the
 +                // `RecordPat` so we can get the containing type.
 +                let record_pat = ast::RecordPatField::cast(parent.clone())
 +                    .and_then(|record_pat| record_pat.syntax().parent())
 +                    .or_else(|| Some(parent.clone()))
 +                    .and_then(|parent| {
 +                        ast::RecordPatFieldList::cast(parent)?
 +                            .syntax()
 +                            .parent()
 +                            .and_then(ast::RecordPat::cast)
 +                    });
 +
 +                // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
 +                // this is initialized from a `FieldExpr`.
 +                if let Some(record_pat) = record_pat {
 +                    self.type_of_pat(&ast::Pat::RecordPat(record_pat))
 +                } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
 +                    let field_expr = match let_stmt.initializer()? {
 +                        ast::Expr::FieldExpr(field_expr) => field_expr,
 +                        _ => return None,
 +                    };
 +
 +                    self.type_of_expr(&field_expr.expr()?)
 +                } else {
 +                    None
 +                }
 +            })
 +            // Binding a reference to a packed type is possibly unsafe.
 +            .map(|ty| ty.original.is_packed(self.db))
 +            .unwrap_or(false)
 +    }
 +}
 +
 +fn macro_call_to_macro_id(
 +    ctx: &mut SourceToDefCtx<'_, '_>,
 +    db: &dyn AstDatabase,
 +    macro_call_id: MacroCallId,
 +) -> Option<MacroId> {
 +    let loc = db.lookup_intern_macro_call(macro_call_id);
 +    match loc.def.kind {
 +        hir_expand::MacroDefKind::Declarative(it)
 +        | hir_expand::MacroDefKind::BuiltIn(_, it)
 +        | hir_expand::MacroDefKind::BuiltInAttr(_, it)
 +        | hir_expand::MacroDefKind::BuiltInDerive(_, it)
 +        | hir_expand::MacroDefKind::BuiltInEager(_, it) => {
 +            ctx.macro_to_def(InFile::new(it.file_id, it.to_node(db)))
 +        }
 +        hir_expand::MacroDefKind::ProcMacro(_, _, it) => {
 +            ctx.proc_macro_to_def(InFile::new(it.file_id, it.to_node(db)))
 +        }
 +    }
 +}
 +
 +pub trait ToDef: AstNode + Clone {
 +    type Def;
 +
 +    fn to_def(sema: &SemanticsImpl<'_>, src: InFile<Self>) -> Option<Self::Def>;
 +}
 +
 +macro_rules! to_def_impls {
 +    ($(($def:path, $ast:path, $meth:ident)),* ,) => {$(
 +        impl ToDef for $ast {
 +            type Def = $def;
 +            fn to_def(sema: &SemanticsImpl<'_>, src: InFile<Self>) -> Option<Self::Def> {
 +                sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
 +            }
 +        }
 +    )*}
 +}
 +
 +to_def_impls![
 +    (crate::Module, ast::Module, module_to_def),
 +    (crate::Module, ast::SourceFile, source_file_to_def),
 +    (crate::Struct, ast::Struct, struct_to_def),
 +    (crate::Enum, ast::Enum, enum_to_def),
 +    (crate::Union, ast::Union, union_to_def),
 +    (crate::Trait, ast::Trait, trait_to_def),
 +    (crate::Impl, ast::Impl, impl_to_def),
 +    (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
 +    (crate::Const, ast::Const, const_to_def),
 +    (crate::Static, ast::Static, static_to_def),
 +    (crate::Function, ast::Fn, fn_to_def),
 +    (crate::Field, ast::RecordField, record_field_to_def),
 +    (crate::Field, ast::TupleField, tuple_field_to_def),
 +    (crate::Variant, ast::Variant, enum_variant_to_def),
 +    (crate::TypeParam, ast::TypeParam, type_param_to_def),
 +    (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
 +    (crate::ConstParam, ast::ConstParam, const_param_to_def),
 +    (crate::GenericParam, ast::GenericParam, generic_param_to_def),
 +    (crate::Macro, ast::Macro, macro_to_def),
 +    (crate::Local, ast::IdentPat, bind_pat_to_def),
 +    (crate::Local, ast::SelfParam, self_param_to_def),
 +    (crate::Label, ast::Label, label_to_def),
 +    (crate::Adt, ast::Adt, adt_to_def),
 +];
 +
 +fn find_root(node: &SyntaxNode) -> SyntaxNode {
 +    node.ancestors().last().unwrap()
 +}
 +
 +/// `SemanticScope` encapsulates the notion of a scope (the set of visible
 +/// names) at a particular program point.
 +///
 +/// It is a bit tricky, as scopes do not really exist inside the compiler.
 +/// Rather, the compiler directly computes for each reference the definition it
 +/// refers to. It might transiently compute the explicit scope map while doing
 +/// so, but, generally, this is not something left after the analysis.
 +///
 +/// However, we do very much need explicit scopes for IDE purposes --
 +/// completion, at its core, lists the contents of the current scope. The notion
 +/// of scope is also useful to answer questions like "what would be the meaning
 +/// of this piece of code if we inserted it into this position?".
 +///
 +/// So `SemanticsScope` is constructed from a specific program point (a syntax
 +/// node or just a raw offset) and provides access to the set of visible names
 +/// on a somewhat best-effort basis.
 +///
 +/// Note that if you are wondering "what does this specific existing name mean?",
 +/// you'd better use the `resolve_` family of methods.
 +#[derive(Debug)]
 +pub struct SemanticsScope<'a> {
 +    pub db: &'a dyn HirDatabase,
 +    file_id: HirFileId,
 +    resolver: Resolver,
 +}
 +
 +impl<'a> SemanticsScope<'a> {
 +    pub fn module(&self) -> Module {
 +        Module { id: self.resolver.module() }
 +    }
 +
 +    pub fn krate(&self) -> Crate {
 +        Crate { id: self.resolver.krate() }
 +    }
 +
 +    pub(crate) fn resolver(&self) -> &Resolver {
 +        &self.resolver
 +    }
 +
 +    /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
 +    pub fn visible_traits(&self) -> VisibleTraits {
 +        let resolver = &self.resolver;
 +        VisibleTraits(resolver.traits_in_scope(self.db.upcast()))
 +    }
 +
 +    pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
 +        let scope = self.resolver.names_in_scope(self.db.upcast());
 +        for (name, entries) in scope {
 +            for entry in entries {
 +                let def = match entry {
 +                    resolver::ScopeDef::ModuleDef(it) => ScopeDef::ModuleDef(it.into()),
 +                    resolver::ScopeDef::Unknown => ScopeDef::Unknown,
 +                    resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
 +                    resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
 +                    resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
 +                    resolver::ScopeDef::Local(pat_id) => match self.resolver.body_owner() {
 +                        Some(parent) => ScopeDef::Local(Local { parent, pat_id }),
 +                        None => continue,
 +                    },
 +                    resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() {
 +                        Some(parent) => ScopeDef::Label(Label { parent, label_id }),
 +                        None => continue,
 +                    },
 +                };
 +                f(name.clone(), def)
 +            }
 +        }
 +    }
 +
 +    /// Resolve a path as-if it was written at the given scope. This is
 +    /// necessary a heuristic, as it doesn't take hygiene into account.
 +    pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
 +        let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id);
 +        let path = Path::from_src(path.clone(), &ctx)?;
 +        resolve_hir_path(self.db, &self.resolver, &path)
 +    }
 +
 +    /// Iterates over associated types that may be specified after the given path (using
 +    /// `Ty::Assoc` syntax).
 +    pub fn assoc_type_shorthand_candidates<R>(
 +        &self,
 +        resolution: &PathResolution,
 +        mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
 +    ) -> Option<R> {
 +        let def = self.resolver.generic_def()?;
 +        hir_ty::associated_type_shorthand_candidates(
 +            self.db,
 +            def,
 +            resolution.in_type_ns()?,
 +            |name, _, id| cb(name, id.into()),
 +        )
 +    }
 +}
 +
 +pub struct VisibleTraits(pub FxHashSet<TraitId>);
 +
 +impl ops::Deref for VisibleTraits {
 +    type Target = FxHashSet<TraitId>;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
index 5c4cfa7b45a53fa275411abafba764083f39baf5,0000000000000000000000000000000000000000..ba9a1cfb6b51c5cdb0a27a27c4a1901d42927a13
mode 100644,000000..100644
--- /dev/null
@@@ -1,471 -1,0 +1,473 @@@
 +//! Maps *syntax* of various definitions to their semantic ids.
 +//!
 +//! This is a very interesting module, and, in some sense, can be considered the
 +//! heart of the IDE parts of rust-analyzer.
 +//!
 +//! This module solves the following problem:
 +//!
 +//!     Given a piece of syntax, find the corresponding semantic definition (def).
 +//!
 +//! This problem is a part of more-or-less every IDE feature implemented. Every
 +//! IDE functionality (like goto to definition), conceptually starts with a
 +//! specific cursor position in a file. Starting with this text offset, we first
 +//! figure out what syntactic construct are we at: is this a pattern, an
 +//! expression, an item definition.
 +//!
 +//! Knowing only the syntax gives us relatively little info. For example,
 +//! looking at the syntax of the function we can realise that it is a part of an
 +//! `impl` block, but we won't be able to tell what trait function the current
 +//! function overrides, and whether it does that correctly. For that, we need to
 +//! go from [`ast::Fn`] to [`crate::Function`], and that's exactly what this
 +//! module does.
 +//!
 +//! As syntax trees are values and don't know their place of origin/identity,
 +//! this module also requires [`InFile`] wrappers to understand which specific
 +//! real or macro-expanded file the tree comes from.
 +//!
 +//! The actual algorithm to resolve syntax to def is curious in two aspects:
 +//!
 +//!     * It is recursive
 +//!     * It uses the inverse algorithm (what is the syntax for this def?)
 +//!
 +//! Specifically, the algorithm goes like this:
 +//!
 +//!     1. Find the syntactic container for the syntax. For example, field's
 +//!        container is the struct, and structs container is a module.
 +//!     2. Recursively get the def corresponding to container.
 +//!     3. Ask the container def for all child defs. These child defs contain
 +//!        the answer and answer's siblings.
 +//!     4. For each child def, ask for it's source.
 +//!     5. The child def whose source is the syntax node we've started with
 +//!        is the answer.
 +//!
 +//! It's interesting that both Roslyn and Kotlin contain very similar code
 +//! shape.
 +//!
 +//! Let's take a look at Roslyn:
 +//!
 +//!   <https://github.com/dotnet/roslyn/blob/36a0c338d6621cc5fe34b79d414074a95a6a489c/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs#L1403-L1429>
 +//!   <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1403>
 +//!
 +//! The `GetDeclaredType` takes `Syntax` as input, and returns `Symbol` as
 +//! output. First, it retrieves a `Symbol` for parent `Syntax`:
 +//!
 +//! * <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1423>
 +//!
 +//! Then, it iterates parent symbol's children, looking for one which has the
 +//! same text span as the original node:
 +//!
 +//!   <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1786>
 +//!
 +//! Now, let's look at Kotlin:
 +//!
 +//!   <https://github.com/JetBrains/kotlin/blob/a288b8b00e4754a1872b164999c6d3f3b8c8994a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt#L93-L125>
 +//!
 +//! This function starts with a syntax node (`KtExpression` is syntax, like all
 +//! `Kt` nodes), and returns a def. It uses
 +//! `getNonLocalContainingOrThisDeclaration` to get syntactic container for a
 +//! current node. Then, `findSourceNonLocalFirDeclaration` gets `Fir` for this
 +//! parent. Finally, `findElementIn` function traverses `Fir` children to find
 +//! one with the same source we originally started with.
 +//!
 +//! One question is left though -- where does the recursion stops? This happens
 +//! when we get to the file syntax node, which doesn't have a syntactic parent.
 +//! In that case, we loop through all the crates that might contain this file
 +//! and look for a module whose source is the given file.
 +//!
 +//! Note that the logic in this module is somewhat fundamentally imprecise --
 +//! due to conditional compilation and `#[path]` attributes, there's no
 +//! injective mapping from syntax nodes to defs. This is not an edge case --
 +//! more or less every item in a `lib.rs` is a part of two distinct crates: a
 +//! library with `--cfg test` and a library without.
 +//!
 +//! At the moment, we don't really handle this well and return the first answer
 +//! that works. Ideally, we should first let the caller to pick a specific
 +//! active crate for a given position, and then provide an API to resolve all
 +//! syntax nodes against this specific crate.
 +
 +use base_db::FileId;
 +use hir_def::{
 +    attr::AttrId,
 +    child_by_source::ChildBySource,
 +    dyn_map::DynMap,
 +    expr::{LabelId, PatId},
 +    keys::{self, Key},
 +    AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId,
 +    GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId,
 +    TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
 +};
 +use hir_expand::{name::AsName, HirFileId, MacroCallId};
 +use rustc_hash::FxHashMap;
 +use smallvec::SmallVec;
 +use stdx::impl_from;
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SyntaxNode,
 +};
 +
 +use crate::{db::HirDatabase, InFile};
 +
 +pub(super) type SourceToDefCache = FxHashMap<(ChildContainer, HirFileId), DynMap>;
 +
 +pub(super) struct SourceToDefCtx<'a, 'b> {
 +    pub(super) db: &'b dyn HirDatabase,
 +    pub(super) cache: &'a mut SourceToDefCache,
 +}
 +
 +impl SourceToDefCtx<'_, '_> {
 +    pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
 +        let _p = profile::span("SourceBinder::to_module_def");
 +        let mut mods = SmallVec::new();
 +        for &crate_id in self.db.relevant_crates(file).iter() {
 +            // FIXME: inner items
 +            let crate_def_map = self.db.crate_def_map(crate_id);
 +            mods.extend(
 +                crate_def_map
 +                    .modules_for_file(file)
 +                    .map(|local_id| crate_def_map.module_id(local_id)),
 +            )
 +        }
 +        mods
 +    }
 +
 +    pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
 +        let _p = profile::span("module_to_def");
 +        let parent_declaration = src
 +            .syntax()
 +            .ancestors_with_macros_skip_attr_item(self.db.upcast())
 +            .find_map(|it| it.map(ast::Module::cast).transpose());
 +
 +        let parent_module = match parent_declaration {
 +            Some(parent_declaration) => self.module_to_def(parent_declaration),
 +            None => {
 +                let file_id = src.file_id.original_file(self.db.upcast());
 +                self.file_to_def(file_id).get(0).copied()
 +            }
 +        }?;
 +
 +        let child_name = src.value.name()?.as_name();
 +        let def_map = parent_module.def_map(self.db.upcast());
 +        let &child_id = def_map[parent_module.local_id].children.get(&child_name)?;
 +        Some(def_map.module_id(child_id))
 +    }
 +
 +    pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
 +        let _p = profile::span("source_file_to_def");
 +        let file_id = src.file_id.original_file(self.db.upcast());
 +        self.file_to_def(file_id).get(0).copied()
 +    }
 +
 +    pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
 +        self.to_def(src, keys::TRAIT)
 +    }
 +    pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> {
 +        self.to_def(src, keys::IMPL)
 +    }
 +    pub(super) fn fn_to_def(&mut self, src: InFile<ast::Fn>) -> Option<FunctionId> {
 +        self.to_def(src, keys::FUNCTION)
 +    }
 +    pub(super) fn struct_to_def(&mut self, src: InFile<ast::Struct>) -> Option<StructId> {
 +        self.to_def(src, keys::STRUCT)
 +    }
 +    pub(super) fn enum_to_def(&mut self, src: InFile<ast::Enum>) -> Option<EnumId> {
 +        self.to_def(src, keys::ENUM)
 +    }
 +    pub(super) fn union_to_def(&mut self, src: InFile<ast::Union>) -> Option<UnionId> {
 +        self.to_def(src, keys::UNION)
 +    }
 +    pub(super) fn static_to_def(&mut self, src: InFile<ast::Static>) -> Option<StaticId> {
 +        self.to_def(src, keys::STATIC)
 +    }
 +    pub(super) fn const_to_def(&mut self, src: InFile<ast::Const>) -> Option<ConstId> {
 +        self.to_def(src, keys::CONST)
 +    }
 +    pub(super) fn type_alias_to_def(&mut self, src: InFile<ast::TypeAlias>) -> Option<TypeAliasId> {
 +        self.to_def(src, keys::TYPE_ALIAS)
 +    }
 +    pub(super) fn record_field_to_def(&mut self, src: InFile<ast::RecordField>) -> Option<FieldId> {
 +        self.to_def(src, keys::RECORD_FIELD)
 +    }
 +    pub(super) fn tuple_field_to_def(&mut self, src: InFile<ast::TupleField>) -> Option<FieldId> {
 +        self.to_def(src, keys::TUPLE_FIELD)
 +    }
 +    pub(super) fn enum_variant_to_def(
 +        &mut self,
 +        src: InFile<ast::Variant>,
 +    ) -> Option<EnumVariantId> {
 +        self.to_def(src, keys::VARIANT)
 +    }
 +    pub(super) fn adt_to_def(
 +        &mut self,
 +        InFile { file_id, value }: InFile<ast::Adt>,
 +    ) -> Option<AdtId> {
 +        match value {
 +            ast::Adt::Enum(it) => self.enum_to_def(InFile::new(file_id, it)).map(AdtId::EnumId),
 +            ast::Adt::Struct(it) => {
 +                self.struct_to_def(InFile::new(file_id, it)).map(AdtId::StructId)
 +            }
 +            ast::Adt::Union(it) => self.union_to_def(InFile::new(file_id, it)).map(AdtId::UnionId),
 +        }
 +    }
 +    pub(super) fn bind_pat_to_def(
 +        &mut self,
 +        src: InFile<ast::IdentPat>,
 +    ) -> Option<(DefWithBodyId, PatId)> {
 +        let container = self.find_pat_or_label_container(src.syntax())?;
 +        let (body, source_map) = self.db.body_with_source_map(container);
 +        let src = src.map(ast::Pat::from);
 +        let pat_id = source_map.node_pat(src.as_ref())?;
 +        // the pattern could resolve to a constant, verify that that is not the case
 +        if let crate::Pat::Bind { .. } = body[pat_id] {
 +            Some((container, pat_id))
 +        } else {
 +            None
 +        }
 +    }
 +    pub(super) fn self_param_to_def(
 +        &mut self,
 +        src: InFile<ast::SelfParam>,
 +    ) -> Option<(DefWithBodyId, PatId)> {
 +        let container = self.find_pat_or_label_container(src.syntax())?;
 +        let (_body, source_map) = self.db.body_with_source_map(container);
 +        let pat_id = source_map.node_self_param(src.as_ref())?;
 +        Some((container, pat_id))
 +    }
 +    pub(super) fn label_to_def(
 +        &mut self,
 +        src: InFile<ast::Label>,
 +    ) -> Option<(DefWithBodyId, LabelId)> {
 +        let container = self.find_pat_or_label_container(src.syntax())?;
 +        let (_body, source_map) = self.db.body_with_source_map(container);
 +        let label_id = source_map.node_label(src.as_ref())?;
 +        Some((container, label_id))
 +    }
 +
 +    pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> {
 +        let map = self.dyn_map(src.as_ref())?;
 +        map[keys::ATTR_MACRO_CALL].get(&src.value).copied()
 +    }
 +
++    /// (AttrId, derive attribute call id, derive call ids)
 +    pub(super) fn attr_to_derive_macro_call(
 +        &mut self,
 +        item: InFile<&ast::Adt>,
 +        src: InFile<ast::Attr>,
 +    ) -> Option<(AttrId, MacroCallId, &[Option<MacroCallId>])> {
 +        let map = self.dyn_map(item)?;
 +        map[keys::DERIVE_MACRO_CALL]
 +            .get(&src.value)
 +            .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids))
 +    }
++
 +    pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool {
 +        self.dyn_map(adt).as_ref().map_or(false, |map| !map[keys::DERIVE_MACRO_CALL].is_empty())
 +    }
 +
 +    fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
 +        &mut self,
 +        src: InFile<Ast>,
 +        key: Key<Ast, ID>,
 +    ) -> Option<ID> {
 +        self.dyn_map(src.as_ref())?[key].get(&src.value).copied()
 +    }
 +
 +    fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> {
 +        let container = self.find_container(src.map(|it| it.syntax()))?;
 +        Some(self.cache_for(container, src.file_id))
 +    }
 +
 +    fn cache_for(&mut self, container: ChildContainer, file_id: HirFileId) -> &DynMap {
 +        let db = self.db;
 +        self.cache
 +            .entry((container, file_id))
 +            .or_insert_with(|| container.child_by_source(db, file_id))
 +    }
 +
 +    pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
 +        let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
 +        let dyn_map = self.cache_for(container, src.file_id);
 +        dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x))
 +    }
 +
 +    pub(super) fn lifetime_param_to_def(
 +        &mut self,
 +        src: InFile<ast::LifetimeParam>,
 +    ) -> Option<LifetimeParamId> {
 +        let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
 +        let dyn_map = self.cache_for(container, src.file_id);
 +        dyn_map[keys::LIFETIME_PARAM].get(&src.value).copied()
 +    }
 +
 +    pub(super) fn const_param_to_def(
 +        &mut self,
 +        src: InFile<ast::ConstParam>,
 +    ) -> Option<ConstParamId> {
 +        let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
 +        let dyn_map = self.cache_for(container, src.file_id);
 +        dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x))
 +    }
 +
 +    pub(super) fn generic_param_to_def(
 +        &mut self,
 +        InFile { file_id, value }: InFile<ast::GenericParam>,
 +    ) -> Option<GenericParamId> {
 +        match value {
 +            ast::GenericParam::ConstParam(it) => {
 +                self.const_param_to_def(InFile::new(file_id, it)).map(GenericParamId::ConstParamId)
 +            }
 +            ast::GenericParam::LifetimeParam(it) => self
 +                .lifetime_param_to_def(InFile::new(file_id, it))
 +                .map(GenericParamId::LifetimeParamId),
 +            ast::GenericParam::TypeParam(it) => {
 +                self.type_param_to_def(InFile::new(file_id, it)).map(GenericParamId::TypeParamId)
 +            }
 +        }
 +    }
 +
 +    pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroId> {
 +        self.dyn_map(src.as_ref()).and_then(|it| match &src.value {
 +            ast::Macro::MacroRules(value) => {
 +                it[keys::MACRO_RULES].get(value).copied().map(MacroId::from)
 +            }
 +            ast::Macro::MacroDef(value) => it[keys::MACRO2].get(value).copied().map(MacroId::from),
 +        })
 +    }
 +
 +    pub(super) fn proc_macro_to_def(&mut self, src: InFile<ast::Fn>) -> Option<MacroId> {
 +        self.dyn_map(src.as_ref())
 +            .and_then(|it| it[keys::PROC_MACRO].get(&src.value).copied().map(MacroId::from))
 +    }
 +
 +    pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
 +        for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()) {
 +            if let Some(res) = self.container_to_def(container) {
 +                return Some(res);
 +            }
 +        }
 +
 +        let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?;
 +        Some(def.into())
 +    }
 +
 +    fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> {
 +        let cont = if let Some(item) = ast::Item::cast(container.value.clone()) {
 +            match item {
 +                ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(),
 +                ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
 +                ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
 +                ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
 +                ast::Item::TypeAlias(it) => {
 +                    self.type_alias_to_def(container.with_value(it))?.into()
 +                }
 +                ast::Item::Struct(it) => {
 +                    let def = self.struct_to_def(container.with_value(it))?;
 +                    VariantId::from(def).into()
 +                }
 +                ast::Item::Union(it) => {
 +                    let def = self.union_to_def(container.with_value(it))?;
 +                    VariantId::from(def).into()
 +                }
 +                ast::Item::Fn(it) => {
 +                    let def = self.fn_to_def(container.with_value(it))?;
 +                    DefWithBodyId::from(def).into()
 +                }
 +                ast::Item::Static(it) => {
 +                    let def = self.static_to_def(container.with_value(it))?;
 +                    DefWithBodyId::from(def).into()
 +                }
 +                ast::Item::Const(it) => {
 +                    let def = self.const_to_def(container.with_value(it))?;
 +                    DefWithBodyId::from(def).into()
 +                }
 +                _ => return None,
 +            }
 +        } else {
 +            let it = ast::Variant::cast(container.value)?;
 +            let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
 +            VariantId::from(def).into()
 +        };
 +        Some(cont)
 +    }
 +
 +    fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
 +        let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast());
 +        for InFile { file_id, value } in ancestors {
 +            let item = match ast::Item::cast(value) {
 +                Some(it) => it,
 +                None => continue,
 +            };
 +            let res: GenericDefId = match item {
 +                ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::Struct(it) => self.struct_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::Enum(it) => self.enum_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::Trait(it) => self.trait_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::TypeAlias(it) => {
 +                    self.type_alias_to_def(InFile::new(file_id, it))?.into()
 +                }
 +                ast::Item::Impl(it) => self.impl_to_def(InFile::new(file_id, it))?.into(),
 +                _ => continue,
 +            };
 +            return Some(res);
 +        }
 +        None
 +    }
 +
 +    fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
 +        let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast());
 +        for InFile { file_id, value } in ancestors {
 +            let item = match ast::Item::cast(value) {
 +                Some(it) => it,
 +                None => continue,
 +            };
 +            let res: DefWithBodyId = match item {
 +                ast::Item::Const(it) => self.const_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::Static(it) => self.static_to_def(InFile::new(file_id, it))?.into(),
 +                ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(),
 +                _ => continue,
 +            };
 +            return Some(res);
 +        }
 +        None
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 +pub(crate) enum ChildContainer {
 +    DefWithBodyId(DefWithBodyId),
 +    ModuleId(ModuleId),
 +    TraitId(TraitId),
 +    ImplId(ImplId),
 +    EnumId(EnumId),
 +    VariantId(VariantId),
 +    TypeAliasId(TypeAliasId),
 +    /// XXX: this might be the same def as, for example an `EnumId`. However,
 +    /// here the children are generic parameters, and not, eg enum variants.
 +    GenericDefId(GenericDefId),
 +}
 +impl_from! {
 +    DefWithBodyId,
 +    ModuleId,
 +    TraitId,
 +    ImplId,
 +    EnumId,
 +    VariantId,
 +    TypeAliasId,
 +    GenericDefId
 +    for ChildContainer
 +}
 +
 +impl ChildContainer {
 +    fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap {
 +        let db = db.upcast();
 +        match self {
 +            ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::ModuleId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::TraitId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::ImplId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::EnumId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::VariantId(it) => it.child_by_source(db, file_id),
 +            ChildContainer::TypeAliasId(_) => DynMap::default(),
 +            ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id),
 +        }
 +    }
 +}
index e89f8a542981cdf185bd3369a6ba1d856c92ebf9,0000000000000000000000000000000000000000..1eb51b20c356b602efa8057b9b09a4447a2f9e93
mode 100644,000000..100644
--- /dev/null
@@@ -1,872 -1,0 +1,915 @@@
-     BuiltinType, Callable, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct,
-     ToolModule, Trait, Type, TypeAlias, Variant,
 +//! Lookup hir elements using positions in the source code. This is a lossy
 +//! transformation: in general, a single source might correspond to several
 +//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
 +//! modules.
 +//!
 +//! So, this modules should not be used during hir construction, it exists
 +//! purely for "IDE needs".
 +use std::{
 +    iter::{self, once},
 +    sync::Arc,
 +};
 +
 +use hir_def::{
 +    body::{
 +        self,
 +        scope::{ExprScopes, ScopeId},
 +        Body, BodySourceMap,
 +    },
 +    expr::{ExprId, Pat, PatId},
 +    macro_id_to_def_id,
 +    path::{ModPath, Path, PathKind},
 +    resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
 +    type_ref::Mutability,
 +    AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
 +    Lookup, ModuleDefId, VariantId,
 +};
 +use hir_expand::{
 +    builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile,
 +};
 +use hir_ty::{
 +    diagnostics::{
 +        record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
 +        UnsafeExpr,
 +    },
 +    method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
 +    TyExt, TyKind, TyLoweringContext,
 +};
++use itertools::Itertools;
 +use smallvec::SmallVec;
 +use syntax::{
 +    ast::{self, AstNode},
 +    SyntaxKind, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
-         let is_path_of_attr = path
++    BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
++    Struct, ToolModule, Trait, Type, TypeAlias, Variant,
 +};
 +
 +/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
 +/// original source files. It should not be used inside the HIR itself.
 +#[derive(Debug)]
 +pub(crate) struct SourceAnalyzer {
 +    pub(crate) file_id: HirFileId,
 +    pub(crate) resolver: Resolver,
 +    def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
 +    infer: Option<Arc<InferenceResult>>,
 +}
 +
 +impl SourceAnalyzer {
 +    pub(crate) fn new_for_body(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer {
 +            resolver,
 +            def: Some((def, body, source_map)),
 +            infer: Some(db.infer(def)),
 +            file_id,
 +        }
 +    }
 +
 +    pub(crate) fn new_for_body_no_infer(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
 +    }
 +
 +    pub(crate) fn new_for_resolver(
 +        resolver: Resolver,
 +        node: InFile<&SyntaxNode>,
 +    ) -> SourceAnalyzer {
 +        SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
 +    }
 +
 +    fn body_source_map(&self) -> Option<&BodySourceMap> {
 +        self.def.as_ref().map(|(.., source_map)| &**source_map)
 +    }
 +    fn body(&self) -> Option<&Body> {
 +        self.def.as_ref().map(|(_, body, _)| &**body)
 +    }
 +
 +    fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
 +        let src = match expr {
 +            ast::Expr::MacroExpr(expr) => {
 +                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?.clone()))?
 +            }
 +            _ => InFile::new(self.file_id, expr.clone()),
 +        };
 +        let sm = self.body_source_map()?;
 +        sm.node_expr(src.as_ref())
 +    }
 +
 +    fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
 +        // FIXME: macros, see `expr_id`
 +        let src = InFile { file_id: self.file_id, value: pat };
 +        self.body_source_map()?.node_pat(src)
 +    }
 +
 +    fn expand_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: InFile<ast::MacroCall>,
 +    ) -> Option<InFile<ast::Expr>> {
 +        let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
 +        let expanded = db.parse_or_expand(macro_file)?;
 +
 +        let res = match ast::MacroCall::cast(expanded.clone()) {
 +            Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
 +            _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
 +        };
 +        Some(res)
 +    }
 +
 +    pub(crate) fn is_implicit_reborrow(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<Mutability> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let adjustments = infer.expr_adjustments.get(&expr_id)?;
 +        adjustments.windows(2).find_map(|slice| match slice {
 +            &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
 +                hir_ty::Mutability::Mut => Mutability::Mut,
 +                hir_ty::Mutability::Not => Mutability::Shared,
 +            }),
 +            _ => None,
 +        })
 +    }
 +
 +    pub(crate) fn type_of_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .expr_adjustments
 +            .get(&expr_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
 +        let ty = infer[expr_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_pat(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let pat_id = self.pat_id(pat)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .pat_adjustments
 +            .get(&pat_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
 +        let ty = infer[pat_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_self(
 +        &self,
 +        db: &dyn HirDatabase,
 +        param: &ast::SelfParam,
 +    ) -> Option<Type> {
 +        let src = InFile { file_id: self.file_id, value: param };
 +        let pat_id = self.body_source_map()?.node_self_param(src)?;
 +        let ty = self.infer.as_ref()?[pat_id].clone();
 +        Some(Type::new_with_resolver(db, &self.resolver, ty))
 +    }
 +
 +    pub(crate) fn binding_mode_of_pat(
 +        &self,
 +        _db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<BindingMode> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let infer = self.infer.as_ref()?;
 +        infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
 +            hir_ty::BindingMode::Move => BindingMode::Move,
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
 +                BindingMode::Ref(Mutability::Shared)
 +            }
 +        })
 +    }
 +    pub(crate) fn pattern_adjustments(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<SmallVec<[Type; 1]>> {
 +        let pat_id = self.pat_id(&pat)?;
 +        let infer = self.infer.as_ref()?;
 +        Some(
 +            infer
 +                .pat_adjustments
 +                .get(&pat_id)?
 +                .iter()
 +                .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
 +                .collect(),
 +        )
 +    }
 +
 +    pub(crate) fn resolve_method_call_as_callable(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<Callable> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +        let ty = db.value_ty(func.into()).substitute(Interner, &substs);
 +        let ty = Type::new_with_resolver(db, &self.resolver, ty);
 +        let mut res = ty.as_callable(db)?;
 +        res.is_bound_method = true;
 +        Some(res)
 +    }
 +
 +    pub(crate) fn resolve_method_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<FunctionId> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +        let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs);
 +        f_in_impl.or(Some(f_in_trait))
 +    }
 +
 +    pub(crate) fn resolve_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::FieldExpr,
 +    ) -> Option<Field> {
 +        let expr_id = self.expr_id(db, &field.clone().into())?;
 +        self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_record_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordExprField,
 +    ) -> Option<(Field, Option<Local>, Type)> {
 +        let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let expr = ast::Expr::from(record_expr);
 +        let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
 +
 +        let local_name = field.field_name()?.as_name();
 +        let local = if field.name_ref().is_some() {
 +            None
 +        } else {
 +            let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
 +            match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
 +                Some(ValueNs::LocalBinding(pat_id)) => {
 +                    Some(Local { pat_id, parent: self.resolver.body_owner()? })
 +                }
 +                _ => None,
 +            }
 +        };
 +        let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
 +        let field_ty =
 +            db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
 +        Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
 +    }
 +
 +    pub(crate) fn resolve_record_pat_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordPatField,
 +    ) -> Option<Field> {
 +        let field_name = field.field_name()?.as_name();
 +        let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let pat_id = self.pat_id(&record_pat.into())?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
 +        Some(field.into())
 +    }
 +
 +    pub(crate) fn resolve_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<Macro> {
 +        let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
 +        let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
 +        self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_bind_pat_to_const(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<ModuleDef> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let body = self.body()?;
 +        let path = match &body[pat_id] {
 +            Pat::Path(path) => path,
 +            _ => return None,
 +        };
 +        let res = resolve_hir_path(db, &self.resolver, path)?;
 +        match res {
 +            PathResolution::Def(def) => Some(def),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn resolve_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +        path: &ast::Path,
 +    ) -> Option<PathResolution> {
 +        let parent = path.syntax().parent();
 +        let parent = || parent.clone();
 +
 +        let mut prefer_value_ns = false;
 +        let resolved = (|| {
 +            if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
 +                let expr_id = self.expr_id(db, &path_expr.into())?;
 +                let infer = self.infer.as_ref()?;
 +                if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
 +                    let assoc = match assoc {
 +                        AssocItemId::FunctionId(f_in_trait) => {
 +                            match infer.type_of_expr.get(expr_id) {
 +                                None => assoc,
 +                                Some(func_ty) => {
 +                                    if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
 +                                        self.resolve_impl_method(db, f_in_trait, subs)
 +                                            .map(AssocItemId::FunctionId)
 +                                            .unwrap_or(assoc)
 +                                    } else {
 +                                        assoc
 +                                    }
 +                                }
 +                            }
 +                        }
 +
 +                        _ => assoc,
 +                    };
 +
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    infer.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +                prefer_value_ns = true;
 +            } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
 +                let pat_id = self.pat_id(&path_pat.into())?;
 +                if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
 +                let expr_id = self.expr_id(db, &rec_lit.into())?;
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else {
 +                let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
 +                let tuple_struct_pat =
 +                    || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
 +                if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
 +                    let pat_id = self.pat_id(&pat)?;
 +                    let variant_res_for_pat =
 +                        self.infer.as_ref()?.variant_resolution_for_pat(pat_id);
 +                    if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
 +                        return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                    }
 +                }
 +            }
 +            None
 +        })();
 +        if let Some(_) = resolved {
 +            return resolved;
 +        }
 +
 +        // This must be a normal source file rather than macro file.
 +        let hygiene = Hygiene::new(db.upcast(), self.file_id);
 +        let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
 +        let hir_path = Path::from_src(path.clone(), &ctx)?;
 +
 +        // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
 +        // trying to resolve foo::bar.
 +        if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
 +            if use_tree.coloncolon_token().is_some() {
 +                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
 +            }
 +        }
 +
-             .map(|it| it.kind())
-             .take_while(|&kind| ast::Path::can_cast(kind) || ast::Meta::can_cast(kind))
++        let meta_path = path
 +            .syntax()
 +            .ancestors()
-             .map_or(false, ast::Meta::can_cast);
++            .take_while(|it| {
++                let kind = it.kind();
++                ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
++            })
 +            .last()
-                 None if is_path_of_attr => {
++            .and_then(ast::Meta::cast);
 +
 +        // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
 +        // trying to resolve foo::bar.
 +        if path.parent_path().is_some() {
 +            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
-         } else if is_path_of_attr {
++                None if meta_path.is_some() => {
 +                    path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                        ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                            .map(PathResolution::ToolModule)
 +                    })
 +                }
 +                res => res,
 +            };
-             let name_ref = path.as_single_name_ref();
-             let builtin = name_ref.as_ref().and_then(|name_ref| {
-                 BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text())
-             });
-             if let Some(_) = builtin {
-                 return builtin.map(PathResolution::BuiltinAttr);
++        } else if let Some(meta_path) = meta_path {
 +            // Case where we are resolving the final path segment of a path in an attribute
 +            // in this case we have to check for inert/builtin attributes and tools and prioritize
 +            // resolution of attributes over other namespaces
++            if let Some(name_ref) = path.as_single_name_ref() {
++                let builtin =
++                    BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
++                if let Some(_) = builtin {
++                    return builtin.map(PathResolution::BuiltinAttr);
++                }
++
++                if let Some(attr) = meta_path.parent_attr() {
++                    let adt = if let Some(field) =
++                        attr.syntax().parent().and_then(ast::RecordField::cast)
++                    {
++                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
++                    } else if let Some(field) =
++                        attr.syntax().parent().and_then(ast::TupleField::cast)
++                    {
++                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
++                    } else if let Some(variant) =
++                        attr.syntax().parent().and_then(ast::Variant::cast)
++                    {
++                        variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
++                    } else {
++                        None
++                    };
++                    if let Some(adt) = adt {
++                        let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
++                        if let Some(helpers) = self
++                            .resolver
++                            .def_map()
++                            .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
++                        {
++                            // FIXME: Multiple derives can have the same helper
++                            let name_ref = name_ref.as_name();
++                            for (macro_id, mut helpers) in
++                                helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
++                            {
++                                if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
++                                {
++                                    return Some(PathResolution::DeriveHelper(DeriveHelper {
++                                        derive: *macro_id,
++                                        idx,
++                                    }));
++                                }
++                            }
++                        }
++                    }
++                }
 +            }
 +            return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
 +                Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
 +                // this labels any path that starts with a tool module as the tool itself, this is technically wrong
 +                // but there is no benefit in differentiating these two cases for the time being
 +                None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                    ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                        .map(PathResolution::ToolModule)
 +                }),
 +            };
 +        }
 +        if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
 +            resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
 +        } else {
 +            resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
 +        }
 +    }
 +
 +    pub(crate) fn record_literal_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        literal: &ast::RecordExpr,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let expr_id = self.expr_id(db, &literal.clone().into())?;
 +        let substs = infer.type_of_expr[expr_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    pub(crate) fn record_pattern_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pattern: &ast::RecordPat,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let pat_id = self.pat_id(&pattern.clone().into())?;
 +        let substs = infer.type_of_pat[pat_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    fn missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        substs: &Substitution,
 +        variant: VariantId,
 +        missing_fields: Vec<LocalFieldId>,
 +    ) -> Vec<(Field, Type)> {
 +        let field_types = db.field_types(variant);
 +
 +        missing_fields
 +            .into_iter()
 +            .map(|local_id| {
 +                let field = FieldId { parent: variant, local_id };
 +                let ty = field_types[local_id].clone().substitute(Interner, substs);
 +                (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub(crate) fn expand(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<HirFileId> {
 +        let krate = self.resolver.krate();
 +        let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
 +            self.resolver
 +                .resolve_path_as_macro(db.upcast(), &path)
 +                .map(|it| macro_id_to_def_id(db.upcast(), it))
 +        })?;
 +        Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
 +    }
 +
 +    pub(crate) fn resolve_variant(
 +        &self,
 +        db: &dyn HirDatabase,
 +        record_lit: ast::RecordExpr,
 +    ) -> Option<VariantId> {
 +        let infer = self.infer.as_ref()?;
 +        let expr_id = self.expr_id(db, &record_lit.into())?;
 +        infer.variant_resolution_for_expr(expr_id)
 +    }
 +
 +    pub(crate) fn is_unsafe_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> bool {
 +        // check for asm/global_asm
 +        if let Some(mac) = self.resolve_macro_call(db, macro_call) {
 +            let ex = match mac.id {
 +                hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander,
 +                hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander,
 +                _ => hir_def::MacroExpander::Declarative,
 +            };
 +            match ex {
 +                hir_def::MacroExpander::BuiltIn(e)
 +                    if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm =>
 +                {
 +                    return true
 +                }
 +                _ => (),
 +            }
 +        }
 +        let macro_expr = match macro_call
 +            .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast))
 +            .transpose()
 +        {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
 +            if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) {
 +                let mut is_unsafe = false;
 +                unsafe_expressions(
 +                    db,
 +                    infer,
 +                    *def,
 +                    body,
 +                    expanded_expr,
 +                    &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
 +                );
 +                return is_unsafe;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn resolve_impl_method(
 +        &self,
 +        db: &dyn HirDatabase,
 +        func: FunctionId,
 +        substs: &Substitution,
 +    ) -> Option<FunctionId> {
 +        let impled_trait = match func.lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(trait_id) => trait_id,
 +            _ => return None,
 +        };
 +        if substs.is_empty(Interner) {
 +            return None;
 +        }
 +        let self_ty = substs.at(Interner, 0).ty(Interner)?;
 +        let krate = self.resolver.krate();
 +        let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
 +            || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        let fun_data = db.function_data(func);
 +        method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
 +    }
 +}
 +
 +fn scope_for(
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    node: InFile<&SyntaxNode>,
 +) -> Option<ScopeId> {
 +    node.value
 +        .ancestors()
 +        .filter_map(ast::Expr::cast)
 +        .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
 +        .find_map(|it| scopes.scope_for(it))
 +}
 +
 +fn scope_for_offset(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
 +            if from_file == file_id {
 +                return Some((value.text_range(), scope));
 +            }
 +
 +            // FIXME handle attribute expansion
 +            let source = iter::successors(file_id.call_node(db.upcast()), |it| {
 +                it.file_id.call_node(db.upcast())
 +            })
 +            .find(|it| it.file_id == from_file)
 +            .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
 +            Some((source.value.text_range(), scope))
 +        })
 +        .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
 +        // find containing scope
 +        .min_by_key(|(expr_range, _scope)| expr_range.len())
 +        .map(|(expr_range, scope)| {
 +            adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
 +        })
 +}
 +
 +// XXX: during completion, cursor might be outside of any particular
 +// expression. Try to figure out the correct scope...
 +fn adjust(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    expr_range: TextRange,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    let child_scopes = scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let source = source_map.expr_syntax(*id).ok()?;
 +            // FIXME: correctly handle macro expansion
 +            if source.file_id != from_file {
 +                return None;
 +            }
 +            let root = source.file_syntax(db.upcast());
 +            let node = source.value.to_node(&root);
 +            Some((node.syntax().text_range(), scope))
 +        })
 +        .filter(|&(range, _)| {
 +            range.start() <= offset && expr_range.contains_range(range) && range != expr_range
 +        });
 +
 +    child_scopes
 +        .max_by(|&(r1, _), &(r2, _)| {
 +            if r1.contains_range(r2) {
 +                std::cmp::Ordering::Greater
 +            } else if r2.contains_range(r1) {
 +                std::cmp::Ordering::Less
 +            } else {
 +                r1.start().cmp(&r2.start())
 +            }
 +        })
 +        .map(|(_ptr, scope)| *scope)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolve_hir_path_(db, resolver, path, false)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path_as_macro(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<Macro> {
 +    resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
 +}
 +
 +fn resolve_hir_path_(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +    prefer_value_ns: bool,
 +) -> Option<PathResolution> {
 +    let types = || {
 +        let (ty, unresolved) = match path.type_anchor() {
 +            Some(type_ref) => {
 +                let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
 +                res.map(|ty_ns| (ty_ns, path.segments().first()))
 +            }
 +            None => {
 +                let (ty, remaining) =
 +                    resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
 +                match remaining {
 +                    Some(remaining) if remaining > 1 => {
 +                        if remaining + 1 == path.segments().len() {
 +                            Some((ty, path.segments().last()))
 +                        } else {
 +                            None
 +                        }
 +                    }
 +                    _ => Some((ty, path.segments().get(1))),
 +                }
 +            }
 +        }?;
 +
 +        // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
 +        // within the trait's associated types.
 +        if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
 +            if let Some(type_alias_id) =
 +                db.trait_data(trait_id).associated_type_by_name(unresolved.name)
 +            {
 +                return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
 +            }
 +        }
 +
 +        let res = match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        };
 +        match unresolved {
 +            Some(unresolved) => resolver
 +                .generic_def()
 +                .and_then(|def| {
 +                    hir_ty::associated_type_shorthand_candidates(
 +                        db,
 +                        def,
 +                        res.in_type_ns()?,
 +                        |name, _, id| (name == unresolved.name).then(|| id),
 +                    )
 +                })
 +                .map(TypeAlias::from)
 +                .map(Into::into)
 +                .map(PathResolution::Def),
 +            None => Some(res),
 +        }
 +    };
 +
 +    let body_owner = resolver.body_owner();
 +    let values = || {
 +        resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
 +            let res = match val {
 +                ValueNs::LocalBinding(pat_id) => {
 +                    let var = Local { parent: body_owner?, pat_id };
 +                    PathResolution::Local(var)
 +                }
 +                ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
 +                ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
 +                ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
 +                ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
 +                ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +                ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
 +                ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
 +            };
 +            Some(res)
 +        })
 +    };
 +
 +    let items = || {
 +        resolver
 +            .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +            .take_types()
 +            .map(|it| PathResolution::Def(it.into()))
 +    };
 +
 +    let macros = || {
 +        resolver
 +            .resolve_path_as_macro(db.upcast(), path.mod_path())
 +            .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
 +    };
 +
 +    if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
 +        .or_else(items)
 +        .or_else(macros)
 +}
 +
 +/// Resolves a path where we know it is a qualifier of another path.
 +///
 +/// For example, if we have:
 +/// ```
 +/// mod my {
 +///     pub mod foo {
 +///         struct Bar;
 +///     }
 +///
 +///     pub fn foo() {}
 +/// }
 +/// ```
 +/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
 +fn resolve_hir_path_qualifier(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolver
 +        .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
 +        .map(|ty| match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        })
 +        .or_else(|| {
 +            resolver
 +                .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +                .take_types()
 +                .map(|it| PathResolution::Def(it.into()))
 +        })
 +}
index 7f2a26ad06741fa6246fe240e2ee4d0d8537fdc9,0000000000000000000000000000000000000000..c808c010c672eac67d9d397eaf20fa5332d7fee7
mode 100644,000000..100644
--- /dev/null
@@@ -1,1337 -1,0 +1,1340 @@@
-                 if let ast::AssocItem::Fn(func) = &first_new_item {
-                     if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() {
-                         if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
-                         {
-                             if m.syntax().text() == "todo!()" {
-                                 placeholder = m;
-                                 cursor = Cursor::Replace(placeholder.syntax());
 +use hir::HasSource;
 +use ide_db::{
 +    syntax_helpers::insert_whitespace_into_node::insert_ws_into, traits::resolve_target_trait,
 +};
 +use syntax::ast::{self, make, AstNode};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    utils::{
 +        add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, render_snippet,
 +        Cursor, DefaultMethods,
 +    },
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: add_impl_missing_members
 +//
 +// Adds scaffold for required impl members.
 +//
 +// ```
 +// trait Trait<T> {
 +//     type X;
 +//     fn foo(&self) -> T;
 +//     fn bar(&self) {}
 +// }
 +//
 +// impl Trait<u32> for () {$0
 +//
 +// }
 +// ```
 +// ->
 +// ```
 +// trait Trait<T> {
 +//     type X;
 +//     fn foo(&self) -> T;
 +//     fn bar(&self) {}
 +// }
 +//
 +// impl Trait<u32> for () {
 +//     $0type X;
 +//
 +//     fn foo(&self) -> u32 {
 +//         todo!()
 +//     }
 +// }
 +// ```
 +pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    add_missing_impl_members_inner(
 +        acc,
 +        ctx,
 +        DefaultMethods::No,
 +        "add_impl_missing_members",
 +        "Implement missing members",
 +    )
 +}
 +
 +// Assist: add_impl_default_members
 +//
 +// Adds scaffold for overriding default impl members.
 +//
 +// ```
 +// trait Trait {
 +//     type X;
 +//     fn foo(&self);
 +//     fn bar(&self) {}
 +// }
 +//
 +// impl Trait for () {
 +//     type X = ();
 +//     fn foo(&self) {}$0
 +// }
 +// ```
 +// ->
 +// ```
 +// trait Trait {
 +//     type X;
 +//     fn foo(&self);
 +//     fn bar(&self) {}
 +// }
 +//
 +// impl Trait for () {
 +//     type X = ();
 +//     fn foo(&self) {}
 +//
 +//     $0fn bar(&self) {}
 +// }
 +// ```
 +pub(crate) fn add_missing_default_members(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    add_missing_impl_members_inner(
 +        acc,
 +        ctx,
 +        DefaultMethods::Only,
 +        "add_impl_default_members",
 +        "Implement default members",
 +    )
 +}
 +
 +fn add_missing_impl_members_inner(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    mode: DefaultMethods,
 +    assist_id: &'static str,
 +    label: &'static str,
 +) -> Option<()> {
 +    let _p = profile::span("add_missing_impl_members_inner");
 +    let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
 +    let target_scope = ctx.sema.scope(impl_def.syntax())?;
 +    let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
 +
 +    let missing_items = filter_assoc_items(
 +        &ctx.sema,
 +        &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def),
 +        mode,
 +    );
 +
 +    if missing_items.is_empty() {
 +        return None;
 +    }
 +
 +    let target = impl_def.syntax().text_range();
 +    acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
 +        let missing_items = missing_items
 +            .into_iter()
 +            .map(|it| {
 +                if ctx.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 (new_impl_def, first_new_item) = add_trait_assoc_items_to_impl(
 +            &ctx.sema,
 +            missing_items,
 +            trait_,
 +            impl_def.clone(),
 +            target_scope,
 +        );
 +        match ctx.config.snippet_cap {
 +            None => builder.replace(target, new_impl_def.to_string()),
 +            Some(cap) => {
 +                let mut cursor = Cursor::Before(first_new_item.syntax());
 +                let placeholder;
++                if let DefaultMethods::No = mode {
++                    if let ast::AssocItem::Fn(func) = &first_new_item {
++                        if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() {
++                            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.replace_snippet(
 +                    cap,
 +                    target,
 +                    render_snippet(cap, new_impl_def.syntax(), cursor),
 +                )
 +            }
 +        };
 +    })
 +}
 +
 +fn try_gen_trait_body(
 +    ctx: &AssistContext<'_>,
 +    func: &ast::Fn,
 +    trait_: &hir::Trait,
 +    impl_def: &ast::Impl,
 +) -> Option<()> {
 +    let trait_path = make::ext::ident_path(&trait_.name(ctx.db()).to_string());
 +    let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?;
 +    let adt = hir_ty.as_adt()?.source(ctx.db())?;
 +    gen_trait_fn_body(func, &trait_path, &adt.value)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_add_missing_impl_members() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo {
 +    type Output;
 +
 +    const CONST: usize = 42;
 +
 +    fn foo(&self);
 +    fn bar(&self);
 +    fn baz(&self);
 +}
 +
 +struct S;
 +
 +impl Foo for S {
 +    fn bar(&self) {}
 +$0
 +}"#,
 +            r#"
 +trait Foo {
 +    type Output;
 +
 +    const CONST: usize = 42;
 +
 +    fn foo(&self);
 +    fn bar(&self);
 +    fn baz(&self);
 +}
 +
 +struct S;
 +
 +impl Foo for S {
 +    fn bar(&self) {}
 +
 +    $0type Output;
 +
 +    const CONST: usize = 42;
 +
 +    fn foo(&self) {
 +        todo!()
 +    }
 +
 +    fn baz(&self) {
 +        todo!()
 +    }
 +
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_copied_overriden_members() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo {
 +    fn foo(&self);
 +    fn bar(&self) -> bool { true }
 +    fn baz(&self) -> u32 { 42 }
 +}
 +
 +struct S;
 +
 +impl Foo for S {
 +    fn bar(&self) {}
 +$0
 +}"#,
 +            r#"
 +trait Foo {
 +    fn foo(&self);
 +    fn bar(&self) -> bool { true }
 +    fn baz(&self) -> u32 { 42 }
 +}
 +
 +struct S;
 +
 +impl Foo for S {
 +    fn bar(&self) {}
 +
 +    fn foo(&self) {
 +        ${0:todo!()}
 +    }
 +
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_empty_impl_def() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S { $0 }"#,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S {
 +    fn foo(&self) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_impl_def_without_braces() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S$0"#,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S {
 +    fn foo(&self) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fill_in_type_params_1() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo<T> { fn foo(&self, t: T) -> &T; }
 +struct S;
 +impl Foo<u32> for S { $0 }"#,
 +            r#"
 +trait Foo<T> { fn foo(&self, t: T) -> &T; }
 +struct S;
 +impl Foo<u32> for S {
 +    fn foo(&self, t: u32) -> &u32 {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fill_in_type_params_2() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo<T> { fn foo(&self, t: T) -> &T; }
 +struct S;
 +impl<U> Foo<U> for S { $0 }"#,
 +            r#"
 +trait Foo<T> { fn foo(&self, t: T) -> &T; }
 +struct S;
 +impl<U> Foo<U> for S {
 +    fn foo(&self, t: U) -> &U {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_cursor_after_empty_impl_def() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S {}$0"#,
 +            r#"
 +trait Foo { fn foo(&self); }
 +struct S;
 +impl Foo for S {
 +    fn foo(&self) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_1() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub struct Bar;
 +    trait Foo { fn foo(&self, bar: Bar); }
 +}
 +struct S;
 +impl foo::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub struct Bar;
 +    trait Foo { fn foo(&self, bar: Bar); }
 +}
 +struct S;
 +impl foo::Foo for S {
 +    fn foo(&self, bar: foo::Bar) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_2() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Bar;
 +        pub trait Foo { fn foo(&self, bar: Bar); }
 +    }
 +}
 +
 +use foo::bar;
 +
 +struct S;
 +impl bar::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Bar;
 +        pub trait Foo { fn foo(&self, bar: Bar); }
 +    }
 +}
 +
 +use foo::bar;
 +
 +struct S;
 +impl bar::Foo for S {
 +    fn foo(&self, bar: bar::Bar) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_generic() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    trait Foo { fn foo(&self, bar: Bar<u32>); }
 +}
 +struct S;
 +impl foo::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    trait Foo { fn foo(&self, bar: Bar<u32>); }
 +}
 +struct S;
 +impl foo::Foo for S {
 +    fn foo(&self, bar: foo::Bar<u32>) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_and_substitute_param() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    trait Foo<T> { fn foo(&self, bar: Bar<T>); }
 +}
 +struct S;
 +impl foo::Foo<u32> for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    trait Foo<T> { fn foo(&self, bar: Bar<T>); }
 +}
 +struct S;
 +impl foo::Foo<u32> for S {
 +    fn foo(&self, bar: foo::Bar<u32>) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_substitute_param_no_qualify() {
 +        // when substituting params, the substituted param should not be qualified!
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    trait Foo<T> { fn foo(&self, bar: T); }
 +    pub struct Param;
 +}
 +struct Param;
 +struct S;
 +impl foo::Foo<Param> for S { $0 }"#,
 +            r#"
 +mod foo {
 +    trait Foo<T> { fn foo(&self, bar: T); }
 +    pub struct Param;
 +}
 +struct Param;
 +struct S;
 +impl foo::Foo<Param> for S {
 +    fn foo(&self, bar: Param) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_associated_item() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    impl Bar<T> { type Assoc = u32; }
 +    trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
 +}
 +struct S;
 +impl foo::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    impl Bar<T> { type Assoc = u32; }
 +    trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
 +}
 +struct S;
 +impl foo::Foo for S {
 +    fn foo(&self, bar: foo::Bar<u32>::Assoc) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_nested() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    pub struct Baz;
 +    trait Foo { fn foo(&self, bar: Bar<Baz>); }
 +}
 +struct S;
 +impl foo::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub struct Bar<T>;
 +    pub struct Baz;
 +    trait Foo { fn foo(&self, bar: Bar<Baz>); }
 +}
 +struct S;
 +impl foo::Foo for S {
 +    fn foo(&self, bar: foo::Bar<foo::Baz>) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_qualify_path_fn_trait_notation() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod foo {
 +    pub trait Fn<Args> { type Output; }
 +    trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
 +}
 +struct S;
 +impl foo::Foo for S { $0 }"#,
 +            r#"
 +mod foo {
 +    pub trait Fn<Args> { type Output; }
 +    trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
 +}
 +struct S;
 +impl foo::Foo for S {
 +    fn foo(&self, bar: dyn Fn(u32) -> i32) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_empty_trait() {
 +        check_assist_not_applicable(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo;
 +struct S;
 +impl Foo for S { $0 }"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_ignore_unnamed_trait_members_and_default_methods() {
 +        check_assist_not_applicable(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo {
 +    fn (arg: u32);
 +    fn valid(some: u32) -> bool { false }
 +}
 +struct S;
 +impl Foo for S { $0 }"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_with_docstring_and_attrs() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +#[doc(alias = "test alias")]
 +trait Foo {
 +    /// doc string
 +    type Output;
 +
 +    #[must_use]
 +    fn foo(&self);
 +}
 +struct S;
 +impl Foo for S {}$0"#,
 +            r#"
 +#[doc(alias = "test alias")]
 +trait Foo {
 +    /// doc string
 +    type Output;
 +
 +    #[must_use]
 +    fn foo(&self);
 +}
 +struct S;
 +impl Foo for S {
 +    $0type Output;
 +
 +    fn foo(&self) {
 +        todo!()
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_default_methods() {
 +        check_assist(
 +            add_missing_default_members,
 +            r#"
 +trait Foo {
 +    type Output;
 +
 +    const CONST: usize = 42;
 +
 +    fn valid(some: u32) -> bool { false }
 +    fn foo(some: u32) -> bool;
 +}
 +struct S;
 +impl Foo for S { $0 }"#,
 +            r#"
 +trait Foo {
 +    type Output;
 +
 +    const CONST: usize = 42;
 +
 +    fn valid(some: u32) -> bool { false }
 +    fn foo(some: u32) -> bool;
 +}
 +struct S;
 +impl Foo for S {
 +    $0fn valid(some: u32) -> bool { false }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_generic_single_default_parameter() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo<T = Self> {
 +    fn bar(&self, other: &T);
 +}
 +
 +struct S;
 +impl Foo for S { $0 }"#,
 +            r#"
 +trait Foo<T = Self> {
 +    fn bar(&self, other: &T);
 +}
 +
 +struct S;
 +impl Foo for S {
 +    fn bar(&self, other: &Self) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_generic_default_parameter_is_second() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo<T1, T2 = Self> {
 +    fn bar(&self, this: &T1, that: &T2);
 +}
 +
 +struct S<T>;
 +impl Foo<T> for S<T> { $0 }"#,
 +            r#"
 +trait Foo<T1, T2 = Self> {
 +    fn bar(&self, this: &T1, that: &T2);
 +}
 +
 +struct S<T>;
 +impl Foo<T> for S<T> {
 +    fn bar(&self, this: &T, that: &Self) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_bounds_are_removed() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Tr {
 +    type Ty: Copy + 'static;
 +}
 +
 +impl Tr for ()$0 {
 +}"#,
 +            r#"
 +trait Tr {
 +    type Ty: Copy + 'static;
 +}
 +
 +impl Tr for () {
 +    $0type Ty;
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_whitespace_fixup_preserves_bad_tokens() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Tr {
 +    fn foo();
 +}
 +
 +impl Tr for ()$0 {
 +    +++
 +}"#,
 +            r#"
 +trait Tr {
 +    fn foo();
 +}
 +
 +impl Tr for () {
 +    fn foo() {
 +        ${0:todo!()}
 +    }
 +    +++
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_whitespace_fixup_preserves_comments() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Tr {
 +    fn foo();
 +}
 +
 +impl Tr for ()$0 {
 +    // very important
 +}"#,
 +            r#"
 +trait Tr {
 +    fn foo();
 +}
 +
 +impl Tr for () {
 +    fn foo() {
 +        ${0:todo!()}
 +    }
 +    // very important
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn weird_path() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Test {
 +    fn foo(&self, x: crate)
 +}
 +impl Test for () {
 +    $0
 +}
 +"#,
 +            r#"
 +trait Test {
 +    fn foo(&self, x: crate)
 +}
 +impl Test for () {
 +    fn foo(&self, x: crate) {
 +        ${0:todo!()}
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn missing_generic_type() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +trait Foo<BAR> {
 +    fn foo(&self, bar: BAR);
 +}
 +impl Foo for () {
 +    $0
 +}
 +"#,
 +            r#"
 +trait Foo<BAR> {
 +    fn foo(&self, bar: BAR);
 +}
 +impl Foo for () {
 +    fn foo(&self, bar: BAR) {
 +        ${0:todo!()}
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn does_not_requalify_self_as_crate() {
 +        check_assist(
 +            add_missing_default_members,
 +            r"
 +struct Wrapper<T>(T);
 +
 +trait T {
 +    fn f(self) -> Wrapper<Self> {
 +        Wrapper(self)
 +    }
 +}
 +
 +impl T for () {
 +    $0
 +}
 +",
 +            r"
 +struct Wrapper<T>(T);
 +
 +trait T {
 +    fn f(self) -> Wrapper<Self> {
 +        Wrapper(self)
 +    }
 +}
 +
 +impl T for () {
 +    $0fn f(self) -> Wrapper<Self> {
 +        Wrapper(self)
 +    }
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_default_body_generation() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +//- minicore: default
 +struct Foo(usize);
 +
 +impl Default for Foo {
 +    $0
 +}
 +"#,
 +            r#"
 +struct Foo(usize);
 +
 +impl Default for Foo {
 +    $0fn default() -> Self {
 +        Self(Default::default())
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_from_macro() {
 +        check_assist(
 +            add_missing_default_members,
 +            r#"
 +macro_rules! foo {
 +    () => {
 +        trait FooB {
 +            fn foo<'lt>(&'lt self) {}
 +        }
 +    }
 +}
 +foo!();
 +struct Foo(usize);
 +
 +impl FooB for Foo {
 +    $0
 +}
 +"#,
 +            r#"
 +macro_rules! foo {
 +    () => {
 +        trait FooB {
 +            fn foo<'lt>(&'lt self) {}
 +        }
 +    }
 +}
 +foo!();
 +struct Foo(usize);
 +
 +impl FooB for Foo {
 +    $0fn foo< 'lt>(& 'lt self){}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_when_trait_with_same_name_in_scope() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +pub trait Foo {}
 +
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl<T: Types> Behavior<T> for Impl { $0 }"#,
 +            r#"
 +pub trait Foo {}
 +
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl<T: Types> Behavior<T> for Impl {
 +    fn reproduce(&self, foo: <T as Types>::Foo) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_on_concrete_type() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl { $0 }"#,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl {
 +    fn reproduce(&self, foo: <u32 as Types>::Foo) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_on_concrete_type_qualified() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for std::string::String {
 +    type Foo = bool;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<std::string::String> for Impl { $0 }"#,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for std::string::String {
 +    type Foo = bool;
 +}
 +
 +pub trait Behavior<T: Types> {
 +    fn reproduce(&self, foo: T::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<std::string::String> for Impl {
 +    fn reproduce(&self, foo: <std::string::String as Types>::Foo) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_on_concrete_type_multi_option_ambiguous() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Types2 {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl Types2 for u32 {
 +    type Foo = String;
 +}
 +
 +pub trait Behavior<T: Types + Types2> {
 +    fn reproduce(&self, foo: <T as Types2>::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl { $0 }"#,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Types2 {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl Types2 for u32 {
 +    type Foo = String;
 +}
 +
 +pub trait Behavior<T: Types + Types2> {
 +    fn reproduce(&self, foo: <T as Types2>::Foo);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl {
 +    fn reproduce(&self, foo: <u32 as Types2>::Foo) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_on_concrete_type_multi_option() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Types2 {
 +    type Bar;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl Types2 for u32 {
 +    type Bar = String;
 +}
 +
 +pub trait Behavior<T: Types + Types2> {
 +    fn reproduce(&self, foo: T::Bar);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl { $0 }"#,
 +            r#"
 +pub trait Types {
 +    type Foo;
 +}
 +
 +pub trait Types2 {
 +    type Bar;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl Types2 for u32 {
 +    type Bar = String;
 +}
 +
 +pub trait Behavior<T: Types + Types2> {
 +    fn reproduce(&self, foo: T::Bar);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl {
 +    fn reproduce(&self, foo: <u32 as Types2>::Bar) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_assoc_type_on_concrete_type_multi_option_foreign() {
 +        check_assist(
 +            add_missing_impl_members,
 +            r#"
 +mod bar {
 +    pub trait Types2 {
 +        type Bar;
 +    }
 +}
 +
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl bar::Types2 for u32 {
 +    type Bar = String;
 +}
 +
 +pub trait Behavior<T: Types + bar::Types2> {
 +    fn reproduce(&self, foo: T::Bar);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl { $0 }"#,
 +            r#"
 +mod bar {
 +    pub trait Types2 {
 +        type Bar;
 +    }
 +}
 +
 +pub trait Types {
 +    type Foo;
 +}
 +
 +impl Types for u32 {
 +    type Foo = bool;
 +}
 +
 +impl bar::Types2 for u32 {
 +    type Bar = String;
 +}
 +
 +pub trait Behavior<T: Types + bar::Types2> {
 +    fn reproduce(&self, foo: T::Bar);
 +}
 +
 +pub struct Impl;
 +
 +impl Behavior<u32> for Impl {
 +    fn reproduce(&self, foo: <u32 as bar::Types2>::Bar) {
 +        ${0:todo!()}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_transform_path_in_path_expr() {
 +        check_assist(
 +            add_missing_default_members,
 +            r#"
 +pub trait Const {
 +    const FOO: u32;
 +}
 +
 +pub trait Trait<T: Const> {
 +    fn foo() -> bool {
 +        match T::FOO {
 +            0 => true,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Const for u32 {
 +    const FOO: u32 = 1;
 +}
 +
 +struct Impl;
 +
 +impl Trait<u32> for Impl { $0 }"#,
 +            r#"
 +pub trait Const {
 +    const FOO: u32;
 +}
 +
 +pub trait Trait<T: Const> {
 +    fn foo() -> bool {
 +        match T::FOO {
 +            0 => true,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Const for u32 {
 +    const FOO: u32 = 1;
 +}
 +
 +struct Impl;
 +
 +impl Trait<u32> for Impl {
 +    $0fn foo() -> bool {
 +        match <u32 as Const>::FOO {
 +            0 => true,
 +            _ => false,
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_default_partial_eq() {
 +        check_assist(
 +            add_missing_default_members,
 +            r#"
 +//- minicore: eq
 +struct SomeStruct {
 +    data: usize,
 +    field: (usize, usize),
 +}
 +impl PartialEq for SomeStruct {$0}
 +"#,
 +            r#"
 +struct SomeStruct {
 +    data: usize,
 +    field: (usize, usize),
 +}
 +impl PartialEq for SomeStruct {
 +    $0fn ne(&self, other: &Self) -> bool {
 +            !self.eq(other)
 +        }
 +}
 +"#,
 +        );
 +    }
 +}
index ec4835969f886017c984ca8cec528e134ca9a441,0000000000000000000000000000000000000000..7a0c912959a12c53b9b909225accc56e866d3ca5
mode 100644,000000..100644
--- /dev/null
@@@ -1,660 -1,0 +1,661 @@@
- /// Generate custom trait bodies where possible.
 +//! This module contains functions to generate default trait impl function bodies where possible.
 +
 +use syntax::{
 +    ast::{self, edit::AstNodeEdit, make, AstNode, BinaryOp, CmpOp, HasName, LogicOp},
 +    ted,
 +};
 +
-     if func.name().map_or(false, |name| name.text() == "ne") {
-         return None;
-     }
++/// Generate custom trait bodies without default implementation where possible.
 +///
 +/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
 +/// `None` means that generating a custom trait body failed, and the body will remain
 +/// as `todo!` instead.
 +pub(crate) fn gen_trait_fn_body(
 +    func: &ast::Fn,
 +    trait_path: &ast::Path,
 +    adt: &ast::Adt,
 +) -> Option<()> {
 +    match trait_path.segment()?.name_ref()?.text().as_str() {
 +        "Clone" => gen_clone_impl(adt, func),
 +        "Debug" => gen_debug_impl(adt, func),
 +        "Default" => gen_default_impl(adt, func),
 +        "Hash" => gen_hash_impl(adt, func),
 +        "PartialEq" => gen_partial_eq(adt, func),
 +        "PartialOrd" => gen_partial_ord(adt, func),
 +        _ => None,
 +    }
 +}
 +
 +/// Generate a `Clone` impl based on the fields and members of the target type.
 +fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
++    stdx::always!(func.name().map_or(false, |name| name.text() == "clone"));
 +    fn gen_clone_call(target: ast::Expr) -> ast::Expr {
 +        let method = make::name_ref("clone");
 +        make::expr_method_call(target, method, make::arg_list(None))
 +    }
 +    let expr = match adt {
 +        // `Clone` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => return None,
 +        ast::Adt::Enum(enum_) => {
 +            let list = enum_.variant_list()?;
 +            let mut arms = vec![];
 +            for variant in list.variants() {
 +                let name = variant.name()?;
 +                let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
 +
 +                match variant.field_list() {
 +                    // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
 +                    Some(ast::FieldList::RecordFieldList(list)) => {
 +                        let mut pats = vec![];
 +                        let mut fields = vec![];
 +                        for field in list.fields() {
 +                            let field_name = field.name()?;
 +                            let pat = make::ident_pat(false, false, field_name.clone());
 +                            pats.push(pat.into());
 +
 +                            let path = make::ext::ident_path(&field_name.to_string());
 +                            let method_call = gen_clone_call(make::expr_path(path));
 +                            let name_ref = make::name_ref(&field_name.to_string());
 +                            let field = make::record_expr_field(name_ref, Some(method_call));
 +                            fields.push(field);
 +                        }
 +                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
 +                        let fields = make::record_expr_field_list(fields);
 +                        let record_expr = make::record_expr(variant_name, fields).into();
 +                        arms.push(make::match_arm(Some(pat.into()), None, record_expr));
 +                    }
 +
 +                    // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
 +                    Some(ast::FieldList::TupleFieldList(list)) => {
 +                        let mut pats = vec![];
 +                        let mut fields = vec![];
 +                        for (i, _) in list.fields().enumerate() {
 +                            let field_name = format!("arg{}", i);
 +                            let pat = make::ident_pat(false, false, make::name(&field_name));
 +                            pats.push(pat.into());
 +
 +                            let f_path = make::expr_path(make::ext::ident_path(&field_name));
 +                            fields.push(gen_clone_call(f_path));
 +                        }
 +                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
 +                        let struct_name = make::expr_path(variant_name);
 +                        let tuple_expr = make::expr_call(struct_name, make::arg_list(fields));
 +                        arms.push(make::match_arm(Some(pat.into()), None, tuple_expr));
 +                    }
 +
 +                    // => match self { Self::Name => Self::Name }
 +                    None => {
 +                        let pattern = make::path_pat(variant_name.clone());
 +                        let variant_expr = make::expr_path(variant_name);
 +                        arms.push(make::match_arm(Some(pattern), None, variant_expr));
 +                    }
 +                }
 +            }
 +
 +            let match_target = make::expr_path(make::ext::ident_path("self"));
 +            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
 +            make::expr_match(match_target, list)
 +        }
 +        ast::Adt::Struct(strukt) => {
 +            match strukt.field_list() {
 +                // => Self { name: self.name.clone() }
 +                Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                    let mut fields = vec![];
 +                    for field in field_list.fields() {
 +                        let base = make::expr_path(make::ext::ident_path("self"));
 +                        let target = make::expr_field(base, &field.name()?.to_string());
 +                        let method_call = gen_clone_call(target);
 +                        let name_ref = make::name_ref(&field.name()?.to_string());
 +                        let field = make::record_expr_field(name_ref, Some(method_call));
 +                        fields.push(field);
 +                    }
 +                    let struct_name = make::ext::ident_path("Self");
 +                    let fields = make::record_expr_field_list(fields);
 +                    make::record_expr(struct_name, fields).into()
 +                }
 +                // => Self(self.0.clone(), self.1.clone())
 +                Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                    let mut fields = vec![];
 +                    for (i, _) in field_list.fields().enumerate() {
 +                        let f_path = make::expr_path(make::ext::ident_path("self"));
 +                        let target = make::expr_field(f_path, &format!("{}", i));
 +                        fields.push(gen_clone_call(target));
 +                    }
 +                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
 +                    make::expr_call(struct_name, make::arg_list(fields))
 +                }
 +                // => Self { }
 +                None => {
 +                    let struct_name = make::ext::ident_path("Self");
 +                    let fields = make::record_expr_field_list(None);
 +                    make::record_expr(struct_name, fields).into()
 +                }
 +            }
 +        }
 +    };
 +    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 +    ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +    Some(())
 +}
 +
 +/// Generate a `Debug` impl based on the fields and members of the target type.
 +fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 +    let annotated_name = adt.name()?;
 +    match adt {
 +        // `Debug` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => None,
 +
 +        // => match self { Self::Variant => write!(f, "Variant") }
 +        ast::Adt::Enum(enum_) => {
 +            let list = enum_.variant_list()?;
 +            let mut arms = vec![];
 +            for variant in list.variants() {
 +                let name = variant.name()?;
 +                let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
 +                let target = make::expr_path(make::ext::ident_path("f"));
 +
 +                match variant.field_list() {
 +                    Some(ast::FieldList::RecordFieldList(list)) => {
 +                        // => f.debug_struct(name)
 +                        let target = make::expr_path(make::ext::ident_path("f"));
 +                        let method = make::name_ref("debug_struct");
 +                        let struct_name = format!("\"{}\"", name);
 +                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
 +                        let mut expr = make::expr_method_call(target, method, args);
 +
 +                        let mut pats = vec![];
 +                        for field in list.fields() {
 +                            let field_name = field.name()?;
 +
 +                            // create a field pattern for use in `MyStruct { fields.. }`
 +                            let pat = make::ident_pat(false, false, field_name.clone());
 +                            pats.push(pat.into());
 +
 +                            // => <expr>.field("field_name", field)
 +                            let method_name = make::name_ref("field");
 +                            let name = make::expr_literal(&(format!("\"{}\"", field_name))).into();
 +                            let path = &format!("{}", field_name);
 +                            let path = make::expr_path(make::ext::ident_path(path));
 +                            let args = make::arg_list(vec![name, path]);
 +                            expr = make::expr_method_call(expr, method_name, args);
 +                        }
 +
 +                        // => <expr>.finish()
 +                        let method = make::name_ref("finish");
 +                        let expr = make::expr_method_call(expr, method, make::arg_list(None));
 +
 +                        // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
 +                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
 +                        arms.push(make::match_arm(Some(pat.into()), None, expr));
 +                    }
 +                    Some(ast::FieldList::TupleFieldList(list)) => {
 +                        // => f.debug_tuple(name)
 +                        let target = make::expr_path(make::ext::ident_path("f"));
 +                        let method = make::name_ref("debug_tuple");
 +                        let struct_name = format!("\"{}\"", name);
 +                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
 +                        let mut expr = make::expr_method_call(target, method, args);
 +
 +                        let mut pats = vec![];
 +                        for (i, _) in list.fields().enumerate() {
 +                            let name = format!("arg{}", i);
 +
 +                            // create a field pattern for use in `MyStruct(fields..)`
 +                            let field_name = make::name(&name);
 +                            let pat = make::ident_pat(false, false, field_name.clone());
 +                            pats.push(pat.into());
 +
 +                            // => <expr>.field(field)
 +                            let method_name = make::name_ref("field");
 +                            let field_path = &name.to_string();
 +                            let field_path = make::expr_path(make::ext::ident_path(field_path));
 +                            let args = make::arg_list(vec![field_path]);
 +                            expr = make::expr_method_call(expr, method_name, args);
 +                        }
 +
 +                        // => <expr>.finish()
 +                        let method = make::name_ref("finish");
 +                        let expr = make::expr_method_call(expr, method, make::arg_list(None));
 +
 +                        // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
 +                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
 +                        arms.push(make::match_arm(Some(pat.into()), None, expr));
 +                    }
 +                    None => {
 +                        let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into();
 +                        let args = make::arg_list([target, fmt_string]);
 +                        let macro_name = make::expr_path(make::ext::ident_path("write"));
 +                        let macro_call = make::expr_macro_call(macro_name, args);
 +
 +                        let variant_name = make::path_pat(variant_name);
 +                        arms.push(make::match_arm(Some(variant_name), None, macro_call));
 +                    }
 +                }
 +            }
 +
 +            let match_target = make::expr_path(make::ext::ident_path("self"));
 +            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
 +            let match_expr = make::expr_match(match_target, list);
 +
 +            let body = make::block_expr(None, Some(match_expr));
 +            let body = body.indent(ast::edit::IndentLevel(1));
 +            ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +            Some(())
 +        }
 +
 +        ast::Adt::Struct(strukt) => {
 +            let name = format!("\"{}\"", annotated_name);
 +            let args = make::arg_list(Some(make::expr_literal(&name).into()));
 +            let target = make::expr_path(make::ext::ident_path("f"));
 +
 +            let expr = match strukt.field_list() {
 +                // => f.debug_struct("Name").finish()
 +                None => make::expr_method_call(target, make::name_ref("debug_struct"), args),
 +
 +                // => f.debug_struct("Name").field("foo", &self.foo).finish()
 +                Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                    let method = make::name_ref("debug_struct");
 +                    let mut expr = make::expr_method_call(target, method, args);
 +                    for field in field_list.fields() {
 +                        let name = field.name()?;
 +                        let f_name = make::expr_literal(&(format!("\"{}\"", name))).into();
 +                        let f_path = make::expr_path(make::ext::ident_path("self"));
 +                        let f_path = make::expr_ref(f_path, false);
 +                        let f_path = make::expr_field(f_path, &format!("{}", name));
 +                        let args = make::arg_list([f_name, f_path]);
 +                        expr = make::expr_method_call(expr, make::name_ref("field"), args);
 +                    }
 +                    expr
 +                }
 +
 +                // => f.debug_tuple("Name").field(self.0).finish()
 +                Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                    let method = make::name_ref("debug_tuple");
 +                    let mut expr = make::expr_method_call(target, method, args);
 +                    for (i, _) in field_list.fields().enumerate() {
 +                        let f_path = make::expr_path(make::ext::ident_path("self"));
 +                        let f_path = make::expr_ref(f_path, false);
 +                        let f_path = make::expr_field(f_path, &format!("{}", i));
 +                        let method = make::name_ref("field");
 +                        expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)));
 +                    }
 +                    expr
 +                }
 +            };
 +
 +            let method = make::name_ref("finish");
 +            let expr = make::expr_method_call(expr, method, make::arg_list(None));
 +            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 +            ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +            Some(())
 +        }
 +    }
 +}
 +
 +/// Generate a `Debug` impl based on the fields and members of the target type.
 +fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 +    fn gen_default_call() -> Option<ast::Expr> {
 +        let fn_name = make::ext::path_from_idents(["Default", "default"])?;
 +        Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)))
 +    }
 +    match adt {
 +        // `Debug` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => None,
 +        // Deriving `Debug` for enums is not stable yet.
 +        ast::Adt::Enum(_) => None,
 +        ast::Adt::Struct(strukt) => {
 +            let expr = match strukt.field_list() {
 +                Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                    let mut fields = vec![];
 +                    for field in field_list.fields() {
 +                        let method_call = gen_default_call()?;
 +                        let name_ref = make::name_ref(&field.name()?.to_string());
 +                        let field = make::record_expr_field(name_ref, Some(method_call));
 +                        fields.push(field);
 +                    }
 +                    let struct_name = make::ext::ident_path("Self");
 +                    let fields = make::record_expr_field_list(fields);
 +                    make::record_expr(struct_name, fields).into()
 +                }
 +                Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
 +                    let fields = field_list
 +                        .fields()
 +                        .map(|_| gen_default_call())
 +                        .collect::<Option<Vec<ast::Expr>>>()?;
 +                    make::expr_call(struct_name, make::arg_list(fields))
 +                }
 +                None => {
 +                    let struct_name = make::ext::ident_path("Self");
 +                    let fields = make::record_expr_field_list(None);
 +                    make::record_expr(struct_name, fields).into()
 +                }
 +            };
 +            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 +            ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +            Some(())
 +        }
 +    }
 +}
 +
 +/// Generate a `Hash` impl based on the fields and members of the target type.
 +fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
++    stdx::always!(func.name().map_or(false, |name| name.text() == "hash"));
 +    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 +        let method = make::name_ref("hash");
 +        let arg = make::expr_path(make::ext::ident_path("state"));
 +        let expr = make::expr_method_call(target, method, make::arg_list(Some(arg)));
 +        make::expr_stmt(expr).into()
 +    }
 +
 +    let body = match adt {
 +        // `Hash` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => return None,
 +
 +        // => std::mem::discriminant(self).hash(state);
 +        ast::Adt::Enum(_) => {
 +            let fn_name = make_discriminant()?;
 +
 +            let arg = make::expr_path(make::ext::ident_path("self"));
 +            let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg)));
 +            let stmt = gen_hash_call(fn_call);
 +
 +            make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1))
 +        }
 +        ast::Adt::Struct(strukt) => match strukt.field_list() {
 +            // => self.<field>.hash(state);
 +            Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                let mut stmts = vec![];
 +                for field in field_list.fields() {
 +                    let base = make::expr_path(make::ext::ident_path("self"));
 +                    let target = make::expr_field(base, &field.name()?.to_string());
 +                    stmts.push(gen_hash_call(target));
 +                }
 +                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
 +            }
 +
 +            // => self.<field_index>.hash(state);
 +            Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                let mut stmts = vec![];
 +                for (i, _) in field_list.fields().enumerate() {
 +                    let base = make::expr_path(make::ext::ident_path("self"));
 +                    let target = make::expr_field(base, &format!("{}", i));
 +                    stmts.push(gen_hash_call(target));
 +                }
 +                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
 +            }
 +
 +            // No fields in the body means there's nothing to hash.
 +            None => return None,
 +        },
 +    };
 +
 +    ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +    Some(())
 +}
 +
 +/// Generate a `PartialEq` impl based on the fields and members of the target type.
 +fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
-             // No fields in the body means there's nothing to hash.
++    stdx::always!(func.name().map_or(false, |name| name.text() == "eq"));
 +    fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
 +        match expr {
 +            Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
 +            None => Some(cmp),
 +        }
 +    }
 +
 +    fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField {
 +        let pat = make::ext::simple_ident_pat(make::name(pat_name));
 +        let name_ref = make::name_ref(field_name);
 +        make::record_pat_field(name_ref, pat.into())
 +    }
 +
 +    fn gen_record_pat(record_name: ast::Path, fields: Vec<ast::RecordPatField>) -> ast::RecordPat {
 +        let list = make::record_pat_field_list(fields);
 +        make::record_pat_with_fields(record_name, list)
 +    }
 +
 +    fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
 +        make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
 +    }
 +
 +    fn gen_tuple_field(field_name: &String) -> ast::Pat {
 +        ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
 +    }
 +
 +    // FIXME: return `None` if the trait carries a generic type; we can only
 +    // generate this code `Self` for the time being.
 +
 +    let body = match adt {
 +        // `PartialEq` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => return None,
 +
 +        ast::Adt::Enum(enum_) => {
 +            // => std::mem::discriminant(self) == std::mem::discriminant(other)
 +            let lhs_name = make::expr_path(make::ext::ident_path("self"));
 +            let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone())));
 +            let rhs_name = make::expr_path(make::ext::ident_path("other"));
 +            let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone())));
 +            let eq_check =
 +                make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
 +
 +            let mut n_cases = 0;
 +            let mut arms = vec![];
 +            for variant in enum_.variant_list()?.variants() {
 +                n_cases += 1;
 +                match variant.field_list() {
 +                    // => (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
 +                    Some(ast::FieldList::RecordFieldList(list)) => {
 +                        let mut expr = None;
 +                        let mut l_fields = vec![];
 +                        let mut r_fields = vec![];
 +
 +                        for field in list.fields() {
 +                            let field_name = field.name()?.to_string();
 +
 +                            let l_name = &format!("l_{}", field_name);
 +                            l_fields.push(gen_record_pat_field(&field_name, l_name));
 +
 +                            let r_name = &format!("r_{}", field_name);
 +                            r_fields.push(gen_record_pat_field(&field_name, r_name));
 +
 +                            let lhs = make::expr_path(make::ext::ident_path(l_name));
 +                            let rhs = make::expr_path(make::ext::ident_path(r_name));
 +                            let cmp = make::expr_bin_op(
 +                                lhs,
 +                                BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
 +                                rhs,
 +                            );
 +                            expr = gen_eq_chain(expr, cmp);
 +                        }
 +
 +                        let left = gen_record_pat(gen_variant_path(&variant)?, l_fields);
 +                        let right = gen_record_pat(gen_variant_path(&variant)?, r_fields);
 +                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
 +
 +                        if let Some(expr) = expr {
 +                            arms.push(make::match_arm(Some(tuple.into()), None, expr));
 +                        }
 +                    }
 +
 +                    Some(ast::FieldList::TupleFieldList(list)) => {
 +                        let mut expr = None;
 +                        let mut l_fields = vec![];
 +                        let mut r_fields = vec![];
 +
 +                        for (i, _) in list.fields().enumerate() {
 +                            let field_name = format!("{}", i);
 +
 +                            let l_name = format!("l{}", field_name);
 +                            l_fields.push(gen_tuple_field(&l_name));
 +
 +                            let r_name = format!("r{}", field_name);
 +                            r_fields.push(gen_tuple_field(&r_name));
 +
 +                            let lhs = make::expr_path(make::ext::ident_path(&l_name));
 +                            let rhs = make::expr_path(make::ext::ident_path(&r_name));
 +                            let cmp = make::expr_bin_op(
 +                                lhs,
 +                                BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
 +                                rhs,
 +                            );
 +                            expr = gen_eq_chain(expr, cmp);
 +                        }
 +
 +                        let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
 +                        let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
 +                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
 +
 +                        if let Some(expr) = expr {
 +                            arms.push(make::match_arm(Some(tuple.into()), None, expr));
 +                        }
 +                    }
 +                    None => continue,
 +                }
 +            }
 +
 +            let expr = match arms.len() {
 +                0 => eq_check,
 +                _ => {
 +                    if n_cases > arms.len() {
 +                        let lhs = make::wildcard_pat().into();
 +                        arms.push(make::match_arm(Some(lhs), None, eq_check));
 +                    }
 +
 +                    let match_target = make::expr_tuple(vec![lhs_name, rhs_name]);
 +                    let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
 +                    make::expr_match(match_target, list)
 +                }
 +            };
 +
 +            make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
 +        }
 +        ast::Adt::Struct(strukt) => match strukt.field_list() {
 +            Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                let mut expr = None;
 +                for field in field_list.fields() {
 +                    let lhs = make::expr_path(make::ext::ident_path("self"));
 +                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
 +                    let rhs = make::expr_path(make::ext::ident_path("other"));
 +                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
 +                    let cmp =
 +                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
 +                    expr = gen_eq_chain(expr, cmp);
 +                }
 +                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
 +            }
 +
 +            Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                let mut expr = None;
 +                for (i, _) in field_list.fields().enumerate() {
 +                    let idx = format!("{}", i);
 +                    let lhs = make::expr_path(make::ext::ident_path("self"));
 +                    let lhs = make::expr_field(lhs, &idx);
 +                    let rhs = make::expr_path(make::ext::ident_path("other"));
 +                    let rhs = make::expr_field(rhs, &idx);
 +                    let cmp =
 +                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
 +                    expr = gen_eq_chain(expr, cmp);
 +                }
 +                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
 +            }
 +
 +            // No fields in the body means there's nothing to hash.
 +            None => {
 +                let expr = make::expr_literal("true").into();
 +                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
 +            }
 +        },
 +    };
 +
 +    ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +    Some(())
 +}
 +
 +fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
++    stdx::always!(func.name().map_or(false, |name| name.text() == "partial_cmp"));
 +    fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
 +        let mut arms = vec![];
 +
 +        let variant_name =
 +            make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
 +        let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
 +        arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block()));
 +
 +        arms.push(make::match_arm(
 +            [make::ident_pat(false, false, make::name("ord")).into()],
 +            None,
 +            make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
 +        ));
 +        let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
 +        Some(make::expr_stmt(make::expr_match(match_target, list)).into())
 +    }
 +
 +    fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
 +        let rhs = make::expr_ref(rhs, false);
 +        let method = make::name_ref("partial_cmp");
 +        make::expr_method_call(lhs, method, make::arg_list(Some(rhs)))
 +    }
 +
 +    // FIXME: return `None` if the trait carries a generic type; we can only
 +    // generate this code `Self` for the time being.
 +
 +    let body = match adt {
 +        // `PartialOrd` cannot be derived for unions, so no default impl can be provided.
 +        ast::Adt::Union(_) => return None,
 +        // `core::mem::Discriminant` does not implement `PartialOrd` in stable Rust today.
 +        ast::Adt::Enum(_) => return None,
 +        ast::Adt::Struct(strukt) => match strukt.field_list() {
 +            Some(ast::FieldList::RecordFieldList(field_list)) => {
 +                let mut exprs = vec![];
 +                for field in field_list.fields() {
 +                    let lhs = make::expr_path(make::ext::ident_path("self"));
 +                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
 +                    let rhs = make::expr_path(make::ext::ident_path("other"));
 +                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
 +                    let ord = gen_partial_cmp_call(lhs, rhs);
 +                    exprs.push(ord);
 +                }
 +
 +                let tail = exprs.pop();
 +                let stmts = exprs
 +                    .into_iter()
 +                    .map(gen_partial_eq_match)
 +                    .collect::<Option<Vec<ast::Stmt>>>()?;
 +                make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1))
 +            }
 +
 +            Some(ast::FieldList::TupleFieldList(field_list)) => {
 +                let mut exprs = vec![];
 +                for (i, _) in field_list.fields().enumerate() {
 +                    let idx = format!("{}", i);
 +                    let lhs = make::expr_path(make::ext::ident_path("self"));
 +                    let lhs = make::expr_field(lhs, &idx);
 +                    let rhs = make::expr_path(make::ext::ident_path("other"));
 +                    let rhs = make::expr_field(rhs, &idx);
 +                    let ord = gen_partial_cmp_call(lhs, rhs);
 +                    exprs.push(ord);
 +                }
 +                let tail = exprs.pop();
 +                let stmts = exprs
 +                    .into_iter()
 +                    .map(gen_partial_eq_match)
 +                    .collect::<Option<Vec<ast::Stmt>>>()?;
 +                make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1))
 +            }
 +
++            // No fields in the body means there's nothing to compare.
 +            None => {
 +                let expr = make::expr_literal("true").into();
 +                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
 +            }
 +        },
 +    };
 +
 +    ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
 +    Some(())
 +}
 +
 +fn make_discriminant() -> Option<ast::Expr> {
 +    Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?))
 +}
index 27482ea489be75ffb87d250f08b50852f6d16887,0000000000000000000000000000000000000000..27c3ccb35a1eaf263eb8610fce1ccfe1fc8bd5ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,636 -1,0 +1,637 @@@
 +//! See `CompletionItem` structure.
 +
 +use std::fmt;
 +
 +use hir::{Documentation, Mutability};
 +use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind};
 +use smallvec::SmallVec;
 +use stdx::{impl_from, never};
 +use syntax::{SmolStr, TextRange, TextSize};
 +use text_edit::TextEdit;
 +
 +use crate::{
 +    context::{CompletionContext, PathCompletionCtx},
 +    render::{render_path_resolution, RenderContext},
 +};
 +
 +/// `CompletionItem` describes a single completion variant in the editor pop-up.
 +/// It is basically a POD with various properties. To construct a
 +/// `CompletionItem`, use `new` method and the `Builder` struct.
 +#[derive(Clone)]
 +pub struct CompletionItem {
 +    /// Label in the completion pop up which identifies completion.
 +    label: SmolStr,
 +    /// Range of identifier that is being completed.
 +    ///
 +    /// It should be used primarily for UI, but we also use this to convert
 +    /// generic TextEdit into LSP's completion edit (see conv.rs).
 +    ///
 +    /// `source_range` must contain the completion offset. `text_edit` should
 +    /// start with what `source_range` points to, or VSCode will filter out the
 +    /// completion silently.
 +    source_range: TextRange,
 +    /// What happens when user selects this item.
 +    ///
 +    /// Typically, replaces `source_range` with new identifier.
 +    text_edit: TextEdit,
 +    is_snippet: bool,
 +
 +    /// What item (struct, function, etc) are we completing.
 +    kind: CompletionItemKind,
 +
 +    /// Lookup is used to check if completion item indeed can complete current
 +    /// ident.
 +    ///
 +    /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
 +    /// contains `bar` sub sequence), and `quux` will rejected.
 +    lookup: Option<SmolStr>,
 +
 +    /// Additional info to show in the UI pop up.
 +    detail: Option<String>,
 +    documentation: Option<Documentation>,
 +
 +    /// Whether this item is marked as deprecated
 +    deprecated: bool,
 +
 +    /// If completing a function call, ask the editor to show parameter popup
 +    /// after completion.
 +    trigger_call_info: bool,
 +
 +    /// We use this to sort completion. Relevance records facts like "do the
 +    /// types align precisely?". We can't sort by relevances directly, they are
 +    /// only partially ordered.
 +    ///
 +    /// Note that Relevance ignores fuzzy match score. We compute Relevance for
 +    /// all possible items, and then separately build an ordered completion list
 +    /// based on relevance and fuzzy matching with the already typed identifier.
 +    relevance: CompletionRelevance,
 +
 +    /// Indicates that a reference or mutable reference to this variable is a
 +    /// possible match.
 +    ref_match: Option<(Mutability, TextSize)>,
 +
 +    /// The import data to add to completion's edits.
 +    import_to_add: SmallVec<[LocatedImport; 1]>,
 +}
 +
 +// We use custom debug for CompletionItem to make snapshot tests more readable.
 +impl fmt::Debug for CompletionItem {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let mut s = f.debug_struct("CompletionItem");
 +        s.field("label", &self.label()).field("source_range", &self.source_range());
 +        if self.text_edit().len() == 1 {
 +            let atom = &self.text_edit().iter().next().unwrap();
 +            s.field("delete", &atom.delete);
 +            s.field("insert", &atom.insert);
 +        } else {
 +            s.field("text_edit", &self.text_edit);
 +        }
 +        s.field("kind", &self.kind());
 +        if self.lookup() != self.label() {
 +            s.field("lookup", &self.lookup());
 +        }
 +        if let Some(detail) = self.detail() {
 +            s.field("detail", &detail);
 +        }
 +        if let Some(documentation) = self.documentation() {
 +            s.field("documentation", &documentation);
 +        }
 +        if self.deprecated {
 +            s.field("deprecated", &true);
 +        }
 +
 +        if self.relevance != CompletionRelevance::default() {
 +            s.field("relevance", &self.relevance);
 +        }
 +
 +        if let Some((mutability, offset)) = &self.ref_match {
 +            s.field("ref_match", &format!("&{}@{offset:?}", mutability.as_keyword_for_ref()));
 +        }
 +        if self.trigger_call_info {
 +            s.field("trigger_call_info", &true);
 +        }
 +        s.finish()
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
 +pub struct CompletionRelevance {
 +    /// This is set in cases like these:
 +    ///
 +    /// ```
 +    /// fn f(spam: String) {}
 +    /// fn main {
 +    ///     let spam = 92;
 +    ///     f($0) // name of local matches the name of param
 +    /// }
 +    /// ```
 +    pub exact_name_match: bool,
 +    /// See CompletionRelevanceTypeMatch doc comments for cases where this is set.
 +    pub type_match: Option<CompletionRelevanceTypeMatch>,
 +    /// This is set in cases like these:
 +    ///
 +    /// ```
 +    /// fn foo(a: u32) {
 +    ///     let b = 0;
 +    ///     $0 // `a` and `b` are local
 +    /// }
 +    /// ```
 +    pub is_local: bool,
 +    /// This is set when trait items are completed in an impl of that trait.
 +    pub is_item_from_trait: bool,
 +    /// This is set when an import is suggested whose name is already imported.
 +    pub is_name_already_imported: bool,
 +    /// This is set for completions that will insert a `use` item.
 +    pub requires_import: bool,
 +    /// Set for method completions of the `core::ops` and `core::cmp` family.
 +    pub is_op_method: bool,
 +    /// Set for item completions that are private but in the workspace.
 +    pub is_private_editable: bool,
 +    /// Set for postfix snippet item completions
 +    pub postfix_match: Option<CompletionRelevancePostfixMatch>,
 +    /// This is set for type inference results
 +    pub is_definite: bool,
 +}
 +
 +#[derive(Debug, Clone, Copy, Eq, PartialEq)]
 +pub enum CompletionRelevanceTypeMatch {
 +    /// This is set in cases like these:
 +    ///
 +    /// ```
 +    /// enum Option<T> { Some(T), None }
 +    /// fn f(a: Option<u32>) {}
 +    /// fn main {
 +    ///     f(Option::N$0) // type `Option<T>` could unify with `Option<u32>`
 +    /// }
 +    /// ```
 +    CouldUnify,
 +    /// This is set in cases like these:
 +    ///
 +    /// ```
 +    /// fn f(spam: String) {}
 +    /// fn main {
 +    ///     let foo = String::new();
 +    ///     f($0) // type of local matches the type of param
 +    /// }
 +    /// ```
 +    Exact,
 +}
 +
 +#[derive(Debug, Clone, Copy, Eq, PartialEq)]
 +pub enum CompletionRelevancePostfixMatch {
 +    /// Set in cases when item is postfix, but not exact
 +    NonExact,
 +    /// This is set in cases like these:
 +    ///
 +    /// ```
 +    /// (a > b).not$0
 +    /// ```
 +    ///
 +    /// Basically, we want to guarantee that postfix snippets always takes
 +    /// precedence over everything else.
 +    Exact,
 +}
 +
 +impl CompletionRelevance {
 +    /// Provides a relevance score. Higher values are more relevant.
 +    ///
 +    /// The absolute value of the relevance score is not meaningful, for
 +    /// example a value of 0 doesn't mean "not relevant", rather
 +    /// it means "least relevant". The score value should only be used
 +    /// for relative ordering.
 +    ///
 +    /// See is_relevant if you need to make some judgement about score
 +    /// in an absolute sense.
 +    pub fn score(self) -> u32 {
 +        let mut score = 0;
 +        let CompletionRelevance {
 +            exact_name_match,
 +            type_match,
 +            is_local,
 +            is_item_from_trait,
 +            is_name_already_imported,
 +            requires_import,
 +            is_op_method,
 +            is_private_editable,
 +            postfix_match,
 +            is_definite,
 +        } = self;
 +
 +        // lower rank private things
 +        if !is_private_editable {
 +            score += 1;
 +        }
 +        // lower rank trait op methods
 +        if !is_op_method {
 +            score += 10;
 +        }
 +        // lower rank for conflicting import names
 +        if !is_name_already_imported {
 +            score += 1;
 +        }
 +        // lower rank for items that don't need an import
 +        if !requires_import {
 +            score += 1;
 +        }
 +        if exact_name_match {
 +            score += 10;
 +        }
 +        score += match postfix_match {
 +            Some(CompletionRelevancePostfixMatch::Exact) => 100,
 +            Some(CompletionRelevancePostfixMatch::NonExact) => 0,
 +            None => 3,
 +        };
 +        score += match type_match {
 +            Some(CompletionRelevanceTypeMatch::Exact) => 8,
 +            Some(CompletionRelevanceTypeMatch::CouldUnify) => 3,
 +            None => 0,
 +        };
 +        // slightly prefer locals
 +        if is_local {
 +            score += 1;
 +        }
 +        if is_item_from_trait {
 +            score += 1;
 +        }
 +        if is_definite {
 +            score += 10;
 +        }
 +        score
 +    }
 +
 +    /// Returns true when the score for this threshold is above
 +    /// some threshold such that we think it is especially likely
 +    /// to be relevant.
 +    pub fn is_relevant(&self) -> bool {
 +        self.score() > 0
 +    }
 +}
 +
 +/// The type of the completion item.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 +pub enum CompletionItemKind {
 +    SymbolKind(SymbolKind),
 +    Binding,
 +    BuiltinType,
 +    InferredType,
 +    Keyword,
 +    Method,
 +    Snippet,
 +    UnresolvedReference,
 +}
 +
 +impl_from!(SymbolKind for CompletionItemKind);
 +
 +impl CompletionItemKind {
 +    #[cfg(test)]
 +    pub(crate) fn tag(&self) -> &'static str {
 +        match self {
 +            CompletionItemKind::SymbolKind(kind) => match kind {
 +                SymbolKind::Attribute => "at",
 +                SymbolKind::BuiltinAttr => "ba",
 +                SymbolKind::Const => "ct",
 +                SymbolKind::ConstParam => "cp",
 +                SymbolKind::Derive => "de",
++                SymbolKind::DeriveHelper => "dh",
 +                SymbolKind::Enum => "en",
 +                SymbolKind::Field => "fd",
 +                SymbolKind::Function => "fn",
 +                SymbolKind::Impl => "im",
 +                SymbolKind::Label => "lb",
 +                SymbolKind::LifetimeParam => "lt",
 +                SymbolKind::Local => "lc",
 +                SymbolKind::Macro => "ma",
 +                SymbolKind::Module => "md",
 +                SymbolKind::SelfParam => "sp",
 +                SymbolKind::SelfType => "sy",
 +                SymbolKind::Static => "sc",
 +                SymbolKind::Struct => "st",
 +                SymbolKind::ToolModule => "tm",
 +                SymbolKind::Trait => "tt",
 +                SymbolKind::TypeAlias => "ta",
 +                SymbolKind::TypeParam => "tp",
 +                SymbolKind::Union => "un",
 +                SymbolKind::ValueParam => "vp",
 +                SymbolKind::Variant => "ev",
 +            },
 +            CompletionItemKind::Binding => "bn",
 +            CompletionItemKind::BuiltinType => "bt",
 +            CompletionItemKind::InferredType => "it",
 +            CompletionItemKind::Keyword => "kw",
 +            CompletionItemKind::Method => "me",
 +            CompletionItemKind::Snippet => "sn",
 +            CompletionItemKind::UnresolvedReference => "??",
 +        }
 +    }
 +}
 +
 +impl CompletionItem {
 +    pub(crate) fn new(
 +        kind: impl Into<CompletionItemKind>,
 +        source_range: TextRange,
 +        label: impl Into<SmolStr>,
 +    ) -> Builder {
 +        let label = label.into();
 +        Builder {
 +            source_range,
 +            label,
 +            insert_text: None,
 +            is_snippet: false,
 +            trait_name: None,
 +            detail: None,
 +            documentation: None,
 +            lookup: None,
 +            kind: kind.into(),
 +            text_edit: None,
 +            deprecated: false,
 +            trigger_call_info: false,
 +            relevance: CompletionRelevance::default(),
 +            ref_match: None,
 +            imports_to_add: Default::default(),
 +        }
 +    }
 +
 +    /// What user sees in pop-up in the UI.
 +    pub fn label(&self) -> &str {
 +        &self.label
 +    }
 +    pub fn source_range(&self) -> TextRange {
 +        self.source_range
 +    }
 +
 +    pub fn text_edit(&self) -> &TextEdit {
 +        &self.text_edit
 +    }
 +    /// Whether `text_edit` is a snippet (contains `$0` markers).
 +    pub fn is_snippet(&self) -> bool {
 +        self.is_snippet
 +    }
 +
 +    /// Short one-line additional information, like a type
 +    pub fn detail(&self) -> Option<&str> {
 +        self.detail.as_deref()
 +    }
 +    /// A doc-comment
 +    pub fn documentation(&self) -> Option<Documentation> {
 +        self.documentation.clone()
 +    }
 +    /// What string is used for filtering.
 +    pub fn lookup(&self) -> &str {
 +        self.lookup.as_deref().unwrap_or(&self.label)
 +    }
 +
 +    pub fn kind(&self) -> CompletionItemKind {
 +        self.kind
 +    }
 +
 +    pub fn deprecated(&self) -> bool {
 +        self.deprecated
 +    }
 +
 +    pub fn relevance(&self) -> CompletionRelevance {
 +        self.relevance
 +    }
 +
 +    pub fn trigger_call_info(&self) -> bool {
 +        self.trigger_call_info
 +    }
 +
 +    pub fn ref_match(&self) -> Option<(Mutability, TextSize, CompletionRelevance)> {
 +        // Relevance of the ref match should be the same as the original
 +        // match, but with exact type match set because self.ref_match
 +        // is only set if there is an exact type match.
 +        let mut relevance = self.relevance;
 +        relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact);
 +
 +        self.ref_match.map(|(mutability, offset)| (mutability, offset, relevance))
 +    }
 +
 +    pub fn imports_to_add(&self) -> &[LocatedImport] {
 +        &self.import_to_add
 +    }
 +}
 +
 +/// A helper to make `CompletionItem`s.
 +#[must_use]
 +#[derive(Clone)]
 +pub(crate) struct Builder {
 +    source_range: TextRange,
 +    imports_to_add: SmallVec<[LocatedImport; 1]>,
 +    trait_name: Option<SmolStr>,
 +    label: SmolStr,
 +    insert_text: Option<String>,
 +    is_snippet: bool,
 +    detail: Option<String>,
 +    documentation: Option<Documentation>,
 +    lookup: Option<SmolStr>,
 +    kind: CompletionItemKind,
 +    text_edit: Option<TextEdit>,
 +    deprecated: bool,
 +    trigger_call_info: bool,
 +    relevance: CompletionRelevance,
 +    ref_match: Option<(Mutability, TextSize)>,
 +}
 +
 +impl Builder {
 +    pub(crate) fn from_resolution(
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        local_name: hir::Name,
 +        resolution: hir::ScopeDef,
 +    ) -> Self {
 +        render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution)
 +    }
 +
 +    pub(crate) fn build(self) -> CompletionItem {
 +        let _p = profile::span("item::Builder::build");
 +
 +        let mut label = self.label;
 +        let mut lookup = self.lookup;
 +        let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 +
 +        if let [import_edit] = &*self.imports_to_add {
 +            // snippets can have multiple imports, but normal completions only have up to one
 +            if let Some(original_path) = import_edit.original_path.as_ref() {
 +                lookup = lookup.or_else(|| Some(label.clone()));
 +                label = SmolStr::from(format!("{} (use {})", label, original_path));
 +            }
 +        } else if let Some(trait_name) = self.trait_name {
 +            label = SmolStr::from(format!("{} (as {})", label, trait_name));
 +        }
 +
 +        let text_edit = match self.text_edit {
 +            Some(it) => it,
 +            None => TextEdit::replace(self.source_range, insert_text),
 +        };
 +
 +        CompletionItem {
 +            source_range: self.source_range,
 +            label,
 +            text_edit,
 +            is_snippet: self.is_snippet,
 +            detail: self.detail,
 +            documentation: self.documentation,
 +            lookup,
 +            kind: self.kind,
 +            deprecated: self.deprecated,
 +            trigger_call_info: self.trigger_call_info,
 +            relevance: self.relevance,
 +            ref_match: self.ref_match,
 +            import_to_add: self.imports_to_add,
 +        }
 +    }
 +    pub(crate) fn lookup_by(&mut self, lookup: impl Into<SmolStr>) -> &mut Builder {
 +        self.lookup = Some(lookup.into());
 +        self
 +    }
 +    pub(crate) fn label(&mut self, label: impl Into<SmolStr>) -> &mut Builder {
 +        self.label = label.into();
 +        self
 +    }
 +    pub(crate) fn trait_name(&mut self, trait_name: SmolStr) -> &mut Builder {
 +        self.trait_name = Some(trait_name);
 +        self
 +    }
 +    pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder {
 +        self.insert_text = Some(insert_text.into());
 +        self
 +    }
 +    pub(crate) fn insert_snippet(
 +        &mut self,
 +        cap: SnippetCap,
 +        snippet: impl Into<String>,
 +    ) -> &mut Builder {
 +        let _ = cap;
 +        self.is_snippet = true;
 +        self.insert_text(snippet)
 +    }
 +    pub(crate) fn text_edit(&mut self, edit: TextEdit) -> &mut Builder {
 +        self.text_edit = Some(edit);
 +        self
 +    }
 +    pub(crate) fn snippet_edit(&mut self, _cap: SnippetCap, edit: TextEdit) -> &mut Builder {
 +        self.is_snippet = true;
 +        self.text_edit(edit)
 +    }
 +    pub(crate) fn detail(&mut self, detail: impl Into<String>) -> &mut Builder {
 +        self.set_detail(Some(detail))
 +    }
 +    pub(crate) fn set_detail(&mut self, detail: Option<impl Into<String>>) -> &mut Builder {
 +        self.detail = detail.map(Into::into);
 +        if let Some(detail) = &self.detail {
 +            if never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
 +                self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
 +            }
 +        }
 +        self
 +    }
 +    #[allow(unused)]
 +    pub(crate) fn documentation(&mut self, docs: Documentation) -> &mut Builder {
 +        self.set_documentation(Some(docs))
 +    }
 +    pub(crate) fn set_documentation(&mut self, docs: Option<Documentation>) -> &mut Builder {
 +        self.documentation = docs.map(Into::into);
 +        self
 +    }
 +    pub(crate) fn set_deprecated(&mut self, deprecated: bool) -> &mut Builder {
 +        self.deprecated = deprecated;
 +        self
 +    }
 +    pub(crate) fn set_relevance(&mut self, relevance: CompletionRelevance) -> &mut Builder {
 +        self.relevance = relevance;
 +        self
 +    }
 +    pub(crate) fn trigger_call_info(&mut self) -> &mut Builder {
 +        self.trigger_call_info = true;
 +        self
 +    }
 +    pub(crate) fn add_import(&mut self, import_to_add: LocatedImport) -> &mut Builder {
 +        self.imports_to_add.push(import_to_add);
 +        self
 +    }
 +    pub(crate) fn ref_match(&mut self, mutability: Mutability, offset: TextSize) -> &mut Builder {
 +        self.ref_match = Some((mutability, offset));
 +        self
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use itertools::Itertools;
 +    use test_utils::assert_eq_text;
 +
 +    use super::{
 +        CompletionRelevance, CompletionRelevancePostfixMatch, CompletionRelevanceTypeMatch,
 +    };
 +
 +    /// Check that these are CompletionRelevance are sorted in ascending order
 +    /// by their relevance score.
 +    ///
 +    /// We want to avoid making assertions about the absolute score of any
 +    /// item, but we do want to assert whether each is >, <, or == to the
 +    /// others.
 +    ///
 +    /// If provided vec![vec![a], vec![b, c], vec![d]], then this will assert:
 +    ///     a.score < b.score == c.score < d.score
 +    fn check_relevance_score_ordered(expected_relevance_order: Vec<Vec<CompletionRelevance>>) {
 +        let expected = format!("{:#?}", &expected_relevance_order);
 +
 +        let actual_relevance_order = expected_relevance_order
 +            .into_iter()
 +            .flatten()
 +            .map(|r| (r.score(), r))
 +            .sorted_by_key(|(score, _r)| *score)
 +            .fold(
 +                (u32::MIN, vec![vec![]]),
 +                |(mut currently_collecting_score, mut out), (score, r)| {
 +                    if currently_collecting_score == score {
 +                        out.last_mut().unwrap().push(r);
 +                    } else {
 +                        currently_collecting_score = score;
 +                        out.push(vec![r]);
 +                    }
 +                    (currently_collecting_score, out)
 +                },
 +            )
 +            .1;
 +
 +        let actual = format!("{:#?}", &actual_relevance_order);
 +
 +        assert_eq_text!(&expected, &actual);
 +    }
 +
 +    #[test]
 +    fn relevance_score() {
 +        use CompletionRelevance as Cr;
 +        let default = Cr::default();
 +        // This test asserts that the relevance score for these items is ascending, and
 +        // that any items in the same vec have the same score.
 +        let expected_relevance_order = vec![
 +            vec![],
 +            vec![Cr { is_op_method: true, is_private_editable: true, ..default }],
 +            vec![Cr { is_op_method: true, ..default }],
 +            vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }],
 +            vec![Cr { is_private_editable: true, ..default }],
 +            vec![default],
 +            vec![Cr { is_local: true, ..default }],
 +            vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::CouldUnify), ..default }],
 +            vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::Exact), ..default }],
 +            vec![Cr { exact_name_match: true, ..default }],
 +            vec![Cr { exact_name_match: true, is_local: true, ..default }],
 +            vec![Cr {
 +                exact_name_match: true,
 +                type_match: Some(CompletionRelevanceTypeMatch::Exact),
 +                ..default
 +            }],
 +            vec![Cr {
 +                exact_name_match: true,
 +                type_match: Some(CompletionRelevanceTypeMatch::Exact),
 +                is_local: true,
 +                ..default
 +            }],
 +            vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::Exact), ..default }],
 +        ];
 +
 +        check_relevance_score_ordered(expected_relevance_order);
 +    }
 +}
index 3f25b294e01802d99628dccc68dc2999fff7f8db,0000000000000000000000000000000000000000..9b25964a6086e704e0c4ca5ef5676cf1f985127c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1879 -1,0 +1,1913 @@@
-         receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name).into()),
 +//! `render` module provides utilities for rendering completion suggestions
 +//! into code pieces that will be presented to user.
 +
 +pub(crate) mod macro_;
 +pub(crate) mod function;
 +pub(crate) mod const_;
 +pub(crate) mod pattern;
 +pub(crate) mod type_alias;
 +pub(crate) mod variant;
 +pub(crate) mod union_literal;
 +pub(crate) mod literal;
 +
 +use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
 +use ide_db::{
 +    helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
 +};
 +use syntax::{AstNode, SmolStr, SyntaxKind, TextRange};
 +
 +use crate::{
 +    context::{DotAccess, PathCompletionCtx, PathKind, PatternContext},
 +    item::{Builder, CompletionRelevanceTypeMatch},
 +    render::{
 +        function::render_fn,
 +        literal::render_variant_lit,
 +        macro_::{render_macro, render_macro_pat},
 +    },
 +    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
 +};
 +/// Interface for data and methods required for items rendering.
 +#[derive(Debug, Clone)]
 +pub(crate) struct RenderContext<'a> {
 +    completion: &'a CompletionContext<'a>,
 +    is_private_editable: bool,
 +    import_to_add: Option<LocatedImport>,
 +}
 +
 +impl<'a> RenderContext<'a> {
 +    pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
 +        RenderContext { completion, is_private_editable: false, import_to_add: None }
 +    }
 +
 +    pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {
 +        self.is_private_editable = private_editable;
 +        self
 +    }
 +
 +    pub(crate) fn import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self {
 +        self.import_to_add = import_to_add;
 +        self
 +    }
 +
 +    fn snippet_cap(&self) -> Option<SnippetCap> {
 +        self.completion.config.snippet_cap
 +    }
 +
 +    fn db(&self) -> &'a RootDatabase {
 +        self.completion.db
 +    }
 +
 +    fn source_range(&self) -> TextRange {
 +        self.completion.source_range()
 +    }
 +
 +    fn completion_relevance(&self) -> CompletionRelevance {
 +        CompletionRelevance {
 +            is_private_editable: self.is_private_editable,
 +            requires_import: self.import_to_add.is_some(),
 +            ..Default::default()
 +        }
 +    }
 +
 +    fn is_immediately_after_macro_bang(&self) -> bool {
 +        self.completion.token.kind() == SyntaxKind::BANG
 +            && self
 +                .completion
 +                .token
 +                .parent()
 +                .map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL)
 +    }
 +
 +    fn is_deprecated(&self, def: impl HasAttrs) -> bool {
 +        let attrs = def.attrs(self.db());
 +        attrs.by_key("deprecated").exists()
 +    }
 +
 +    fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
 +        let db = self.db();
 +        let assoc = match as_assoc_item.as_assoc_item(db) {
 +            Some(assoc) => assoc,
 +            None => return false,
 +        };
 +
 +        let is_assoc_deprecated = match assoc {
 +            hir::AssocItem::Function(it) => self.is_deprecated(it),
 +            hir::AssocItem::Const(it) => self.is_deprecated(it),
 +            hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
 +        };
 +        is_assoc_deprecated
 +            || assoc
 +                .containing_trait_or_trait_impl(db)
 +                .map(|trait_| self.is_deprecated(trait_))
 +                .unwrap_or(false)
 +    }
 +
 +    // FIXME: remove this
 +    fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
 +        def.docs(self.db())
 +    }
 +}
 +
 +pub(crate) fn render_field(
 +    ctx: RenderContext<'_>,
 +    dot_access: &DotAccess,
 +    receiver: Option<hir::Name>,
 +    field: hir::Field,
 +    ty: &hir::Type,
 +) -> CompletionItem {
 +    let is_deprecated = ctx.is_deprecated(field);
 +    let name = field.name(ctx.db());
 +    let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str());
 +    let mut item = CompletionItem::new(
 +        SymbolKind::Field,
 +        ctx.source_range(),
-     item.insert_text(escaped_name);
++        field_with_receiver(receiver.as_ref(), &name),
 +    );
 +    item.set_relevance(CompletionRelevance {
 +        type_match: compute_type_match(ctx.completion, ty),
 +        exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
 +        ..CompletionRelevance::default()
 +    });
 +    item.detail(ty.display(ctx.db()).to_string())
 +        .set_documentation(field.docs(ctx.db()))
 +        .set_deprecated(is_deprecated)
 +        .lookup_by(name.clone());
-         receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
++    item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name));
 +    if let Some(receiver) = &dot_access.receiver {
 +        if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
 +            if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
 +                item.ref_match(ref_match, original.syntax().text_range().start());
 +            }
 +        }
 +    }
 +    item.build()
 +}
 +
++fn field_with_receiver(receiver: Option<&hir::Name>, field_name: &str) -> SmolStr {
++    receiver
++        .map_or_else(|| field_name.into(), |receiver| format!("{}.{}", receiver, field_name).into())
++}
++
 +pub(crate) fn render_tuple_field(
 +    ctx: RenderContext<'_>,
 +    receiver: Option<hir::Name>,
 +    field: usize,
 +    ty: &hir::Type,
 +) -> CompletionItem {
 +    let mut item = CompletionItem::new(
 +        SymbolKind::Field,
 +        ctx.source_range(),
++        field_with_receiver(receiver.as_ref(), &field.to_string()),
 +    );
 +    item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
 +    item.build()
 +}
 +
 +pub(crate) fn render_type_inference(
 +    ty_string: String,
 +    ctx: &CompletionContext<'_>,
 +) -> CompletionItem {
 +    let mut builder =
 +        CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
 +    builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
 +    builder.build()
 +}
 +
 +pub(crate) fn render_path_resolution(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    local_name: hir::Name,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    render_resolution_path(ctx, path_ctx, local_name, None, resolution)
 +}
 +
 +pub(crate) fn render_pattern_resolution(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    local_name: hir::Name,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution)
 +}
 +
 +pub(crate) fn render_resolution_with_import(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    import_edit: LocatedImport,
 +) -> Option<Builder> {
 +    let resolution = ScopeDef::from(import_edit.original_item);
 +    let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
 +
 +    Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution))
 +}
 +
 +pub(crate) fn render_resolution_with_import_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    import_edit: LocatedImport,
 +) -> Option<Builder> {
 +    let resolution = ScopeDef::from(import_edit.original_item);
 +    let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
 +    Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))
 +}
 +
 +fn scope_def_to_name(
 +    resolution: ScopeDef,
 +    ctx: &RenderContext<'_>,
 +    import_edit: &LocatedImport,
 +) -> Option<hir::Name> {
 +    Some(match resolution {
 +        ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
 +        ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
 +        ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
 +        _ => item_name(ctx.db(), import_edit.original_item)?,
 +    })
 +}
 +
 +fn render_resolution_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    local_name: hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +    use hir::ModuleDef::*;
 +
 +    match resolution {
 +        ScopeDef::ModuleDef(Macro(mac)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_macro_pat(ctx, pattern_ctx, local_name, mac);
 +        }
 +        _ => (),
 +    }
 +
 +    render_resolution_simple_(ctx, &local_name, import_to_add, resolution)
 +}
 +
 +fn render_resolution_path(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    local_name: hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +    use hir::ModuleDef::*;
 +
 +    match resolution {
 +        ScopeDef::ModuleDef(Macro(mac)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_macro(ctx, path_ctx, local_name, mac);
 +        }
 +        ScopeDef::ModuleDef(Function(func)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_fn(ctx, path_ctx, Some(local_name), func);
 +        }
 +        ScopeDef::ModuleDef(Variant(var)) => {
 +            let ctx = ctx.clone().import_to_add(import_to_add.clone());
 +            if let Some(item) =
 +                render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None)
 +            {
 +                return item;
 +            }
 +        }
 +        _ => (),
 +    }
 +
 +    let completion = ctx.completion;
 +    let cap = ctx.snippet_cap();
 +    let db = completion.db;
 +    let config = completion.config;
 +
 +    let name = local_name.to_smol_str();
 +    let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
 +    if local_name.escaped().is_escaped() {
 +        item.insert_text(local_name.escaped().to_smol_str());
 +    }
 +    // Add `<>` for generic types
 +    let type_path_no_ty_args = matches!(
 +        path_ctx,
 +        PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. }
 +    ) && config.callable.is_some();
 +    if type_path_no_ty_args {
 +        if let Some(cap) = cap {
 +            let has_non_default_type_params = match resolution {
 +                ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db),
 +                ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => {
 +                    it.has_non_default_type_params(db)
 +                }
 +                _ => false,
 +            };
 +
 +            if has_non_default_type_params {
 +                cov_mark::hit!(inserts_angle_brackets_for_generics);
 +                item.lookup_by(name.clone())
 +                    .label(SmolStr::from_iter([&name, "<…>"]))
 +                    .trigger_call_info()
 +                    .insert_snippet(cap, format!("{}<$0>", local_name.escaped()));
 +            }
 +        }
 +    }
 +    if let ScopeDef::Local(local) = resolution {
 +        let ty = local.ty(db);
 +        if !ty.is_unknown() {
 +            item.detail(ty.display(db).to_string());
 +        }
 +
 +        item.set_relevance(CompletionRelevance {
 +            type_match: compute_type_match(completion, &ty),
 +            exact_name_match: compute_exact_name_match(completion, &name),
 +            is_local: true,
 +            ..CompletionRelevance::default()
 +        });
 +
 +        if let Some(ref_match) = compute_ref_match(completion, &ty) {
 +            item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
 +        }
 +    };
 +    item
 +}
 +
 +fn render_resolution_simple_(
 +    ctx: RenderContext<'_>,
 +    local_name: &hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +
 +    let db = ctx.db();
 +    let ctx = ctx.import_to_add(import_to_add);
 +    let kind = res_to_kind(resolution);
 +
 +    let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str());
 +    item.set_relevance(ctx.completion_relevance())
 +        .set_documentation(scope_def_docs(db, resolution))
 +        .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
 +
 +    if let Some(import_to_add) = ctx.import_to_add {
 +        item.add_import(import_to_add);
 +    }
 +    item
 +}
 +
 +fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind {
 +    use hir::ModuleDef::*;
 +    match resolution {
 +        ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
 +        ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
 +        ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +        ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),
 +        ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
 +        ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
 +            hir::Adt::Struct(_) => SymbolKind::Struct,
 +            hir::Adt::Union(_) => SymbolKind::Union,
 +            hir::Adt::Enum(_) => SymbolKind::Enum,
 +        }),
 +        ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
 +        ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
 +        ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
 +        ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
 +        ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
 +        ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
 +            hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
 +            hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
 +            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
 +        }),
 +        ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
 +        ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
 +        ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
 +            CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
 +        }
 +    }
 +}
 +
 +fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
 +    use hir::ModuleDef::*;
 +    match resolution {
 +        ScopeDef::ModuleDef(Module(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Const(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Static(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
 +        _ => None,
 +    }
 +}
 +
 +fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool {
 +    match resolution {
 +        ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it),
 +        ScopeDef::GenericParam(it) => ctx.is_deprecated(it),
 +        ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it),
 +        _ => false,
 +    }
 +}
 +
 +fn compute_type_match(
 +    ctx: &CompletionContext<'_>,
 +    completion_ty: &hir::Type,
 +) -> Option<CompletionRelevanceTypeMatch> {
 +    let expected_type = ctx.expected_type.as_ref()?;
 +
 +    // We don't ever consider unit type to be an exact type match, since
 +    // nearly always this is not meaningful to the user.
 +    if expected_type.is_unit() {
 +        return None;
 +    }
 +
 +    if completion_ty == expected_type {
 +        Some(CompletionRelevanceTypeMatch::Exact)
 +    } else if expected_type.could_unify_with(ctx.db, completion_ty) {
 +        Some(CompletionRelevanceTypeMatch::CouldUnify)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) -> bool {
 +    ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
 +}
 +
 +fn compute_ref_match(
 +    ctx: &CompletionContext<'_>,
 +    completion_ty: &hir::Type,
 +) -> Option<hir::Mutability> {
 +    let expected_type = ctx.expected_type.as_ref()?;
 +    if completion_ty != expected_type {
 +        let expected_type_without_ref = expected_type.remove_ref()?;
 +        if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
 +            cov_mark::hit!(suggest_ref);
 +            let mutability = if expected_type.is_mutable_reference() {
 +                hir::Mutability::Mut
 +            } else {
 +                hir::Mutability::Shared
 +            };
 +            return Some(mutability);
 +        };
 +    }
 +    None
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::cmp;
 +
 +    use expect_test::{expect, Expect};
 +    use ide_db::SymbolKind;
 +    use itertools::Itertools;
 +
 +    use crate::{
 +        item::CompletionRelevanceTypeMatch,
 +        tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
 +        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
 +    };
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
 +        let actual = do_completion(ra_fixture, kind.into());
 +        expect.assert_debug_eq(&actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
 +        let actual: Vec<_> =
 +            kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
 +        expect.assert_debug_eq(&actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
 +        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
 +        actual.retain(|it| kinds.contains(&it.kind()));
 +        actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
 +        check_relevance_(actual, expect);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance(ra_fixture: &str, expect: Expect) {
 +        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
 +        actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
 +        actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
 +        actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
 +        actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
 +        check_relevance_(actual, expect);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {
 +        let actual = actual
 +            .into_iter()
 +            .flat_map(|it| {
 +                let mut items = vec![];
 +
 +                let tag = it.kind().tag();
 +                let relevance = display_relevance(it.relevance());
 +                items.push(format!("{} {} {}\n", tag, it.label(), relevance));
 +
 +                if let Some((mutability, _offset, relevance)) = it.ref_match() {
 +                    let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label());
 +                    let relevance = display_relevance(relevance);
 +
 +                    items.push(format!("{} {} {}\n", tag, label, relevance));
 +                }
 +
 +                items
 +            })
 +            .collect::<String>();
 +
 +        expect.assert_eq(&actual);
 +
 +        fn display_relevance(relevance: CompletionRelevance) -> String {
 +            let relevance_factors = vec![
 +                (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
 +                (
 +                    relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
 +                    "type_could_unify",
 +                ),
 +                (relevance.exact_name_match, "name"),
 +                (relevance.is_local, "local"),
 +                (
 +                    relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact),
 +                    "snippet",
 +                ),
 +                (relevance.is_op_method, "op_method"),
 +                (relevance.requires_import, "requires_import"),
 +            ]
 +            .into_iter()
 +            .filter_map(|(cond, desc)| if cond { Some(desc) } else { None })
 +            .join("+");
 +
 +            format!("[{}]", relevance_factors)
 +        }
 +    }
 +
 +    #[test]
 +    fn enum_detail_includes_record_fields() {
 +        check(
 +            r#"
 +enum Foo { Foo { x: i32, y: i32 } }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo {…}",
 +                        source_range: 54..56,
 +                        delete: 54..56,
 +                        insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "Foo { x: i32, y: i32 }",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_detail_includes_tuple_fields() {
 +        check(
 +            r#"
 +enum Foo { Foo (i32, i32) }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo(…)",
 +                        source_range: 46..48,
 +                        delete: 46..48,
 +                        insert: "Foo(${1:()}, ${2:()})$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "Foo(i32, i32)",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn fn_detail_includes_args_and_return_type() {
 +        check(
 +            r#"
 +fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
 +
 +fn main() { fo$0 }
 +"#,
 +            SymbolKind::Function,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "foo(…)",
 +                        source_range: 68..70,
 +                        delete: 68..70,
 +                        insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "foo",
 +                        detail: "fn(u32, u32, T) -> (u32, T)",
 +                        trigger_call_info: true,
 +                    },
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 68..70,
 +                        delete: 68..70,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_detail_just_name_for_unit() {
 +        check(
 +            r#"
 +enum Foo { Foo }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo",
 +                        source_range: 35..37,
 +                        delete: 35..37,
 +                        insert: "Foo$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "Foo",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn lookup_enums_by_two_qualifiers() {
 +        check_kinds(
 +            r#"
 +mod m {
 +    pub enum Spam { Foo, Bar(i32) }
 +}
 +fn main() { let _: m::Spam = S$0 }
 +"#,
 +            &[
 +                CompletionItemKind::SymbolKind(SymbolKind::Function),
 +                CompletionItemKind::SymbolKind(SymbolKind::Module),
 +                CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +            ],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                    CompletionItem {
 +                        label: "m",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m",
 +                        kind: SymbolKind(
 +                            Module,
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "m::Spam::Bar(…)",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m::Spam::Bar(${1:()})$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        lookup: "Spam::Bar(…)",
 +                        detail: "m::Spam::Bar(i32)",
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                Exact,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                    CompletionItem {
 +                        label: "m::Spam::Foo",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m::Spam::Foo$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        lookup: "Spam::Foo",
 +                        detail: "m::Spam::Foo",
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                Exact,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn sets_deprecated_flag_in_items() {
 +        check(
 +            r#"
 +#[deprecated]
 +fn something_deprecated() {}
 +
 +fn main() { som$0 }
 +"#,
 +            SymbolKind::Function,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 56..59,
 +                        delete: 56..59,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                    CompletionItem {
 +                        label: "something_deprecated()",
 +                        source_range: 56..59,
 +                        delete: 56..59,
 +                        insert: "something_deprecated()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "something_deprecated",
 +                        detail: "fn()",
 +                        deprecated: true,
 +                    },
 +                ]
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +struct A { #[deprecated] the_field: u32 }
 +fn foo() { A { the$0 } }
 +"#,
 +            SymbolKind::Field,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "the_field",
 +                        source_range: 57..60,
 +                        delete: 57..60,
 +                        insert: "the_field",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "u32",
 +                        deprecated: true,
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                CouldUnify,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn renders_docs() {
 +        check_kinds(
 +            r#"
 +struct S {
 +    /// Field docs
 +    foo:
 +}
 +impl S {
 +    /// Method docs
 +    fn bar(self) { self.$0 }
 +}"#,
 +            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "bar()",
 +                        source_range: 94..94,
 +                        delete: 94..94,
 +                        insert: "bar()$0",
 +                        kind: Method,
 +                        lookup: "bar",
 +                        detail: "fn(self)",
 +                        documentation: Documentation(
 +                            "Method docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "foo",
 +                        source_range: 94..94,
 +                        delete: 94..94,
 +                        insert: "foo",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "{unknown}",
 +                        documentation: Documentation(
 +                            "Field docs",
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +
 +        check_kinds(
 +            r#"
 +use self::my$0;
 +
 +/// mod docs
 +mod my { }
 +
 +/// enum docs
 +enum E {
 +    /// variant docs
 +    V
 +}
 +use self::E::*;
 +"#,
 +            &[
 +                CompletionItemKind::SymbolKind(SymbolKind::Module),
 +                CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +                CompletionItemKind::SymbolKind(SymbolKind::Enum),
 +            ],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "my",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "my",
 +                        kind: SymbolKind(
 +                            Module,
 +                        ),
 +                        documentation: Documentation(
 +                            "mod docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "V",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "V$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "V",
 +                        documentation: Documentation(
 +                            "variant docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "E",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "E",
 +                        kind: SymbolKind(
 +                            Enum,
 +                        ),
 +                        documentation: Documentation(
 +                            "enum docs",
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn dont_render_attrs() {
 +        check(
 +            r#"
 +struct S;
 +impl S {
 +    #[inline]
 +    fn the_method(&self) { }
 +}
 +fn foo(s: S) { s.$0 }
 +"#,
 +            CompletionItemKind::Method,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "the_method()",
 +                        source_range: 81..81,
 +                        delete: 81..81,
 +                        insert: "the_method()$0",
 +                        kind: Method,
 +                        lookup: "the_method",
 +                        detail: "fn(&self)",
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn no_call_parens_if_fn_ptr_needed() {
 +        cov_mark::check!(no_call_parens_if_fn_ptr_needed);
 +        check_edit(
 +            "foo",
 +            r#"
 +fn foo(foo: u8, bar: u8) {}
 +struct ManualVtable { f: fn(u8, u8) }
 +
 +fn main() -> ManualVtable {
 +    ManualVtable { f: f$0 }
 +}
 +"#,
 +            r#"
 +fn foo(foo: u8, bar: u8) {}
 +struct ManualVtable { f: fn(u8, u8) }
 +
 +fn main() -> ManualVtable {
 +    ManualVtable { f: foo }
 +}
 +"#,
 +        );
 +        check_edit(
 +            "type",
 +            r#"
 +struct RawIdentTable { r#type: u32 }
 +
 +fn main() -> RawIdentTable {
 +    RawIdentTable { t$0: 42 }
 +}
 +"#,
 +            r#"
 +struct RawIdentTable { r#type: u32 }
 +
 +fn main() -> RawIdentTable {
 +    RawIdentTable { r#type: 42 }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_parens_in_use_item() {
 +        check_edit(
 +            "foo",
 +            r#"
 +mod m { pub fn foo() {} }
 +use crate::m::f$0;
 +"#,
 +            r#"
 +mod m { pub fn foo() {} }
 +use crate::m::foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_parens_in_call() {
 +        check_edit(
 +            "foo",
 +            r#"
 +fn foo(x: i32) {}
 +fn main() { f$0(); }
 +"#,
 +            r#"
 +fn foo(x: i32) {}
 +fn main() { foo(); }
 +"#,
 +        );
 +        check_edit(
 +            "foo",
 +            r#"
 +struct Foo;
 +impl Foo { fn foo(&self){} }
 +fn f(foo: &Foo) { foo.f$0(); }
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo { fn foo(&self){} }
 +fn f(foo: &Foo) { foo.foo(); }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inserts_angle_brackets_for_generics() {
 +        cov_mark::check!(inserts_angle_brackets_for_generics);
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Vec<$0>)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +type Vec<T> = (T,);
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +type Vec<T> = (T,);
 +fn foo(xs: Vec<$0>)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T = i128> {}
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +struct Vec<T = i128> {}
 +fn foo(xs: Vec)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Ve$0<i128>)
 +"#,
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Vec<i128>)
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn active_param_relevance() {
 +        check_relevance(
 +            r#"
 +struct S { foo: i64, bar: u32, baz: u32 }
 +fn test(bar: u32) { }
 +fn foo(s: S) { test(s.$0) }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn record_field_relevances() {
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn foo(a: A) { B { bar: a.$0 }; }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn record_field_and_call_relevances() {
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn f(foo: i64) {  }
 +fn foo(a: A) { B { bar: f(a.$0) }; }
 +"#,
 +            expect![[r#"
 +                fd foo [type+name]
 +                fd bar []
 +                fd baz []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn f(foo: i64) {  }
 +fn foo(a: A) { f(B { bar: a.$0 }); }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn prioritize_exact_ref_match() {
 +        check_relevance(
 +            r#"
 +struct WorldSnapshot { _f: () };
 +fn go(world: &WorldSnapshot) { go(w$0) }
 +"#,
 +            expect![[r#"
 +                lc world [type+name+local]
 +                st WorldSnapshot {…} []
 +                st &WorldSnapshot {…} [type]
 +                st WorldSnapshot []
 +                fn go(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn too_many_arguments() {
 +        cov_mark::check!(too_many_arguments);
 +        check_relevance(
 +            r#"
 +struct Foo;
 +fn f(foo: &Foo) { f(foo, w$0) }
 +"#,
 +            expect![[r#"
 +                lc foo [local]
 +                st Foo []
 +                fn f(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_fn_type_and_name_match() {
 +        check_relevance(
 +            r#"
 +struct A { bar: u8 }
 +fn baz() -> u8 { 0 }
 +fn bar() -> u8 { 0 }
 +fn f() { A { bar: b$0 }; }
 +"#,
 +            expect![[r#"
 +                fn bar() [type+name]
 +                fn baz() [type]
 +                st A []
 +                fn f() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_method_type_and_name_match() {
 +        check_relevance(
 +            r#"
 +fn baz(aaa: u32){}
 +struct Foo;
 +impl Foo {
 +fn aaa(&self) -> u32 { 0 }
 +fn bbb(&self) -> u32 { 0 }
 +fn ccc(&self) -> u64 { 0 }
 +}
 +fn f() {
 +    baz(Foo.$0
 +}
 +"#,
 +            expect![[r#"
 +                me aaa() [type+name]
 +                me bbb() [type]
 +                me ccc() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_method_name_match_only() {
 +        check_relevance(
 +            r#"
 +fn baz(aaa: u32){}
 +struct Foo;
 +impl Foo {
 +fn aaa(&self) -> u64 { 0 }
 +}
 +fn f() {
 +    baz(Foo.$0
 +}
 +"#,
 +            expect![[r#"
 +                me aaa() [name]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_ref_mut() {
 +        cov_mark::check!(suggest_ref);
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut s = S;
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc s [name+local]
 +                lc &mut s [type+name+local]
 +                st S []
 +                st &mut S [type]
 +                st S []
 +                fn main() []
 +                fn foo(…) []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut s = S;
 +    foo(&mut $0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc s [type+name+local]
 +                st S [type]
 +                st S []
 +                fn main() []
 +                fn foo(…) []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut ssss = S;
 +    foo(&mut s$0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc ssss [type+local]
 +                st S [type]
 +                st S []
 +                fn main() []
 +                fn foo(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_deref() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn foo(s: &S) {}
 +
 +fn main() {
 +    let t = T(S);
 +    let m = 123;
 +
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc m [local]
 +                lc t [local]
 +                lc &t [type+local]
 +                st S []
 +                st &S [type]
 +                st T []
 +                st S []
 +                fn main() []
 +                fn foo(…) []
 +                md core []
 +                tt Sized []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn suggest_deref_mut() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref_mut
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +impl core::ops::DerefMut for T {
 +    fn deref_mut(&mut self) -> &mut Self::Target {
 +        &mut self.0
 +    }
 +}
 +
 +fn foo(s: &mut S) {}
 +
 +fn main() {
 +    let t = T(S);
 +    let m = 123;
 +
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc m [local]
 +                lc t [local]
 +                lc &mut t [type+local]
 +                st S []
 +                st &mut S [type]
 +                st T []
 +                st S []
 +                fn main() []
 +                fn foo(…) []
 +                md core []
 +                tt Sized []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn locals() {
 +        check_relevance(
 +            r#"
 +fn foo(bar: u32) {
 +    let baz = 0;
 +
 +    f$0
 +}
 +"#,
 +            expect![[r#"
 +                lc baz [local]
 +                lc bar [local]
 +                fn foo(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_owned() {
 +        check_relevance(
 +            r#"
 +enum Foo { A, B }
 +fn foo() {
 +    bar($0);
 +}
 +fn bar(t: Foo) {}
 +"#,
 +            expect![[r#"
 +                ev Foo::A [type]
 +                ev Foo::B [type]
 +                en Foo []
 +                fn bar(…) []
 +                fn foo() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_ref() {
 +        check_relevance(
 +            r#"
 +enum Foo { A, B }
 +fn foo() {
 +    bar($0);
 +}
 +fn bar(t: &Foo) {}
 +"#,
 +            expect![[r#"
 +                ev Foo::A []
 +                ev &Foo::A [type]
 +                ev Foo::B []
 +                ev &Foo::B [type]
 +                en Foo []
 +                fn bar(…) []
 +                fn foo() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_deref_fn_ret() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn foo(s: &S) {}
 +fn bar() -> T {}
 +
 +fn main() {
 +    foo($0);
 +}
 +"#,
 +            expect![[r#"
 +                st S []
 +                st &S [type]
 +                st T []
 +                st S []
 +                fn main() []
 +                fn bar() []
 +                fn &bar() [type]
 +                fn foo(…) []
 +                md core []
 +                tt Sized []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn op_function_relevances() {
 +        check_relevance(
 +            r#"
 +#[lang = "sub"]
 +trait Sub {
 +    fn sub(self, other: Self) -> Self { self }
 +}
 +impl Sub for u32 {}
 +fn foo(a: u32) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me sub(…) (as Sub) [op_method]
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn new() -> Self {}
 +}
 +#[lang = "eq"]
 +pub trait PartialEq<Rhs: ?Sized = Self> {
 +    fn eq(&self, other: &Rhs) -> bool;
 +    fn ne(&self, other: &Rhs) -> bool;
 +}
 +
 +impl PartialEq for Foo {}
 +fn main() {
 +    Foo::$0
 +}
 +"#,
 +            expect![[r#"
 +                fn new() []
 +                me eq(…) (as PartialEq) [op_method]
 +                me ne(…) (as PartialEq) [op_method]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_field_method_ref() {
 +        check_kinds(
 +            r#"
 +struct Foo { bar: u32 }
 +impl Foo { fn baz(&self) -> u32 { 0 } }
 +
 +fn foo(f: Foo) { let _: &u32 = f.b$0 }
 +"#,
 +            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "baz()",
 +                        source_range: 98..99,
 +                        delete: 98..99,
 +                        insert: "baz()$0",
 +                        kind: Method,
 +                        lookup: "baz",
 +                        detail: "fn(&self) -> u32",
 +                        ref_match: "&@96",
 +                    },
 +                    CompletionItem {
 +                        label: "bar",
 +                        source_range: 98..99,
 +                        delete: 98..99,
 +                        insert: "bar",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "u32",
 +                        ref_match: "&@96",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn qualified_path_ref() {
 +        check_kinds(
 +            r#"
 +struct S;
 +
 +struct T;
 +impl T {
 +    fn foo() -> S {}
 +}
 +
 +fn bar(s: &S) {}
 +
 +fn main() {
 +    bar(T::$0);
 +}
 +"#,
 +            &[CompletionItemKind::SymbolKind(SymbolKind::Function)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "foo()",
 +                        source_range: 95..95,
 +                        delete: 95..95,
 +                        insert: "foo()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "foo",
 +                        detail: "fn() -> S",
 +                        ref_match: "&@92",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_enum() {
 +        check_relevance(
 +            r#"
 +enum Foo<T> { A(T), B }
 +// bar() should not be an exact type match
 +// because the generic parameters are different
 +fn bar() -> Foo<u8> { Foo::B }
 +// FIXME baz() should be an exact type match
 +// because the types could unify, but it currently
 +// is not. This is due to the T here being
 +// TyKind::Placeholder rather than TyKind::Missing.
 +fn baz<T>() -> Foo<T> { Foo::B }
 +fn foo() {
 +    let foo: Foo<u32> = Foo::B;
 +    let _: Foo<u32> = f$0;
 +}
 +"#,
 +            expect![[r#"
 +                lc foo [type+local]
 +                ev Foo::A(…) [type_could_unify]
 +                ev Foo::B [type_could_unify]
 +                fn foo() []
 +                en Foo []
 +                fn baz() []
 +                fn bar() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn postfix_exact_match_is_high_priority() {
 +        cov_mark::check!(postfix_exact_match_is_high_priority);
 +        check_relevance_for_kinds(
 +            r#"
 +mod ops {
 +    pub trait Not {
 +        type Output;
 +        fn not(self) -> Self::Output;
 +    }
 +
 +    impl Not for bool {
 +        type Output = bool;
 +        fn not(self) -> bool { if self { false } else { true }}
 +    }
 +}
 +
 +fn main() {
 +    let _: bool = (9 > 2).not$0;
 +}
 +    "#,
 +            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
 +            expect![[r#"
 +                sn not [snippet]
 +                me not() (use ops::Not) [type_could_unify+requires_import]
 +                sn if []
 +                sn while []
 +                sn ref []
 +                sn refm []
 +                sn match []
 +                sn box []
 +                sn dbg []
 +                sn dbgr []
 +                sn call []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn postfix_inexact_match_is_low_priority() {
 +        cov_mark::check!(postfix_inexact_match_is_low_priority);
 +        check_relevance_for_kinds(
 +            r#"
 +struct S;
 +impl S {
 +    fn f(&self) {}
 +}
 +fn main() {
 +    S.$0
 +}
 +    "#,
 +            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
 +            expect![[r#"
 +                me f() []
 +                sn ref []
 +                sn refm []
 +                sn match []
 +                sn box []
 +                sn dbg []
 +                sn dbgr []
 +                sn call []
 +                sn let []
 +                sn letm []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn flyimport_reduced_relevance() {
 +        check_relevance(
 +            r#"
 +mod std {
 +    pub mod io {
 +        pub trait BufRead {}
 +        pub struct BufReader;
 +        pub struct BufWriter;
 +    }
 +}
 +struct Buffer;
 +
 +fn f() {
 +    Buf$0
 +}
 +"#,
 +            expect![[r#"
 +                md std []
 +                st Buffer []
 +                fn f() []
 +                tt BufRead (use std::io::BufRead) [requires_import]
 +                st BufReader (use std::io::BufReader) [requires_import]
 +                st BufWriter (use std::io::BufWriter) [requires_import]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_struct_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +mod m { pub struct r#type {} }
 +fn main() {
 +    let r#type = m::t$0;
 +}
 +"#,
 +            r#"
 +mod m { pub struct r#type {} }
 +fn main() {
 +    let r#type = m::r#type;
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_fn_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +mod m { pub fn r#type {} }
 +fn main() {
 +    m::t$0
 +}
 +"#,
 +            r#"
 +mod m { pub fn r#type {} }
 +fn main() {
 +    m::r#type()$0
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_macro_with_raw_identifier() {
 +        check_edit(
 +            "let!",
 +            r#"
 +macro_rules! r#let { () => {} }
 +fn main() {
 +    $0
 +}
 +"#,
 +            r#"
 +macro_rules! r#let { () => {} }
 +fn main() {
 +    r#let!($0)
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_variant_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +enum A { r#type }
 +fn main() {
 +    let a = A::t$0
 +}
 +"#,
 +            r#"
 +enum A { r#type }
 +fn main() {
 +    let a = A::r#type$0
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_field_with_raw_identifier() {
 +        check_edit(
 +            "fn",
 +            r#"
 +mod r#type {
 +    pub struct r#struct {
 +        pub r#fn: u32
 +    }
 +}
 +
 +fn main() {
 +    let a = r#type::r#struct {};
 +    a.$0
 +}
 +"#,
 +            r#"
 +mod r#type {
 +    pub struct r#struct {
 +        pub r#fn: u32
 +    }
 +}
 +
 +fn main() {
 +    let a = r#type::r#struct {};
 +    a.r#fn
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_const_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +struct r#struct {}
 +impl r#struct { pub const r#type: u8 = 1; }
 +fn main() {
 +    r#struct::t$0
 +}
 +"#,
 +            r#"
 +struct r#struct {}
 +impl r#struct { pub const r#type: u8 = 1; }
 +fn main() {
 +    r#struct::r#type
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_type_alias_with_raw_identifier() {
 +        check_edit(
 +            "type type",
 +            r#"
 +struct r#struct {}
 +trait r#trait { type r#type; }
 +impl r#trait for r#struct { type t$0 }
 +"#,
 +            r#"
 +struct r#struct {}
 +trait r#trait { type r#type; }
 +impl r#trait for r#struct { type r#type = $0; }
++"#,
++        )
++    }
++
++    #[test]
++    fn field_access_includes_self() {
++        check_edit(
++            "length",
++            r#"
++struct S {
++    length: i32
++}
++
++impl S {
++    fn some_fn(&self) {
++        let l = len$0
++    }
++}
++"#,
++            r#"
++struct S {
++    length: i32
++}
++
++impl S {
++    fn some_fn(&self) {
++        let l = self.length
++    }
++}
 +"#,
 +        )
 +    }
 +}
index 692a3157203086df6124551781f137183c9a9485,0000000000000000000000000000000000000000..aeaca00ec65cc3aeb053cf2731ddfd26e877fccf
mode 100644,000000..100644
--- /dev/null
@@@ -1,540 -1,0 +1,545 @@@
-     Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, Field, Function,
-     GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, Name,
-     PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility,
 +//! `NameDefinition` keeps information about the element we want to search references for.
 +//! The element is represented by `NameKind`. It's located inside some `container` and
 +//! has a `visibility`, which defines a search scope.
 +//! Note that the reference search is possible for not all of the classified items.
 +
 +// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 +
 +use arrayvec::ArrayVec;
 +use hir::{
-             | Definition::Label(_) => return None,
++    Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field,
++    Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef,
++    Name, PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility,
 +};
 +use stdx::impl_from;
 +use syntax::{
 +    ast::{self, AstNode},
 +    match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
 +};
 +
 +use crate::RootDatabase;
 +
 +// FIXME: a more precise name would probably be `Symbol`?
 +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 +pub enum Definition {
 +    Macro(Macro),
 +    Field(Field),
 +    Module(Module),
 +    Function(Function),
 +    Adt(Adt),
 +    Variant(Variant),
 +    Const(Const),
 +    Static(Static),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    BuiltinType(BuiltinType),
 +    SelfType(Impl),
 +    Local(Local),
 +    GenericParam(GenericParam),
 +    Label(Label),
++    DeriveHelper(DeriveHelper),
 +    BuiltinAttr(BuiltinAttr),
 +    ToolModule(ToolModule),
 +}
 +
 +impl Definition {
 +    pub fn canonical_module_path(&self, db: &RootDatabase) -> Option<impl Iterator<Item = Module>> {
 +        self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 +    }
 +
 +    pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
 +        Some(match self {
 +            Definition::Module(m) => m.krate(),
 +            _ => self.module(db)?.krate(),
 +        })
 +    }
 +
 +    pub fn module(&self, db: &RootDatabase) -> Option<Module> {
 +        let module = match self {
 +            Definition::Macro(it) => it.module(db),
 +            Definition::Module(it) => it.parent(db)?,
 +            Definition::Field(it) => it.parent_def(db).module(db),
 +            Definition::Function(it) => it.module(db),
 +            Definition::Adt(it) => it.module(db),
 +            Definition::Const(it) => it.module(db),
 +            Definition::Static(it) => it.module(db),
 +            Definition::Trait(it) => it.module(db),
 +            Definition::TypeAlias(it) => it.module(db),
 +            Definition::Variant(it) => it.module(db),
 +            Definition::SelfType(it) => it.module(db),
 +            Definition::Local(it) => it.module(db),
 +            Definition::GenericParam(it) => it.module(db),
 +            Definition::Label(it) => it.module(db),
++            Definition::DeriveHelper(it) => it.derive().module(db),
 +            Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => {
 +                return None
 +            }
 +        };
 +        Some(module)
 +    }
 +
 +    pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
 +        let vis = match self {
 +            Definition::Field(sf) => sf.visibility(db),
 +            Definition::Module(it) => it.visibility(db),
 +            Definition::Function(it) => it.visibility(db),
 +            Definition::Adt(it) => it.visibility(db),
 +            Definition::Const(it) => it.visibility(db),
 +            Definition::Static(it) => it.visibility(db),
 +            Definition::Trait(it) => it.visibility(db),
 +            Definition::TypeAlias(it) => it.visibility(db),
 +            Definition::Variant(it) => it.visibility(db),
 +            Definition::BuiltinType(_) => Visibility::Public,
 +            Definition::Macro(_) => return None,
 +            Definition::BuiltinAttr(_)
 +            | Definition::ToolModule(_)
 +            | Definition::SelfType(_)
 +            | Definition::Local(_)
 +            | Definition::GenericParam(_)
++            | Definition::Label(_)
++            | Definition::DeriveHelper(_) => return None,
 +        };
 +        Some(vis)
 +    }
 +
 +    pub fn name(&self, db: &RootDatabase) -> Option<Name> {
 +        let name = match self {
 +            Definition::Macro(it) => it.name(db),
 +            Definition::Field(it) => it.name(db),
 +            Definition::Module(it) => it.name(db)?,
 +            Definition::Function(it) => it.name(db),
 +            Definition::Adt(it) => it.name(db),
 +            Definition::Variant(it) => it.name(db),
 +            Definition::Const(it) => it.name(db)?,
 +            Definition::Static(it) => it.name(db),
 +            Definition::Trait(it) => it.name(db),
 +            Definition::TypeAlias(it) => it.name(db),
 +            Definition::BuiltinType(it) => it.name(),
 +            Definition::SelfType(_) => return None,
 +            Definition::Local(it) => it.name(db),
 +            Definition::GenericParam(it) => it.name(db),
 +            Definition::Label(it) => it.name(db),
 +            Definition::BuiltinAttr(_) => return None, // FIXME
 +            Definition::ToolModule(_) => return None,  // FIXME
++            Definition::DeriveHelper(it) => it.name(db),
 +        };
 +        Some(name)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum IdentClass {
 +    NameClass(NameClass),
 +    NameRefClass(NameRefClass),
 +}
 +
 +impl IdentClass {
 +    pub fn classify_node(
 +        sema: &Semantics<'_, RootDatabase>,
 +        node: &SyntaxNode,
 +    ) -> Option<IdentClass> {
 +        match_ast! {
 +            match node {
 +                ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
 +                ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(IdentClass::NameRefClass),
 +                ast::Lifetime(lifetime) => {
 +                    NameClass::classify_lifetime(sema, &lifetime)
 +                        .map(IdentClass::NameClass)
 +                        .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
 +                },
 +                _ => None,
 +            }
 +        }
 +    }
 +
 +    pub fn classify_token(
 +        sema: &Semantics<'_, RootDatabase>,
 +        token: &SyntaxToken,
 +    ) -> Option<IdentClass> {
 +        let parent = token.parent()?;
 +        Self::classify_node(sema, &parent)
 +    }
 +
 +    pub fn classify_lifetime(
 +        sema: &Semantics<'_, RootDatabase>,
 +        lifetime: &ast::Lifetime,
 +    ) -> Option<IdentClass> {
 +        NameRefClass::classify_lifetime(sema, lifetime)
 +            .map(IdentClass::NameRefClass)
 +            .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
 +    }
 +
 +    pub fn definitions(self) -> ArrayVec<Definition, 2> {
 +        let mut res = ArrayVec::new();
 +        match self {
 +            IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
 +                res.push(it)
 +            }
 +            IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => {
 +                res.push(Definition::Local(local_def));
 +                res.push(Definition::Field(field_ref));
 +            }
 +            IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it),
 +            IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => {
 +                res.push(Definition::Local(local_ref));
 +                res.push(Definition::Field(field_ref));
 +            }
 +        }
 +        res
 +    }
 +}
 +
 +/// On a first blush, a single `ast::Name` defines a single definition at some
 +/// scope. That is, that, by just looking at the syntactical category, we can
 +/// unambiguously define the semantic category.
 +///
 +/// Sadly, that's not 100% true, there are special cases. To make sure that
 +/// callers handle all the special cases correctly via exhaustive matching, we
 +/// add a [`NameClass`] enum which lists all of them!
 +///
 +/// A model special case is `None` constant in pattern.
 +#[derive(Debug)]
 +pub enum NameClass {
 +    Definition(Definition),
 +    /// `None` in `if let None = Some(82) {}`.
 +    /// Syntactically, it is a name, but semantically it is a reference.
 +    ConstReference(Definition),
 +    /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces
 +    /// a definition into a local scope, and refers to an existing definition.
 +    PatFieldShorthand {
 +        local_def: Local,
 +        field_ref: Field,
 +    },
 +}
 +
 +impl NameClass {
 +    /// `Definition` defined by this name.
 +    pub fn defined(self) -> Option<Definition> {
 +        let res = match self {
 +            NameClass::Definition(it) => it,
 +            NameClass::ConstReference(_) => return None,
 +            NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
 +                Definition::Local(local_def)
 +            }
 +        };
 +        Some(res)
 +    }
 +
 +    pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
 +        let _p = profile::span("classify_name");
 +
 +        let parent = name.syntax().parent()?;
 +
 +        let definition = match_ast! {
 +            match parent {
 +                ast::Item(it) => classify_item(sema, it)?,
 +                ast::IdentPat(it) => return classify_ident_pat(sema, it),
 +                ast::Rename(it) => classify_rename(sema, it)?,
 +                ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
 +                ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
 +                ast::Variant(it) => Definition::Variant(sema.to_def(&it)?),
 +                ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
 +                ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
 +                _ => return None,
 +            }
 +        };
 +        return Some(NameClass::Definition(definition));
 +
 +        fn classify_item(
 +            sema: &Semantics<'_, RootDatabase>,
 +            item: ast::Item,
 +        ) -> Option<Definition> {
 +            let definition = match item {
 +                ast::Item::MacroRules(it) => {
 +                    Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?)
 +                }
 +                ast::Item::MacroDef(it) => {
 +                    Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?)
 +                }
 +                ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?),
 +                ast::Item::Fn(it) => {
 +                    let def = sema.to_def(&it)?;
 +                    def.as_proc_macro(sema.db)
 +                        .map(Definition::Macro)
 +                        .unwrap_or(Definition::Function(def))
 +                }
 +                ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?),
 +                ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?),
 +                ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?),
 +                ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?),
 +                ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)),
 +                ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
 +                ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
 +                _ => return None,
 +            };
 +            Some(definition)
 +        }
 +
 +        fn classify_ident_pat(
 +            sema: &Semantics<'_, RootDatabase>,
 +            ident_pat: ast::IdentPat,
 +        ) -> Option<NameClass> {
 +            if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
 +                return Some(NameClass::ConstReference(Definition::from(def)));
 +            }
 +
 +            let local = sema.to_def(&ident_pat)?;
 +            let pat_parent = ident_pat.syntax().parent();
 +            if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) {
 +                if record_pat_field.name_ref().is_none() {
 +                    if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
 +                        return Some(NameClass::PatFieldShorthand {
 +                            local_def: local,
 +                            field_ref: field,
 +                        });
 +                    }
 +                }
 +            }
 +            Some(NameClass::Definition(Definition::Local(local)))
 +        }
 +
 +        fn classify_rename(
 +            sema: &Semantics<'_, RootDatabase>,
 +            rename: ast::Rename,
 +        ) -> Option<Definition> {
 +            if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) {
 +                let path = use_tree.path()?;
 +                sema.resolve_path(&path).map(Definition::from)
 +            } else {
 +                let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?;
 +                let krate = sema.resolve_extern_crate(&extern_crate)?;
 +                let root_module = krate.root_module(sema.db);
 +                Some(Definition::Module(root_module))
 +            }
 +        }
 +    }
 +
 +    pub fn classify_lifetime(
 +        sema: &Semantics<'_, RootDatabase>,
 +        lifetime: &ast::Lifetime,
 +    ) -> Option<NameClass> {
 +        let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
 +        let parent = lifetime.syntax().parent()?;
 +
 +        if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
 +            sema.to_def(&it).map(Into::into).map(Definition::GenericParam)
 +        } else if let Some(it) = ast::Label::cast(parent) {
 +            sema.to_def(&it).map(Definition::Label)
 +        } else {
 +            None
 +        }
 +        .map(NameClass::Definition)
 +    }
 +}
 +
 +/// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
 +/// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
 +/// reference most of the time, but there are a couple of annoying exceptions.
 +///
 +/// A model special case is field shorthand syntax, which uses a single
 +/// reference to point to two different defs.
 +#[derive(Debug)]
 +pub enum NameRefClass {
 +    Definition(Definition),
 +    FieldShorthand { local_ref: Local, field_ref: Field },
 +}
 +
 +impl NameRefClass {
 +    // Note: we don't have unit-tests for this rather important function.
 +    // It is primarily exercised via goto definition tests in `ide`.
 +    pub fn classify(
 +        sema: &Semantics<'_, RootDatabase>,
 +        name_ref: &ast::NameRef,
 +    ) -> Option<NameRefClass> {
 +        let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string());
 +
 +        let parent = name_ref.syntax().parent()?;
 +
 +        if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
 +            if let Some((field, local, _)) = sema.resolve_record_field(&record_field) {
 +                let res = match local {
 +                    None => NameRefClass::Definition(Definition::Field(field)),
 +                    Some(local) => {
 +                        NameRefClass::FieldShorthand { field_ref: field, local_ref: local }
 +                    }
 +                };
 +                return Some(res);
 +            }
 +        }
 +
 +        if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) {
 +            if path.parent_path().is_none() {
 +                if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
 +                    // Only use this to resolve to macro calls for last segments as qualifiers resolve
 +                    // to modules below.
 +                    if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
 +                        return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
 +                    }
 +                }
 +            }
 +            return sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition);
 +        }
 +
 +        match_ast! {
 +            match parent {
 +                ast::MethodCallExpr(method_call) => {
 +                    sema.resolve_method_call(&method_call)
 +                        .map(Definition::Function)
 +                        .map(NameRefClass::Definition)
 +                },
 +                ast::FieldExpr(field_expr) => {
 +                    sema.resolve_field(&field_expr)
 +                        .map(Definition::Field)
 +                        .map(NameRefClass::Definition)
 +                },
 +                ast::RecordPatField(record_pat_field) => {
 +                    sema.resolve_record_pat_field(&record_pat_field)
 +                        .map(Definition::Field)
 +                        .map(NameRefClass::Definition)
 +                },
 +                ast::AssocTypeArg(_) => {
 +                    // `Trait<Assoc = Ty>`
 +                    //        ^^^^^
 +                    let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
 +                    let resolved = sema.resolve_path(&containing_path)?;
 +                    if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
 +                        if let Some(ty) = tr
 +                            .items_with_supertraits(sema.db)
 +                            .iter()
 +                            .filter_map(|&assoc| match assoc {
 +                                hir::AssocItem::TypeAlias(it) => Some(it),
 +                                _ => None,
 +                            })
 +                            .find(|alias| alias.name(sema.db).to_smol_str() == name_ref.text().as_str())
 +                        {
 +                            return Some(NameRefClass::Definition(Definition::TypeAlias(ty)));
 +                        }
 +                    }
 +                    None
 +                },
 +                ast::ExternCrate(extern_crate) => {
 +                    let krate = sema.resolve_extern_crate(&extern_crate)?;
 +                    let root_module = krate.root_module(sema.db);
 +                    Some(NameRefClass::Definition(Definition::Module(root_module)))
 +                },
 +                _ => None
 +            }
 +        }
 +    }
 +
 +    pub fn classify_lifetime(
 +        sema: &Semantics<'_, RootDatabase>,
 +        lifetime: &ast::Lifetime,
 +    ) -> Option<NameRefClass> {
 +        let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
 +        let parent = lifetime.syntax().parent()?;
 +        match parent.kind() {
 +            SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
 +                sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition)
 +            }
 +            SyntaxKind::LIFETIME_ARG
 +            | SyntaxKind::SELF_PARAM
 +            | SyntaxKind::TYPE_BOUND
 +            | SyntaxKind::WHERE_PRED
 +            | SyntaxKind::REF_TYPE => sema
 +                .resolve_lifetime_param(lifetime)
 +                .map(GenericParam::LifetimeParam)
 +                .map(Definition::GenericParam)
 +                .map(NameRefClass::Definition),
 +            // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
 +            // if our lifetime is in a LifetimeParam without being the constrained lifetime
 +            _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
 +                != Some(lifetime) =>
 +            {
 +                sema.resolve_lifetime_param(lifetime)
 +                    .map(GenericParam::LifetimeParam)
 +                    .map(Definition::GenericParam)
 +                    .map(NameRefClass::Definition)
 +            }
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl_from!(
 +    Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local,
 +    GenericParam, Label, Macro
 +    for Definition
 +);
 +
 +impl From<Impl> for Definition {
 +    fn from(impl_: Impl) -> Self {
 +        Definition::SelfType(impl_)
 +    }
 +}
 +
 +impl AsAssocItem for Definition {
 +    fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem> {
 +        match self {
 +            Definition::Function(it) => it.as_assoc_item(db),
 +            Definition::Const(it) => it.as_assoc_item(db),
 +            Definition::TypeAlias(it) => it.as_assoc_item(db),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl From<AssocItem> for Definition {
 +    fn from(assoc_item: AssocItem) -> Self {
 +        match assoc_item {
 +            AssocItem::Function(it) => Definition::Function(it),
 +            AssocItem::Const(it) => Definition::Const(it),
 +            AssocItem::TypeAlias(it) => Definition::TypeAlias(it),
 +        }
 +    }
 +}
 +
 +impl From<PathResolution> for Definition {
 +    fn from(path_resolution: PathResolution) -> Self {
 +        match path_resolution {
 +            PathResolution::Def(def) => def.into(),
 +            PathResolution::Local(local) => Definition::Local(local),
 +            PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
 +            PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
 +            PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
 +            PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
 +            PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
++            PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
 +        }
 +    }
 +}
 +
 +impl From<ModuleDef> for Definition {
 +    fn from(def: ModuleDef) -> Self {
 +        match def {
 +            ModuleDef::Module(it) => Definition::Module(it),
 +            ModuleDef::Function(it) => Definition::Function(it),
 +            ModuleDef::Adt(it) => Definition::Adt(it),
 +            ModuleDef::Variant(it) => Definition::Variant(it),
 +            ModuleDef::Const(it) => Definition::Const(it),
 +            ModuleDef::Static(it) => Definition::Static(it),
 +            ModuleDef::Trait(it) => Definition::Trait(it),
 +            ModuleDef::TypeAlias(it) => Definition::TypeAlias(it),
 +            ModuleDef::Macro(it) => Definition::Macro(it),
 +            ModuleDef::BuiltinType(it) => Definition::BuiltinType(it),
 +        }
 +    }
 +}
 +
 +impl From<Definition> for Option<ItemInNs> {
 +    fn from(def: Definition) -> Self {
 +        let item = match def {
 +            Definition::Module(it) => ModuleDef::Module(it),
 +            Definition::Function(it) => ModuleDef::Function(it),
 +            Definition::Adt(it) => ModuleDef::Adt(it),
 +            Definition::Variant(it) => ModuleDef::Variant(it),
 +            Definition::Const(it) => ModuleDef::Const(it),
 +            Definition::Static(it) => ModuleDef::Static(it),
 +            Definition::Trait(it) => ModuleDef::Trait(it),
 +            Definition::TypeAlias(it) => ModuleDef::TypeAlias(it),
 +            Definition::BuiltinType(it) => ModuleDef::BuiltinType(it),
 +            _ => return None,
 +        };
 +        Some(ItemInNs::from(item))
 +    }
 +}
index 26648b4d7638c8f0ca0560d80778ea3e6a5141e1,0000000000000000000000000000000000000000..966bba616f6277aa3a97d9dbbec808927fce05b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,245 -1,0 +1,246 @@@
 +//! 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 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 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<FxHashSet<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 d78b8758d65126afba8d59dc717e15c2b843e977,0000000000000000000000000000000000000000..40af9e6fe2ad80f04042810ab5bc500548bc60b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,286 -1,0 +1,287 @@@
-             | hir::PathResolution::ToolModule(_) => (),
 +//! 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),
 +                            )?;
 +                            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)?;
 +                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 bb466e43e752134c5030c7fffcb2685f9a5ff8b2,0000000000000000000000000000000000000000..517fe3f246d08ecfb3ee8dd59401abe1a0175f62
mode 100644,000000..100644
--- /dev/null
@@@ -1,532 -1,0 +1,540 @@@
-             ast::NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == range => {
 +//! Rename infrastructure for rust-analyzer. It is used primarily for the
 +//! literal "rename" in the ide (look for tests there), but it is also available
 +//! as a general-purpose service. For example, it is used by the fix for the
 +//! "incorrect case" diagnostic.
 +//!
 +//! It leverages the [`crate::search`] functionality to find what needs to be
 +//! renamed. The actual renames are tricky -- field shorthands need special
 +//! attention, and, when renaming modules, you also want to rename files on the
 +//! file system.
 +//!
 +//! Another can of worms are macros:
 +//!
 +//! ```ignore
 +//! macro_rules! m { () => { fn f() {} } }
 +//! m!();
 +//! fn main() {
 +//!     f() // <- rename me
 +//! }
 +//! ```
 +//!
 +//! The correct behavior in such cases is probably to show a dialog to the user.
 +//! Our current behavior is Â¯\_(ツ)_/¯.
 +use std::fmt;
 +
 +use base_db::{AnchoredPathBuf, FileId, FileRange};
 +use either::Either;
 +use hir::{FieldSource, HasSource, InFile, ModuleSource, Semantics};
 +use stdx::never;
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SyntaxKind, TextRange, T,
 +};
 +use text_edit::{TextEdit, TextEditBuilder};
 +
 +use crate::{
 +    defs::Definition,
 +    search::FileReference,
 +    source_change::{FileSystemEdit, SourceChange},
 +    syntax_helpers::node_ext::expr_as_name_ref,
 +    traits::convert_to_def_in_trait,
 +    RootDatabase,
 +};
 +
 +pub type Result<T, E = RenameError> = std::result::Result<T, E>;
 +
 +#[derive(Debug)]
 +pub struct RenameError(pub String);
 +
 +impl fmt::Display for RenameError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(&self.0, f)
 +    }
 +}
 +
 +#[macro_export]
 +macro_rules! _format_err {
 +    ($fmt:expr) => { RenameError(format!($fmt)) };
 +    ($fmt:expr, $($arg:tt)+) => { RenameError(format!($fmt, $($arg)+)) }
 +}
 +pub use _format_err as format_err;
 +
 +#[macro_export]
 +macro_rules! _bail {
 +    ($($tokens:tt)*) => { return Err(format_err!($($tokens)*)) }
 +}
 +pub use _bail as bail;
 +
 +impl Definition {
 +    pub fn rename(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
 +        new_name: &str,
 +    ) -> Result<SourceChange> {
 +        match *self {
 +            Definition::Module(module) => rename_mod(sema, module, new_name),
 +            Definition::BuiltinType(_) => {
 +                bail!("Cannot rename builtin type")
 +            }
 +            Definition::SelfType(_) => bail!("Cannot rename `Self`"),
 +            def => rename_reference(sema, def, new_name),
 +        }
 +    }
 +
 +    /// Textual range of the identifier which will change when renaming this
 +    /// `Definition`. Note that some definitions, like buitin types, can't be
 +    /// renamed.
 +    pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange> {
 +        let res = match self {
 +            Definition::Macro(mac) => {
 +                let src = mac.source(sema.db)?;
 +                let name = match &src.value {
 +                    Either::Left(it) => it.name()?,
 +                    Either::Right(it) => it.name()?,
 +                };
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::Field(field) => {
 +                let src = field.source(sema.db)?;
 +                match &src.value {
 +                    FieldSource::Named(record_field) => {
 +                        let name = record_field.name()?;
 +                        src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                    }
 +                    FieldSource::Pos(_) => None,
 +                }
 +            }
 +            Definition::Module(module) => {
 +                let src = module.declaration_source(sema.db)?;
 +                let name = src.value.name()?;
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::Function(it) => name_range(it, sema),
 +            Definition::Adt(adt) => match adt {
 +                hir::Adt::Struct(it) => name_range(it, sema),
 +                hir::Adt::Union(it) => name_range(it, sema),
 +                hir::Adt::Enum(it) => name_range(it, sema),
 +            },
 +            Definition::Variant(it) => name_range(it, sema),
 +            Definition::Const(it) => name_range(it, sema),
 +            Definition::Static(it) => name_range(it, sema),
 +            Definition::Trait(it) => name_range(it, sema),
 +            Definition::TypeAlias(it) => name_range(it, sema),
 +            Definition::Local(local) => {
 +                let src = local.source(sema.db);
 +                let name = match &src.value {
 +                    Either::Left(bind_pat) => bind_pat.name()?,
 +                    Either::Right(_) => return None,
 +                };
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::GenericParam(generic_param) => match generic_param {
 +                hir::GenericParam::LifetimeParam(lifetime_param) => {
 +                    let src = lifetime_param.source(sema.db)?;
 +                    src.with_value(src.value.lifetime()?.syntax()).original_file_range_opt(sema.db)
 +                }
 +                _ => {
 +                    let x = match generic_param {
 +                        hir::GenericParam::TypeParam(it) => it.merge(),
 +                        hir::GenericParam::ConstParam(it) => it.merge(),
 +                        hir::GenericParam::LifetimeParam(_) => return None,
 +                    };
 +                    let src = x.source(sema.db)?;
 +                    let name = match &src.value {
 +                        Either::Left(x) => x.name()?,
 +                        Either::Right(_) => return None,
 +                    };
 +                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                }
 +            },
 +            Definition::Label(label) => {
 +                let src = label.source(sema.db);
 +                let lifetime = src.value.lifetime()?;
 +                src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::BuiltinType(_) => return None,
 +            Definition::SelfType(_) => return None,
 +            Definition::BuiltinAttr(_) => return None,
 +            Definition::ToolModule(_) => return None,
++            // FIXME: This should be doable in theory
++            Definition::DeriveHelper(_) => return None,
 +        };
 +        return res;
 +
 +        fn name_range<D>(def: D, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange>
 +        where
 +            D: HasSource,
 +            D::Ast: ast::HasName,
 +        {
 +            let src = def.source(sema.db)?;
 +            let name = src.value.name()?;
 +            src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +        }
 +    }
 +}
 +
 +fn rename_mod(
 +    sema: &Semantics<'_, RootDatabase>,
 +    module: hir::Module,
 +    new_name: &str,
 +) -> Result<SourceChange> {
 +    if IdentifierKind::classify(new_name)? != IdentifierKind::Ident {
 +        bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
 +    }
 +
 +    let mut source_change = SourceChange::default();
 +
 +    if module.is_crate_root(sema.db) {
 +        return Ok(source_change);
 +    }
 +
 +    let InFile { file_id, value: def_source } = module.definition_source(sema.db);
 +    if let ModuleSource::SourceFile(..) = def_source {
 +        let anchor = file_id.original_file(sema.db);
 +
 +        let is_mod_rs = module.is_mod_rs(sema.db);
 +        let has_detached_child = module.children(sema.db).any(|child| !child.is_inline(sema.db));
 +
 +        // Module exists in a named file
 +        if !is_mod_rs {
 +            let path = format!("{}.rs", new_name);
 +            let dst = AnchoredPathBuf { anchor, path };
 +            source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst })
 +        }
 +
 +        // Rename the dir if:
 +        //  - Module source is in mod.rs
 +        //  - Module has submodules defined in separate files
 +        let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
 +            // Go up one level since the anchor is inside the dir we're trying to rename
 +            (true, _, Some(mod_name)) => {
 +                Some((format!("../{}", mod_name), format!("../{}", new_name)))
 +            }
 +            // The anchor is on the same level as target dir
 +            (false, true, Some(mod_name)) => Some((mod_name.to_string(), new_name.to_string())),
 +            _ => None,
 +        };
 +
 +        if let Some((src, dst)) = dir_paths {
 +            let src = AnchoredPathBuf { anchor, path: src };
 +            let dst = AnchoredPathBuf { anchor, path: dst };
 +            source_change.push_file_system_edit(FileSystemEdit::MoveDir {
 +                src,
 +                src_id: anchor,
 +                dst,
 +            })
 +        }
 +    }
 +
 +    if let Some(src) = module.declaration_source(sema.db) {
 +        let file_id = src.file_id.original_file(sema.db);
 +        match src.value.name() {
 +            Some(name) => {
 +                if let Some(file_range) =
 +                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                {
 +                    source_change.insert_source_edit(
 +                        file_id,
 +                        TextEdit::replace(file_range.range, new_name.to_string()),
 +                    )
 +                };
 +            }
 +            _ => never!("Module source node is missing a name"),
 +        }
 +    }
 +
 +    let def = Definition::Module(module);
 +    let usages = def.usages(sema).all();
 +    let ref_edits = usages.iter().map(|(&file_id, references)| {
 +        (file_id, source_edit_from_references(references, def, new_name))
 +    });
 +    source_change.extend(ref_edits);
 +
 +    Ok(source_change)
 +}
 +
 +fn rename_reference(
 +    sema: &Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    new_name: &str,
 +) -> Result<SourceChange> {
 +    let ident_kind = IdentifierKind::classify(new_name)?;
 +
 +    if matches!(
 +        def,
 +        Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
 +    ) {
 +        match ident_kind {
 +            IdentifierKind::Ident | IdentifierKind::Underscore => {
 +                cov_mark::hit!(rename_not_a_lifetime_ident_ref);
 +                bail!("Invalid name `{}`: not a lifetime identifier", new_name);
 +            }
 +            IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
 +        }
 +    } else {
 +        match ident_kind {
 +            IdentifierKind::Lifetime => {
 +                cov_mark::hit!(rename_not_an_ident_ref);
 +                bail!("Invalid name `{}`: not an identifier", new_name);
 +            }
 +            IdentifierKind::Ident => cov_mark::hit!(rename_non_local),
 +            IdentifierKind::Underscore => (),
 +        }
 +    }
 +
 +    let def = convert_to_def_in_trait(sema.db, def);
 +    let usages = def.usages(sema).all();
 +
 +    if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
 +        cov_mark::hit!(rename_underscore_multiple);
 +        bail!("Cannot rename reference to `_` as it is being referenced multiple times");
 +    }
 +    let mut source_change = SourceChange::default();
 +    source_change.extend(usages.iter().map(|(&file_id, references)| {
 +        (file_id, source_edit_from_references(references, def, new_name))
 +    }));
 +
 +    let mut insert_def_edit = |def| {
 +        let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
 +        source_change.insert_source_edit(file_id, edit);
 +        Ok(())
 +    };
 +    match def {
 +        Definition::Local(l) => l
 +            .associated_locals(sema.db)
 +            .iter()
 +            .try_for_each(|&local| insert_def_edit(Definition::Local(local))),
 +        def => insert_def_edit(def),
 +    }?;
 +    Ok(source_change)
 +}
 +
 +pub fn source_edit_from_references(
 +    references: &[FileReference],
 +    def: Definition,
 +    new_name: &str,
 +) -> TextEdit {
 +    let mut edit = TextEdit::builder();
 +    // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
 +    let mut edited_ranges = Vec::new();
 +    for &FileReference { range, ref name, .. } in references {
++        let name_range = name.syntax().text_range();
++        if name_range.len() != range.len() {
++            // This usage comes from a different token kind that was downmapped to a NameLike in a macro
++            // Renaming this will most likely break things syntax-wise
++            continue;
++        }
 +        let has_emitted_edit = match name {
 +            // if the ranges differ then the node is inside a macro call, we can't really attempt
 +            // to make special rewrites like shorthand syntax and such, so just rename the node in
 +            // the macro input
-             ast::NameLike::Name(name) if name.syntax().text_range() == range => {
++            ast::NameLike::NameRef(name_ref) if name_range == range => {
 +                source_edit_from_name_ref(&mut edit, name_ref, new_name, def)
 +            }
++            ast::NameLike::Name(name) if name_range == range => {
 +                source_edit_from_name(&mut edit, name, new_name)
 +            }
 +            _ => false,
 +        };
 +        if !has_emitted_edit {
 +            if !edited_ranges.contains(&range.start()) {
 +                edit.replace(range, new_name.to_string());
 +                edited_ranges.push(range.start());
 +            }
 +        }
 +    }
 +
 +    edit.finish()
 +}
 +
 +fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: &str) -> bool {
 +    if ast::RecordPatField::for_field_name(name).is_some() {
 +        if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
 +            cov_mark::hit!(rename_record_pat_field_name_split);
 +            // Foo { ref mut field } -> Foo { new_name: ref mut field }
 +            //      ^ insert `new_name: `
 +
 +            // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
 +            // other name https://github.com/rust-lang/rust-analyzer/issues/6547
 +            edit.insert(ident_pat.syntax().text_range().start(), format!("{}: ", new_name));
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn source_edit_from_name_ref(
 +    edit: &mut TextEditBuilder,
 +    name_ref: &ast::NameRef,
 +    new_name: &str,
 +    def: Definition,
 +) -> bool {
 +    if name_ref.super_token().is_some() {
 +        return true;
 +    }
 +
 +    if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
 +        let rcf_name_ref = record_field.name_ref();
 +        let rcf_expr = record_field.expr();
 +        match &(rcf_name_ref, rcf_expr.and_then(|it| expr_as_name_ref(&it))) {
 +            // field: init-expr, check if we can use a field init shorthand
 +            (Some(field_name), Some(init)) => {
 +                if field_name == name_ref {
 +                    if init.text() == new_name {
 +                        cov_mark::hit!(test_rename_field_put_init_shorthand);
 +                        // Foo { field: local } -> Foo { local }
 +                        //       ^^^^^^^ delete this
 +
 +                        // same names, we can use a shorthand here instead.
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().start();
 +                        let e = init.syntax().text_range().start();
 +                        edit.delete(TextRange::new(s, e));
 +                        return true;
 +                    }
 +                } else if init == name_ref {
 +                    if field_name.text() == new_name {
 +                        cov_mark::hit!(test_rename_local_put_init_shorthand);
 +                        // Foo { field: local } -> Foo { field }
 +                        //            ^^^^^^^ delete this
 +
 +                        // same names, we can use a shorthand here instead.
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().end();
 +                        let e = init.syntax().text_range().end();
 +                        edit.delete(TextRange::new(s, e));
 +                        return true;
 +                    }
 +                }
 +            }
 +            // init shorthand
 +            (None, Some(_)) if matches!(def, Definition::Field(_)) => {
 +                cov_mark::hit!(test_rename_field_in_field_shorthand);
 +                // Foo { field } -> Foo { new_name: field }
 +                //       ^ insert `new_name: `
 +                let offset = name_ref.syntax().text_range().start();
 +                edit.insert(offset, format!("{}: ", new_name));
 +                return true;
 +            }
 +            (None, Some(_)) if matches!(def, Definition::Local(_)) => {
 +                cov_mark::hit!(test_rename_local_in_field_shorthand);
 +                // Foo { field } -> Foo { field: new_name }
 +                //            ^ insert `: new_name`
 +                let offset = name_ref.syntax().text_range().end();
 +                edit.insert(offset, format!(": {}", new_name));
 +                return true;
 +            }
 +            _ => (),
 +        }
 +    } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
 +        let rcf_name_ref = record_field.name_ref();
 +        let rcf_pat = record_field.pat();
 +        match (rcf_name_ref, rcf_pat) {
 +            // field: rename
 +            (Some(field_name), Some(ast::Pat::IdentPat(pat)))
 +                if field_name == *name_ref && pat.at_token().is_none() =>
 +            {
 +                // field name is being renamed
 +                if let Some(name) = pat.name() {
 +                    if name.text() == new_name {
 +                        cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
 +                        // Foo { field: ref mut local } -> Foo { ref mut field }
 +                        //       ^^^^^^^ delete this
 +                        //                      ^^^^^ replace this with `field`
 +
 +                        // same names, we can use a shorthand here instead/
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().start();
 +                        let e = pat.syntax().text_range().start();
 +                        edit.delete(TextRange::new(s, e));
 +                        edit.replace(name.syntax().text_range(), new_name.to_string());
 +                        return true;
 +                    }
 +                }
 +            }
 +            _ => (),
 +        }
 +    }
 +    false
 +}
 +
 +fn source_edit_from_def(
 +    sema: &Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    new_name: &str,
 +) -> Result<(FileId, TextEdit)> {
 +    let FileRange { file_id, range } = def
 +        .range_for_rename(sema)
 +        .ok_or_else(|| format_err!("No identifier available to rename"))?;
 +
 +    let mut edit = TextEdit::builder();
 +    if let Definition::Local(local) = def {
 +        if let Either::Left(pat) = local.source(sema.db).value {
 +            // special cases required for renaming fields/locals in Record patterns
 +            if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {
 +                let name_range = pat.name().unwrap().syntax().text_range();
 +                if let Some(name_ref) = pat_field.name_ref() {
 +                    if new_name == name_ref.text() && pat.at_token().is_none() {
 +                        // Foo { field: ref mut local } -> Foo { ref mut field }
 +                        //       ^^^^^^ delete this
 +                        //                      ^^^^^ replace this with `field`
 +                        cov_mark::hit!(test_rename_local_put_init_shorthand_pat);
 +                        edit.delete(
 +                            name_ref
 +                                .syntax()
 +                                .text_range()
 +                                .cover_offset(pat.syntax().text_range().start()),
 +                        );
 +                        edit.replace(name_range, name_ref.text().to_string());
 +                    } else {
 +                        // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 }
 +                        // Foo { field: ref mut local } -> Foo { field: ref mut new_name }
 +                        //                      ^^^^^ replace this with `new_name`
 +                        edit.replace(name_range, new_name.to_string());
 +                    }
 +                } else {
 +                    // Foo { ref mut field } -> Foo { field: ref mut new_name }
 +                    //      ^ insert `field: `
 +                    //               ^^^^^ replace this with `new_name`
 +                    edit.insert(
 +                        pat.syntax().text_range().start(),
 +                        format!("{}: ", pat_field.field_name().unwrap()),
 +                    );
 +                    edit.replace(name_range, new_name.to_string());
 +                }
 +            }
 +        }
 +    }
 +    if edit.is_empty() {
 +        edit.replace(range, new_name.to_string());
 +    }
 +    Ok((file_id, edit.finish()))
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq)]
 +pub enum IdentifierKind {
 +    Ident,
 +    Lifetime,
 +    Underscore,
 +}
 +
 +impl IdentifierKind {
 +    pub fn classify(new_name: &str) -> Result<IdentifierKind> {
 +        match parser::LexedStr::single_token(new_name) {
 +            Some(res) => match res {
 +                (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
 +                (T![_], _) => Ok(IdentifierKind::Underscore),
 +                (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
 +                    Ok(IdentifierKind::Lifetime)
 +                }
 +                (SyntaxKind::LIFETIME_IDENT, _) => {
 +                    bail!("Invalid name `{}`: not a lifetime identifier", new_name)
 +                }
 +                (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
 +                (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
 +            },
 +            None => bail!("Invalid name `{}`: not an identifier", new_name),
 +        }
 +    }
 +}
index c75364084e36a26c87ea7626489760116411b164,0000000000000000000000000000000000000000..bd038cdaa068261e3738849a930ff0ec59c74e91
mode 100644,000000..100644
--- /dev/null
@@@ -1,783 -1,0 +1,785 @@@
-                 // FIXME: We don't actually see derives in derive attributes as these do not
-                 // expand to something that references the derive macro in the output.
-                 // We could get around this by doing pseudo expansions for proc_macro_derive like we
-                 // do for the derive attribute
 +//! 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::{convert::TryInto, mem, sync::Arc};
 +
 +use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 +use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashMap;
 +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: FxHashMap<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 = <FxHashMap<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,
 +    // 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: FxHashMap<FileId, Option<TextRange>>,
 +}
 +
 +impl SearchScope {
 +    fn new(entries: FxHashMap<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 = FxHashMap::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 = FxHashMap::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::<FxHashMap<_, _>>(),
 +        }
 +    }
 +
 +    /// 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 = FxHashMap::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(FxHashMap::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()))
 +                    })
 +                };
 +                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str())
 +            }
 +        };
 +        let name = match &name {
 +            Some(s) => s.as_str(),
 +            None => return,
 +        };
 +
 +        // these can't be closures because rust infers the lifetimes wrong ...
 +        fn match_indices<'a>(
 +            text: &'a str,
 +            name: &'a str,
 +            search_range: TextRange,
 +        ) -> impl Iterator<Item = TextSize> + 'a {
 +            text.match_indices(name).filter_map(move |(idx, _)| {
 +                let offset: TextSize = idx.try_into().unwrap();
 +                if !search_range.contains_inclusive(offset) {
 +                    return None;
 +                }
 +                Some(offset)
 +            })
 +        }
 +
 +        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
 +            for offset in match_indices(&text, name, 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
 +            if let Some(self_ty) = &self.include_self_kw_refs {
 +                for offset in match_indices(&text, "Self", 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));
 +
 +                let is_crate_root = module.is_crate_root(self.sema.db);
 +
 +                for (text, file_id, search_range) in scope_files(sema, &scope) {
 +                    let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 +
 +                    for offset in match_indices(&text, "super", search_range) {
 +                        for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                            if self.found_name_ref(&name_ref, sink) {
 +                                return;
 +                            }
 +                        }
 +                    }
 +                    if is_crate_root {
 +                        for offset in match_indices(&text, "crate", 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());
 +
 +                for offset in match_indices(&text, "self", 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()),
 +                    category: None,
 +                };
 +                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 None;
 +        }
 +
 +        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))
 +    }
 +}
index 30f903af50d5bd0e8eba742a19af4f42e809fa46,0000000000000000000000000000000000000000..edb1fc0919c242c9f83dc921a488f5b76813e3a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,806 -1,0 +1,837 @@@
 +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)?,
 +                        )?;
 +
 +                        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 fed327f52be52953145156e2ce4f364bec6f254a,0000000000000000000000000000000000000000..582e9fe7e808c05b933de4293d5e66bc719dba70
mode 100644,000000..100644
--- /dev/null
@@@ -1,547 -1,0 +1,549 @@@
-         | Definition::Label(_) => None,
 +//! Extracts, resolves and rewrites links and intra-doc links in markdown documentation.
 +
 +#[cfg(test)]
 +mod tests;
 +
 +mod intra_doc_links;
 +
 +use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
 +use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions};
 +use stdx::format_to;
 +use url::Url;
 +
 +use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs};
 +use ide_db::{
 +    base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase},
 +    defs::{Definition, NameClass, NameRefClass},
 +    helpers::pick_best_token,
 +    RootDatabase,
 +};
 +use syntax::{
 +    ast::{self, IsString},
 +    match_ast, AstNode, AstToken,
 +    SyntaxKind::*,
 +    SyntaxNode, SyntaxToken, TextRange, TextSize, T,
 +};
 +
 +use crate::{
 +    doc_links::intra_doc_links::{parse_intra_doc_link, strip_prefixes_suffixes},
 +    FilePosition, Semantics,
 +};
 +
 +/// Weblink to an item's documentation.
 +pub(crate) type DocumentationLink = String;
 +
 +const MARKDOWN_OPTIONS: Options =
 +    Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS);
 +
 +/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
 +pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String {
 +    let mut cb = broken_link_clone_cb;
 +    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
 +
 +    let doc = map_links(doc, |target, title| {
 +        // This check is imperfect, there's some overlap between valid intra-doc links
 +        // and valid URLs so we choose to be too eager to try to resolve what might be
 +        // a URL.
 +        if target.contains("://") {
 +            (Some(LinkType::Inline), target.to_string(), title.to_string())
 +        } else {
 +            // Two possibilities:
 +            // * path-based links: `../../module/struct.MyStruct.html`
 +            // * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
 +            if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
 +                return (None, target, title);
 +            }
 +            if let Some(target) = rewrite_url_link(db, definition, target) {
 +                return (Some(LinkType::Inline), target, title.to_string());
 +            }
 +
 +            (None, target.to_string(), title.to_string())
 +        }
 +    });
 +    let mut out = String::new();
 +    cmark_resume_with_options(
 +        doc,
 +        &mut out,
 +        None,
 +        CMarkOptions { code_block_token_count: 3, ..Default::default() },
 +    )
 +    .ok();
 +    out
 +}
 +
 +/// Remove all links in markdown documentation.
 +pub(crate) fn remove_links(markdown: &str) -> String {
 +    let mut drop_link = false;
 +
 +    let mut cb = |_: BrokenLink<'_>| {
 +        let empty = InlineStr::try_from("").unwrap();
 +        Some((CowStr::Inlined(empty), CowStr::Inlined(empty)))
 +    };
 +    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
 +    let doc = doc.filter_map(move |evt| match evt {
 +        Event::Start(Tag::Link(link_type, target, title)) => {
 +            if link_type == LinkType::Inline && target.contains("://") {
 +                Some(Event::Start(Tag::Link(link_type, target, title)))
 +            } else {
 +                drop_link = true;
 +                None
 +            }
 +        }
 +        Event::End(_) if drop_link => {
 +            drop_link = false;
 +            None
 +        }
 +        _ => Some(evt),
 +    });
 +
 +    let mut out = String::new();
 +    cmark_resume_with_options(
 +        doc,
 +        &mut out,
 +        None,
 +        CMarkOptions { code_block_token_count: 3, ..Default::default() },
 +    )
 +    .ok();
 +    out
 +}
 +
 +/// Retrieve a link to documentation for the given symbol.
 +pub(crate) fn external_docs(
 +    db: &RootDatabase,
 +    position: &FilePosition,
 +) -> Option<DocumentationLink> {
 +    let sema = &Semantics::new(db);
 +    let file = sema.parse(position.file_id).syntax().clone();
 +    let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
 +        IDENT | INT_NUMBER | T![self] => 3,
 +        T!['('] | T![')'] => 2,
 +        kind if kind.is_trivia() => 0,
 +        _ => 1,
 +    })?;
 +    let token = sema.descend_into_macros_single(token);
 +
 +    let node = token.parent()?;
 +    let definition = match_ast! {
 +        match node {
 +            ast::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
 +                NameRefClass::Definition(def) => def,
 +                NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
 +                    Definition::Field(field_ref)
 +                }
 +            },
 +            ast::Name(name) => match NameClass::classify(sema, &name)? {
 +                NameClass::Definition(it) | NameClass::ConstReference(it) => it,
 +                NameClass::PatFieldShorthand { local_def: _, field_ref } => Definition::Field(field_ref),
 +            },
 +            _ => return None,
 +        }
 +    };
 +
 +    get_doc_link(db, definition)
 +}
 +
 +/// Extracts all links from a given markdown text returning the definition text range, link-text
 +/// and the namespace if known.
 +pub(crate) fn extract_definitions_from_docs(
 +    docs: &hir::Documentation,
 +) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
 +    Parser::new_with_broken_link_callback(
 +        docs.as_str(),
 +        MARKDOWN_OPTIONS,
 +        Some(&mut broken_link_clone_cb),
 +    )
 +    .into_offset_iter()
 +    .filter_map(|(event, range)| match event {
 +        Event::Start(Tag::Link(_, target, _)) => {
 +            let (link, ns) = parse_intra_doc_link(&target);
 +            Some((
 +                TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?),
 +                link.to_string(),
 +                ns,
 +            ))
 +        }
 +        _ => None,
 +    })
 +    .collect()
 +}
 +
 +pub(crate) fn resolve_doc_path_for_def(
 +    db: &dyn HirDatabase,
 +    def: Definition,
 +    link: &str,
 +    ns: Option<hir::Namespace>,
 +) -> Option<Definition> {
 +    match def {
 +        Definition::Module(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Function(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Adt(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Variant(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Const(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Static(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Trait(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::Field(it) => it.resolve_doc_path(db, link, ns),
 +        Definition::BuiltinAttr(_)
 +        | Definition::ToolModule(_)
 +        | Definition::BuiltinType(_)
 +        | Definition::SelfType(_)
 +        | Definition::Local(_)
 +        | Definition::GenericParam(_)
-         | Definition::ToolModule(_) => return None,
++        | Definition::Label(_)
++        | Definition::DeriveHelper(_) => None,
 +    }
 +    .map(Definition::from)
 +}
 +
 +pub(crate) fn doc_attributes(
 +    sema: &Semantics<'_, RootDatabase>,
 +    node: &SyntaxNode,
 +) -> Option<(hir::AttrsWithOwner, Definition)> {
 +    match_ast! {
 +        match node {
 +            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))),
 +            ast::Module(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))),
 +            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Function(def))),
 +            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
 +            ast::Union(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
 +            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
 +            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Variant(def))),
 +            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Trait(def))),
 +            ast::Static(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Static(def))),
 +            ast::Const(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Const(def))),
 +            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::TypeAlias(def))),
 +            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
 +            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
 +            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
 +            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
 +            // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
 +            _ => None
 +        }
 +    }
 +}
 +
 +pub(crate) struct DocCommentToken {
 +    doc_token: SyntaxToken,
 +    prefix_len: TextSize,
 +}
 +
 +pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option<DocCommentToken> {
 +    (match_ast! {
 +        match doc_token {
 +            ast::Comment(comment) => TextSize::try_from(comment.prefix().len()).ok(),
 +            ast::String(string) => doc_token.parent_ancestors().find_map(ast::Attr::cast)
 +                .filter(|attr| attr.simple_name().as_deref() == Some("doc")).and_then(|_| string.open_quote_text_range().map(|it| it.len())),
 +            _ => None,
 +        }
 +    }).map(|prefix_len| DocCommentToken { prefix_len, doc_token: doc_token.clone() })
 +}
 +
 +impl DocCommentToken {
 +    pub(crate) fn get_definition_with_descend_at<T>(
 +        self,
 +        sema: &Semantics<'_, RootDatabase>,
 +        offset: TextSize,
 +        // Definition, CommentOwner, range of intra doc link in original file
 +        mut cb: impl FnMut(Definition, SyntaxNode, TextRange) -> Option<T>,
 +    ) -> Option<T> {
 +        let DocCommentToken { prefix_len, doc_token } = self;
 +        // offset relative to the comments contents
 +        let original_start = doc_token.text_range().start();
 +        let relative_comment_offset = offset - original_start - prefix_len;
 +
 +        sema.descend_into_macros(doc_token).into_iter().find_map(|t| {
 +            let (node, descended_prefix_len) = match_ast! {
 +                match t {
 +                    ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),
 +                    ast::String(string) => (t.parent_ancestors().skip_while(|n| n.kind() != ATTR).nth(1)?, string.open_quote_text_range()?.len()),
 +                    _ => return None,
 +                }
 +            };
 +            let token_start = t.text_range().start();
 +            let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
 +
 +            let (attributes, def) = doc_attributes(sema, &node)?;
 +            let (docs, doc_mapping) = attributes.docs_with_rangemap(sema.db)?;
 +            let (in_expansion_range, link, ns) =
 +                extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
 +                    let mapped = doc_mapping.map(range)?;
 +                    (mapped.value.contains(abs_in_expansion_offset)).then(|| (mapped.value, link, ns))
 +                })?;
 +            // get the relative range to the doc/attribute in the expansion
 +            let in_expansion_relative_range = in_expansion_range - descended_prefix_len - token_start;
 +            // Apply relative range to the original input comment
 +            let absolute_range = in_expansion_relative_range + original_start + prefix_len;
 +            let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
 +            cb(def, node, absolute_range)
 +        })
 +    }
 +}
 +
 +fn broken_link_clone_cb<'a>(link: BrokenLink<'a>) -> Option<(CowStr<'a>, CowStr<'a>)> {
 +    Some((/*url*/ link.reference.clone(), /*title*/ link.reference))
 +}
 +
 +// FIXME:
 +// BUG: For Option::Some
 +// Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some
 +// Instead of https://doc.rust-lang.org/nightly/core/option/enum.Option.html
 +//
 +// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented
 +// https://github.com/rust-lang/rfcs/pull/2988
 +fn get_doc_link(db: &RootDatabase, def: Definition) -> Option<String> {
 +    let (target, file, frag) = filename_and_frag_for_def(db, def)?;
 +
 +    let mut url = get_doc_base_url(db, target)?;
 +
 +    if let Some(path) = mod_path_of_def(db, target) {
 +        url = url.join(&path).ok()?;
 +    }
 +
 +    url = url.join(&file).ok()?;
 +    url.set_fragment(frag.as_deref());
 +
 +    Some(url.into())
 +}
 +
 +fn rewrite_intra_doc_link(
 +    db: &RootDatabase,
 +    def: Definition,
 +    target: &str,
 +    title: &str,
 +) -> Option<(String, String)> {
 +    let (link, ns) = parse_intra_doc_link(target);
 +
 +    let resolved = resolve_doc_path_for_def(db, def, link, ns)?;
 +    let mut url = get_doc_base_url(db, resolved)?;
 +
 +    let (_, file, frag) = filename_and_frag_for_def(db, resolved)?;
 +    if let Some(path) = mod_path_of_def(db, resolved) {
 +        url = url.join(&path).ok()?;
 +    }
 +
 +    url = url.join(&file).ok()?;
 +    url.set_fragment(frag.as_deref());
 +
 +    Some((url.into(), strip_prefixes_suffixes(title).to_string()))
 +}
 +
 +/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
 +fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option<String> {
 +    if !(target.contains('#') || target.contains(".html")) {
 +        return None;
 +    }
 +
 +    let mut url = get_doc_base_url(db, def)?;
 +    let (def, file, frag) = filename_and_frag_for_def(db, def)?;
 +
 +    if let Some(path) = mod_path_of_def(db, def) {
 +        url = url.join(&path).ok()?;
 +    }
 +
 +    url = url.join(&file).ok()?;
 +    url.set_fragment(frag.as_deref());
 +    url.join(target).ok().map(Into::into)
 +}
 +
 +fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
 +    def.canonical_module_path(db).map(|it| {
 +        let mut path = String::new();
 +        it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name));
 +        path
 +    })
 +}
 +
 +/// Rewrites a markdown document, applying 'callback' to each link.
 +fn map_links<'e>(
 +    events: impl Iterator<Item = Event<'e>>,
 +    callback: impl Fn(&str, &str) -> (Option<LinkType>, String, String),
 +) -> impl Iterator<Item = Event<'e>> {
 +    let mut in_link = false;
 +    // holds the origin link target on start event and the rewritten one on end event
 +    let mut end_link_target: Option<CowStr<'_>> = None;
 +    // normally link's type is determined by the type of link tag in the end event,
 +    // however in some cases we want to change the link type, for example,
 +    // `Shortcut` type parsed from Start/End tags doesn't make sense for url links
 +    let mut end_link_type: Option<LinkType> = None;
 +
 +    events.map(move |evt| match evt {
 +        Event::Start(Tag::Link(link_type, ref target, _)) => {
 +            in_link = true;
 +            end_link_target = Some(target.clone());
 +            end_link_type = Some(link_type);
 +            evt
 +        }
 +        Event::End(Tag::Link(link_type, target, _)) => {
 +            in_link = false;
 +            Event::End(Tag::Link(
 +                end_link_type.unwrap_or(link_type),
 +                end_link_target.take().unwrap_or(target),
 +                CowStr::Borrowed(""),
 +            ))
 +        }
 +        Event::Text(s) if in_link => {
 +            let (link_type, link_target_s, link_name) =
 +                callback(&end_link_target.take().unwrap(), &s);
 +            end_link_target = Some(CowStr::Boxed(link_target_s.into()));
 +            if !matches!(end_link_type, Some(LinkType::Autolink)) {
 +                end_link_type = link_type;
 +            }
 +            Event::Text(CowStr::Boxed(link_name.into()))
 +        }
 +        Event::Code(s) if in_link => {
 +            let (link_type, link_target_s, link_name) =
 +                callback(&end_link_target.take().unwrap(), &s);
 +            end_link_target = Some(CowStr::Boxed(link_target_s.into()));
 +            if !matches!(end_link_type, Some(LinkType::Autolink)) {
 +                end_link_type = link_type;
 +            }
 +            Event::Code(CowStr::Boxed(link_name.into()))
 +        }
 +        _ => evt,
 +    })
 +}
 +
 +/// Get the root URL for the documentation of a definition.
 +///
 +/// ```ignore
 +/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
 +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +/// ```
 +fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option<Url> {
 +    // special case base url of `BuiltinType` to core
 +    // https://github.com/rust-lang/rust-analyzer/issues/12250
 +    if let Definition::BuiltinType(..) = def {
 +        return Url::parse("https://doc.rust-lang.org/nightly/core/").ok();
 +    };
 +
 +    let krate = def.krate(db)?;
 +    let display_name = krate.display_name(db)?;
 +
 +    let base = match db.crate_graph()[krate.into()].origin {
 +        // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself.
 +        // FIXME: Use the toolchains channel instead of nightly
 +        CrateOrigin::Lang(
 +            origin @ (LangCrateOrigin::Alloc
 +            | LangCrateOrigin::Core
 +            | LangCrateOrigin::ProcMacro
 +            | LangCrateOrigin::Std
 +            | LangCrateOrigin::Test),
 +        ) => {
 +            format!("https://doc.rust-lang.org/nightly/{origin}")
 +        }
 +        _ => {
 +            krate.get_html_root_url(db).or_else(|| {
 +                let version = krate.version(db);
 +                // Fallback to docs.rs. This uses `display_name` and can never be
 +                // correct, but that's what fallbacks are about.
 +                //
 +                // FIXME: clicking on the link should just open the file in the editor,
 +                // instead of falling back to external urls.
 +                Some(format!(
 +                    "https://docs.rs/{krate}/{version}/",
 +                    krate = display_name,
 +                    version = version.as_deref().unwrap_or("*")
 +                ))
 +            })?
 +        }
 +    };
 +    Url::parse(&base).ok()?.join(&format!("{}/", display_name)).ok()
 +}
 +
 +/// Get the filename and extension generated for a symbol by rustdoc.
 +///
 +/// ```ignore
 +/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
 +///                                    ^^^^^^^^^^^^^^^^^^^
 +/// ```
 +fn filename_and_frag_for_def(
 +    db: &dyn HirDatabase,
 +    def: Definition,
 +) -> Option<(Definition, String, Option<String>)> {
 +    if let Some(assoc_item) = def.as_assoc_item(db) {
 +        let def = match assoc_item.container(db) {
 +            AssocItemContainer::Trait(t) => t.into(),
 +            AssocItemContainer::Impl(i) => i.self_ty(db).as_adt()?.into(),
 +        };
 +        let (_, file, _) = filename_and_frag_for_def(db, def)?;
 +        let frag = get_assoc_item_fragment(db, assoc_item)?;
 +        return Some((def, file, Some(frag)));
 +    }
 +
 +    let res = match def {
 +        Definition::Adt(adt) => match adt {
 +            Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
 +            Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
 +            Adt::Union(u) => format!("union.{}.html", u.name(db)),
 +        },
 +        Definition::Module(m) => match m.name(db) {
 +            // `#[doc(keyword = "...")]` is internal used only by rust compiler
 +            Some(name) => match m.attrs(db).by_key("doc").find_string_value_in_tt("keyword") {
 +                Some(kw) => {
 +                    format!("keyword.{}.html", kw.trim_matches('"'))
 +                }
 +                None => format!("{}/index.html", name),
 +            },
 +            None => String::from("index.html"),
 +        },
 +        Definition::Trait(t) => format!("trait.{}.html", t.name(db)),
 +        Definition::TypeAlias(t) => format!("type.{}.html", t.name(db)),
 +        Definition::BuiltinType(t) => format!("primitive.{}.html", t.name()),
 +        Definition::Function(f) => format!("fn.{}.html", f.name(db)),
 +        Definition::Variant(ev) => {
 +            format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db))
 +        }
 +        Definition::Const(c) => format!("const.{}.html", c.name(db)?),
 +        Definition::Static(s) => format!("static.{}.html", s.name(db)),
 +        Definition::Macro(mac) => format!("macro.{}.html", mac.name(db)),
 +        Definition::Field(field) => {
 +            let def = match field.parent_def(db) {
 +                hir::VariantDef::Struct(it) => Definition::Adt(it.into()),
 +                hir::VariantDef::Union(it) => Definition::Adt(it.into()),
 +                hir::VariantDef::Variant(it) => Definition::Variant(it),
 +            };
 +            let (_, file, _) = filename_and_frag_for_def(db, def)?;
 +            return Some((def, file, Some(format!("structfield.{}", field.name(db)))));
 +        }
 +        Definition::SelfType(impl_) => {
 +            let adt = impl_.self_ty(db).as_adt()?.into();
 +            let (_, file, _) = filename_and_frag_for_def(db, adt)?;
 +            // FIXME fragment numbering
 +            return Some((adt, file, Some(String::from("impl"))));
 +        }
 +        Definition::Local(_)
 +        | Definition::GenericParam(_)
 +        | Definition::Label(_)
 +        | Definition::BuiltinAttr(_)
++        | Definition::ToolModule(_)
++        | Definition::DeriveHelper(_) => return None,
 +    };
 +
 +    Some((def, res, None))
 +}
 +
 +/// Get the fragment required to link to a specific field, method, associated type, or associated constant.
 +///
 +/// ```ignore
 +/// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
 +///                                                       ^^^^^^^^^^^^^^
 +/// ```
 +fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) -> Option<String> {
 +    Some(match assoc_item {
 +        AssocItem::Function(function) => {
 +            let is_trait_method =
 +                function.as_assoc_item(db).and_then(|assoc| assoc.containing_trait(db)).is_some();
 +            // This distinction may get more complicated when specialization is available.
 +            // Rustdoc makes this decision based on whether a method 'has defaultness'.
 +            // Currently this is only the case for provided trait methods.
 +            if is_trait_method && !function.has_body(db) {
 +                format!("tymethod.{}", function.name(db))
 +            } else {
 +                format!("method.{}", function.name(db))
 +            }
 +        }
 +        AssocItem::Const(constant) => format!("associatedconstant.{}", constant.name(db)?),
 +        AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db)),
 +    })
 +}
index d8867cf783ad8ed9fc3b07907724b33d91fc2d04,0000000000000000000000000000000000000000..59c97f2dcf966bff485bdd32b5b14cfeba614d60
mode 100644,000000..100644
--- /dev/null
@@@ -1,385 -1,0 +1,390 @@@
-     let descended = sema.descend_into_macros_with_same_text(original_token.clone());
 +mod render;
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use std::iter;
 +
 +use either::Either;
 +use hir::{HasSource, Semantics};
 +use ide_db::{
 +    base_db::FileRange,
 +    defs::{Definition, IdentClass},
 +    famous_defs::FamousDefs,
 +    helpers::pick_best_token,
 +    FxIndexSet, RootDatabase,
 +};
 +use itertools::Itertools;
 +use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T};
 +
 +use crate::{
 +    doc_links::token_as_doc_comment,
 +    markup::Markup,
 +    runnables::{runnable_fn, runnable_mod},
 +    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
 +};
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct HoverConfig {
 +    pub links_in_hover: bool,
 +    pub documentation: Option<HoverDocFormat>,
 +}
 +
 +impl HoverConfig {
 +    fn markdown(&self) -> bool {
 +        matches!(self.documentation, Some(HoverDocFormat::Markdown))
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum HoverDocFormat {
 +    Markdown,
 +    PlainText,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum HoverAction {
 +    Runnable(Runnable),
 +    Implementation(FilePosition),
 +    Reference(FilePosition),
 +    GoToType(Vec<HoverGotoTypeData>),
 +}
 +
 +impl HoverAction {
 +    fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Self {
 +        let targets = targets
 +            .into_iter()
 +            .filter_map(|it| {
 +                Some(HoverGotoTypeData {
 +                    mod_path: render::path(
 +                        db,
 +                        it.module(db)?,
 +                        it.name(db).map(|name| name.to_string()),
 +                    ),
 +                    nav: it.try_to_nav(db)?,
 +                })
 +            })
 +            .collect();
 +        HoverAction::GoToType(targets)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 +pub struct HoverGotoTypeData {
 +    pub mod_path: String,
 +    pub nav: NavigationTarget,
 +}
 +
 +/// Contains the results when hovering over an item
 +#[derive(Debug, Default)]
 +pub struct HoverResult {
 +    pub markup: Markup,
 +    pub actions: Vec<HoverAction>,
 +}
 +
 +// Feature: Hover
 +//
 +// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
 +// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
 +pub(crate) fn hover(
 +    db: &RootDatabase,
 +    FileRange { file_id, range }: FileRange,
 +    config: &HoverConfig,
 +) -> Option<RangeInfo<HoverResult>> {
 +    let sema = &hir::Semantics::new(db);
 +    let file = sema.parse(file_id).syntax().clone();
 +
 +    if !range.is_empty() {
 +        return hover_ranged(&file, range, sema, config);
 +    }
 +    let offset = range.start();
 +
 +    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] => 3,
 +        T!['('] | T![')'] => 2,
 +        kind if kind.is_trivia() => 0,
 +        _ => 1,
 +    })?;
 +
 +    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
 +        cov_mark::hit!(no_highlight_on_comment_hover);
 +        return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
 +            let res = hover_for_definition(sema, file_id, def, &node, config)?;
 +            Some(RangeInfo::new(range, res))
 +        });
 +    }
 +
++    let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())));
++    let descended = if in_attr {
++        [sema.descend_into_macros_with_kind_preference(original_token.clone())].into()
++    } else {
++        sema.descend_into_macros_with_same_text(original_token.clone())
++    };
 +
 +    // FIXME: Definition should include known lints and the like instead of having this special case here
 +    let hovered_lint = descended.iter().find_map(|token| {
 +        let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
 +        render::try_for_lint(&attr, token)
 +    });
 +    if let Some(res) = hovered_lint {
 +        return Some(RangeInfo::new(original_token.text_range(), res));
 +    }
 +
 +    let result = descended
 +        .iter()
 +        .filter_map(|token| {
 +            let node = token.parent()?;
 +            let class = IdentClass::classify_token(sema, token)?;
 +            Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
 +        })
 +        .flatten()
 +        .unique_by(|&(def, _)| def)
 +        .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
 +        .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
 +            acc.actions.extend(actions);
 +            acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup));
 +            acc
 +        });
 +
 +    if result.is_none() {
 +        // fallbacks, show keywords or types
 +
 +        let res = descended.iter().find_map(|token| render::keyword(sema, config, token));
 +        if let Some(res) = res {
 +            return Some(RangeInfo::new(original_token.text_range(), res));
 +        }
 +        let res = descended
 +            .iter()
 +            .find_map(|token| hover_type_fallback(sema, config, token, &original_token));
 +        if let Some(_) = res {
 +            return res;
 +        }
 +    }
 +    result.map(|mut res: HoverResult| {
 +        res.actions = dedupe_or_merge_hover_actions(res.actions);
 +        RangeInfo::new(original_token.text_range(), res)
 +    })
 +}
 +
 +pub(crate) fn hover_for_definition(
 +    sema: &Semantics<'_, RootDatabase>,
 +    file_id: FileId,
 +    definition: Definition,
 +    node: &SyntaxNode,
 +    config: &HoverConfig,
 +) -> Option<HoverResult> {
 +    let famous_defs = match &definition {
 +        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
 +        _ => None,
 +    };
 +    render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| {
 +        HoverResult {
 +            markup: render::process_markup(sema.db, definition, &markup, config),
 +            actions: show_implementations_action(sema.db, definition)
 +                .into_iter()
 +                .chain(show_fn_references_action(sema.db, definition))
 +                .chain(runnable_action(sema, definition, file_id))
 +                .chain(goto_type_action_for_def(sema.db, definition))
 +                .collect(),
 +        }
 +    })
 +}
 +
 +fn hover_ranged(
 +    file: &SyntaxNode,
 +    range: syntax::TextRange,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +) -> Option<RangeInfo<HoverResult>> {
 +    // FIXME: make this work in attributes
 +    let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| {
 +        match_ast! {
 +            match it {
 +                ast::Expr(expr) => Some(Either::Left(expr)),
 +                ast::Pat(pat) => Some(Either::Right(pat)),
 +                _ => None,
 +            }
 +        }
 +    })?;
 +    let res = match &expr_or_pat {
 +        Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr),
 +        Either::Left(ast::Expr::PrefixExpr(prefix_expr))
 +            if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
 +        {
 +            render::deref_expr(sema, config, prefix_expr)
 +        }
 +        _ => None,
 +    };
 +    let res = res.or_else(|| render::type_info(sema, config, &expr_or_pat));
 +    res.map(|it| {
 +        let range = match expr_or_pat {
 +            Either::Left(it) => it.syntax().text_range(),
 +            Either::Right(it) => it.syntax().text_range(),
 +        };
 +        RangeInfo::new(range, it)
 +    })
 +}
 +
 +fn hover_type_fallback(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    token: &SyntaxToken,
 +    original_token: &SyntaxToken,
 +) -> Option<RangeInfo<HoverResult>> {
 +    let node = token
 +        .parent_ancestors()
 +        .take_while(|it| !ast::Item::can_cast(it.kind()))
 +        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
 +
 +    let expr_or_pat = match_ast! {
 +        match node {
 +            ast::Expr(it) => Either::Left(it),
 +            ast::Pat(it) => Either::Right(it),
 +            // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
 +            // (e.g expanding a builtin macro). So we give up here.
 +            ast::MacroCall(_it) => return None,
 +            _ => return None,
 +        }
 +    };
 +
 +    let res = render::type_info(sema, config, &expr_or_pat)?;
 +    let range = sema
 +        .original_range_opt(&node)
 +        .map(|frange| frange.range)
 +        .unwrap_or_else(|| original_token.text_range());
 +    Some(RangeInfo::new(range, res))
 +}
 +
 +fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    fn to_action(nav_target: NavigationTarget) -> HoverAction {
 +        HoverAction::Implementation(FilePosition {
 +            file_id: nav_target.file_id,
 +            offset: nav_target.focus_or_full_range().start(),
 +        })
 +    }
 +
 +    let adt = match def {
 +        Definition::Trait(it) => return it.try_to_nav(db).map(to_action),
 +        Definition::Adt(it) => Some(it),
 +        Definition::SelfType(it) => it.self_ty(db).as_adt(),
 +        _ => None,
 +    }?;
 +    adt.try_to_nav(db).map(to_action)
 +}
 +
 +fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    match def {
 +        Definition::Function(it) => it.try_to_nav(db).map(|nav_target| {
 +            HoverAction::Reference(FilePosition {
 +                file_id: nav_target.file_id,
 +                offset: nav_target.focus_or_full_range().start(),
 +            })
 +        }),
 +        _ => None,
 +    }
 +}
 +
 +fn runnable_action(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    file_id: FileId,
 +) -> Option<HoverAction> {
 +    match def {
 +        Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
 +        Definition::Function(func) => {
 +            let src = func.source(sema.db)?;
 +            if src.file_id != file_id.into() {
 +                cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
 +                cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
 +                return None;
 +            }
 +
 +            runnable_fn(sema, func).map(HoverAction::Runnable)
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +
 +    if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
 +        it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
 +    } else {
 +        let ty = match def {
 +            Definition::Local(it) => it.ty(db),
 +            Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
 +            Definition::Field(field) => field.ty(db),
 +            Definition::Function(function) => function.ret_type(db),
 +            _ => return None,
 +        };
 +
 +        walk_and_push_ty(db, &ty, &mut push_new_def);
 +    }
 +
 +    Some(HoverAction::goto_type_from_targets(db, targets))
 +}
 +
 +fn walk_and_push_ty(
 +    db: &RootDatabase,
 +    ty: &hir::Type,
 +    push_new_def: &mut dyn FnMut(hir::ModuleDef),
 +) {
 +    ty.walk(db, |t| {
 +        if let Some(adt) = t.as_adt() {
 +            push_new_def(adt.into());
 +        } else if let Some(trait_) = t.as_dyn_trait() {
 +            push_new_def(trait_.into());
 +        } else if let Some(traits) = t.as_impl_traits(db) {
 +            traits.for_each(|it| push_new_def(it.into()));
 +        } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
 +            push_new_def(trait_.into());
 +        }
 +    });
 +}
 +
 +fn dedupe_or_merge_hover_actions(actions: Vec<HoverAction>) -> Vec<HoverAction> {
 +    let mut deduped_actions = Vec::with_capacity(actions.len());
 +    let mut go_to_type_targets = FxIndexSet::default();
 +
 +    let mut seen_implementation = false;
 +    let mut seen_reference = false;
 +    let mut seen_runnable = false;
 +    for action in actions {
 +        match action {
 +            HoverAction::GoToType(targets) => {
 +                go_to_type_targets.extend(targets);
 +            }
 +            HoverAction::Implementation(..) => {
 +                if !seen_implementation {
 +                    seen_implementation = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +            HoverAction::Reference(..) => {
 +                if !seen_reference {
 +                    seen_reference = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +            HoverAction::Runnable(..) => {
 +                if !seen_runnable {
 +                    seen_runnable = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +        };
 +    }
 +
 +    if !go_to_type_targets.is_empty() {
 +        deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect()));
 +    }
 +
 +    deduped_actions
 +}
index 925aaa61cdd04f4b9777b326a8c1e70acaddc366,0000000000000000000000000000000000000000..6c50a4e6adc0ef663856331f022dcc63000e0f77
mode 100644,000000..100644
--- /dev/null
@@@ -1,562 -1,0 +1,563 @@@
 +//! Logic for rendering the different hover messages
 +use std::fmt::Display;
 +
 +use either::Either;
 +use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::SourceDatabase,
 +    defs::Definition,
 +    famous_defs::FamousDefs,
 +    generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::format_to;
 +use syntax::{
 +    algo, ast, match_ast, AstNode, Direction,
 +    SyntaxKind::{LET_EXPR, LET_STMT},
 +    SyntaxToken, T,
 +};
 +
 +use crate::{
 +    doc_links::{remove_links, rewrite_links},
 +    hover::walk_and_push_ty,
 +    markdown_remove::remove_markdown,
 +    HoverAction, HoverConfig, HoverResult, Markup,
 +};
 +
 +pub(super) fn type_info(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    expr_or_pat: &Either<ast::Expr, ast::Pat>,
 +) -> Option<HoverResult> {
 +    let TypeInfo { original, adjusted } = match expr_or_pat {
 +        Either::Left(expr) => sema.type_of_expr(expr)?,
 +        Either::Right(pat) => sema.type_of_pat(pat)?,
 +    };
 +
 +    let mut res = HoverResult::default();
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &original, &mut push_new_def);
 +
 +    res.markup = if let Some(adjusted_ty) = adjusted {
 +        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
 +        let original = original.display(sema.db).to_string();
 +        let adjusted = adjusted_ty.display(sema.db).to_string();
 +        let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
 +        format!(
 +            "{bt_start}Type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
 +            original,
 +            adjusted,
 +            apad = static_text_diff_len + adjusted.len().max(original.len()),
 +            opad = original.len(),
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    } else {
 +        if config.markdown() {
 +            Markup::fenced_block(&original.display(sema.db))
 +        } else {
 +            original.display(sema.db).to_string().into()
 +        }
 +    };
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +    Some(res)
 +}
 +
 +pub(super) fn try_expr(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    try_expr: &ast::TryExpr,
 +) -> Option<HoverResult> {
 +    let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
 +    let mut ancestors = try_expr.syntax().ancestors();
 +    let mut body_ty = loop {
 +        let next = ancestors.next()?;
 +        break match_ast! {
 +            match next {
 +                ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
 +                ast::Item(__) => return None,
 +                ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
 +                ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
 +                    sema.type_of_expr(&block_expr.into())?.original
 +                } else {
 +                    continue;
 +                },
 +                _ => continue,
 +            }
 +        };
 +    };
 +
 +    if inner_ty == body_ty {
 +        return None;
 +    }
 +
 +    let mut inner_ty = inner_ty;
 +    let mut s = "Try Target".to_owned();
 +
 +    let adts = inner_ty.as_adt().zip(body_ty.as_adt());
 +    if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts {
 +        let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax())?.krate());
 +        // special case for two options, there is no value in showing them
 +        if let Some(option_enum) = famous_defs.core_option_Option() {
 +            if inner == option_enum && body == option_enum {
 +                cov_mark::hit!(hover_try_expr_opt_opt);
 +                return None;
 +            }
 +        }
 +
 +        // special case two results to show the error variants only
 +        if let Some(result_enum) = famous_defs.core_result_Result() {
 +            if inner == result_enum && body == result_enum {
 +                let error_type_args =
 +                    inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1));
 +                if let Some((inner, body)) = error_type_args {
 +                    inner_ty = inner;
 +                    body_ty = body;
 +                    s = "Try Error".to_owned();
 +                }
 +            }
 +        }
 +    }
 +
 +    let mut res = HoverResult::default();
 +
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
 +    walk_and_push_ty(sema.db, &body_ty, &mut push_new_def);
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +
 +    let inner_ty = inner_ty.display(sema.db).to_string();
 +    let body_ty = body_ty.display(sema.db).to_string();
 +    let ty_len_max = inner_ty.len().max(body_ty.len());
 +
 +    let l = "Propagated as: ".len() - " Type: ".len();
 +    let static_text_len_diff = l as isize - s.len() as isize;
 +    let tpad = static_text_len_diff.max(0) as usize;
 +    let ppad = static_text_len_diff.min(0).abs() as usize;
 +
 +    res.markup = format!(
 +        "{bt_start}{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n{bt_end}",
 +        s,
 +        inner_ty,
 +        body_ty,
 +        pad0 = ty_len_max + tpad,
 +        pad1 = ty_len_max + ppad,
 +        bt_start = if config.markdown() { "```text\n" } else { "" },
 +        bt_end = if config.markdown() { "```\n" } else { "" }
 +    )
 +    .into();
 +    Some(res)
 +}
 +
 +pub(super) fn deref_expr(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    deref_expr: &ast::PrefixExpr,
 +) -> Option<HoverResult> {
 +    let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
 +    let TypeInfo { original, adjusted } =
 +        sema.type_of_expr(&ast::Expr::from(deref_expr.clone()))?;
 +
 +    let mut res = HoverResult::default();
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
 +    walk_and_push_ty(sema.db, &original, &mut push_new_def);
 +
 +    res.markup = if let Some(adjusted_ty) = adjusted {
 +        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
 +        let original = original.display(sema.db).to_string();
 +        let adjusted = adjusted_ty.display(sema.db).to_string();
 +        let inner = inner_ty.display(sema.db).to_string();
 +        let type_len = "To type: ".len();
 +        let coerced_len = "Coerced to: ".len();
 +        let deref_len = "Dereferenced from: ".len();
 +        let max_len = (original.len() + type_len)
 +            .max(adjusted.len() + coerced_len)
 +            .max(inner.len() + deref_len);
 +        format!(
 +            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
 +            inner,
 +            original,
 +            adjusted,
 +            ipad = max_len - deref_len,
 +            apad = max_len - type_len,
 +            opad = max_len - coerced_len,
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    } else {
 +        let original = original.display(sema.db).to_string();
 +        let inner = inner_ty.display(sema.db).to_string();
 +        let type_len = "To type: ".len();
 +        let deref_len = "Dereferenced from: ".len();
 +        let max_len = (original.len() + type_len).max(inner.len() + deref_len);
 +        format!(
 +            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\n{bt_end}",
 +            inner,
 +            original,
 +            ipad = max_len - deref_len,
 +            apad = max_len - type_len,
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    };
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +
 +    Some(res)
 +}
 +
 +pub(super) fn keyword(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    token: &SyntaxToken,
 +) -> Option<HoverResult> {
 +    if !token.kind().is_keyword() || !config.documentation.is_some() {
 +        return None;
 +    }
 +    let parent = token.parent()?;
 +    let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate());
 +
 +    let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent);
 +
 +    let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
 +    let docs = doc_owner.attrs(sema.db).docs()?;
 +    let markup = process_markup(
 +        sema.db,
 +        Definition::Module(doc_owner),
 +        &markup(Some(docs.into()), description, None)?,
 +        config,
 +    );
 +    Some(HoverResult { markup, actions })
 +}
 +
 +pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> {
 +    let (path, tt) = attr.as_simple_call()?;
 +    if !tt.syntax().text_range().contains(token.text_range().start()) {
 +        return None;
 +    }
 +    let (is_clippy, lints) = match &*path {
 +        "feature" => (false, FEATURES),
 +        "allow" | "deny" | "forbid" | "warn" => {
 +            let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev)
 +                .filter(|t| t.kind() == T![:])
 +                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
 +                .filter(|t| t.kind() == T![:])
 +                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
 +                .map_or(false, |t| {
 +                    t.kind() == T![ident] && t.into_token().map_or(false, |t| t.text() == "clippy")
 +                });
 +            if is_clippy {
 +                (true, CLIPPY_LINTS)
 +            } else {
 +                (false, DEFAULT_LINTS)
 +            }
 +        }
 +        _ => return None,
 +    };
 +
 +    let tmp;
 +    let needle = if is_clippy {
 +        tmp = format!("clippy::{}", token.text());
 +        &tmp
 +    } else {
 +        &*token.text()
 +    };
 +
 +    let lint =
 +        lints.binary_search_by_key(&needle, |lint| lint.label).ok().map(|idx| &lints[idx])?;
 +    Some(HoverResult {
 +        markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)),
 +        ..Default::default()
 +    })
 +}
 +
 +pub(super) fn process_markup(
 +    db: &RootDatabase,
 +    def: Definition,
 +    markup: &Markup,
 +    config: &HoverConfig,
 +) -> Markup {
 +    let markup = markup.as_str();
 +    let markup = if !config.markdown() {
 +        remove_markdown(markup)
 +    } else if config.links_in_hover {
 +        rewrite_links(db, markup, def)
 +    } else {
 +        remove_links(markup)
 +    };
 +    Markup::from(markup)
 +}
 +
 +fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
 +    match def {
 +        Definition::Field(f) => Some(f.parent_def(db).name(db)),
 +        Definition::Local(l) => l.parent(db).name(db),
 +        Definition::Function(f) => match f.as_assoc_item(db)?.container(db) {
 +            hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
 +            hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
 +        },
 +        Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
 +        _ => None,
 +    }
 +    .map(|name| name.to_string())
 +}
 +
 +pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
 +    let crate_name =
 +        db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
 +    let module_path = module
 +        .path_to_root(db)
 +        .into_iter()
 +        .rev()
 +        .flat_map(|it| it.name(db).map(|name| name.to_string()));
 +    crate_name.into_iter().chain(module_path).chain(item_name).join("::")
 +}
 +
 +pub(super) fn definition(
 +    db: &RootDatabase,
 +    def: Definition,
 +    famous_defs: Option<&FamousDefs<'_, '_>>,
 +    config: &HoverConfig,
 +) -> Option<Markup> {
 +    let mod_path = definition_mod_path(db, &def);
 +    let (label, docs) = match def {
 +        Definition::Macro(it) => label_and_docs(db, it),
 +        Definition::Field(it) => label_and_docs(db, it),
 +        Definition::Module(it) => label_and_docs(db, it),
 +        Definition::Function(it) => label_and_docs(db, it),
 +        Definition::Adt(it) => label_and_docs(db, it),
 +        Definition::Variant(it) => label_and_docs(db, it),
 +        Definition::Const(it) => label_value_and_docs(db, it, |it| {
 +            let body = it.eval(db);
 +            match body {
 +                Ok(x) => Some(format!("{}", x)),
 +                Err(_) => it.value(db).map(|x| format!("{}", x)),
 +            }
 +        }),
 +        Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)),
 +        Definition::Trait(it) => label_and_docs(db, it),
 +        Definition::TypeAlias(it) => label_and_docs(db, it),
 +        Definition::BuiltinType(it) => {
 +            return famous_defs
 +                .and_then(|fd| builtin(fd, it))
 +                .or_else(|| Some(Markup::fenced_block(&it.name())))
 +        }
 +        Definition::Local(it) => return local(db, it),
 +        Definition::SelfType(impl_def) => {
 +            impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
 +        }
 +        Definition::GenericParam(it) => label_and_docs(db, it),
 +        Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
 +        // FIXME: We should be able to show more info about these
 +        Definition::BuiltinAttr(it) => return render_builtin_attr(db, it),
 +        Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
++        Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None),
 +    };
 +
 +    let docs = match config.documentation {
 +        Some(_) => docs.or_else(|| {
 +            // docs are missing, for assoc items of trait impls try to fall back to the docs of the
 +            // original item of the trait
 +            let assoc = def.as_assoc_item(db)?;
 +            let trait_ = assoc.containing_trait_impl(db)?;
 +            let name = Some(assoc.name(db)?);
 +            let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
 +            item.docs(db)
 +        }),
 +        None => None,
 +    };
 +    let docs = docs.filter(|_| config.documentation.is_some()).map(Into::into);
 +    markup(docs, label, mod_path)
 +}
 +
 +fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Markup> {
 +    let name = attr.name(db);
 +    let desc = format!("#[{}]", name);
 +
 +    let AttributeTemplate { word, list, name_value_str } = match attr.template(db) {
 +        Some(template) => template,
 +        None => return Some(Markup::fenced_block(&attr.name(db))),
 +    };
 +    let mut docs = "Valid forms are:".to_owned();
 +    if word {
 +        format_to!(docs, "\n - #\\[{}]", name);
 +    }
 +    if let Some(list) = list {
 +        format_to!(docs, "\n - #\\[{}({})]", name, list);
 +    }
 +    if let Some(name_value_str) = name_value_str {
 +        format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str);
 +    }
 +    markup(Some(docs.replace('*', "\\*")), desc, None)
 +}
 +
 +fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
 +where
 +    D: HasAttrs + HirDisplay,
 +{
 +    let label = def.display(db).to_string();
 +    let docs = def.attrs(db).docs();
 +    (label, docs)
 +}
 +
 +fn label_value_and_docs<D, E, V>(
 +    db: &RootDatabase,
 +    def: D,
 +    value_extractor: E,
 +) -> (String, Option<hir::Documentation>)
 +where
 +    D: HasAttrs + HirDisplay,
 +    E: Fn(&D) -> Option<V>,
 +    V: Display,
 +{
 +    let label = if let Some(value) = value_extractor(&def) {
 +        format!("{} = {}", def.display(db), value)
 +    } else {
 +        def.display(db).to_string()
 +    };
 +    let docs = def.attrs(db).docs();
 +    (label, docs)
 +}
 +
 +fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
 +    if let Definition::GenericParam(_) = def {
 +        return None;
 +    }
 +    def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
 +}
 +
 +fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
 +    let mut buf = String::new();
 +
 +    if let Some(mod_path) = mod_path {
 +        if !mod_path.is_empty() {
 +            format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
 +        }
 +    }
 +    format_to!(buf, "```rust\n{}\n```", desc);
 +
 +    if let Some(doc) = docs {
 +        format_to!(buf, "\n___\n\n{}", doc);
 +    }
 +    Some(buf.into())
 +}
 +
 +fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option<Markup> {
 +    // std exposes prim_{} modules with docstrings on the root to document the builtins
 +    let primitive_mod = format!("prim_{}", builtin.name());
 +    let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
 +    let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
 +    markup(Some(docs.into()), builtin.name().to_string(), None)
 +}
 +
 +fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
 +    let db = famous_defs.0.db;
 +    let std_crate = famous_defs.std()?;
 +    let std_root_module = std_crate.root_module(db);
 +    std_root_module
 +        .children(db)
 +        .find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
 +}
 +
 +fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
 +    let ty = it.ty(db);
 +    let ty = ty.display_truncated(db, None);
 +    let is_mut = if it.is_mut(db) { "mut " } else { "" };
 +    let desc = match it.source(db).value {
 +        Either::Left(ident) => {
 +            let name = it.name(db);
 +            let let_kw = if ident
 +                .syntax()
 +                .parent()
 +                .map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR)
 +            {
 +                "let "
 +            } else {
 +                ""
 +            };
 +            format!("{}{}{}: {}", let_kw, is_mut, name, ty)
 +        }
 +        Either::Right(_) => format!("{}self: {}", is_mut, ty),
 +    };
 +    markup(None, desc, None)
 +}
 +
 +struct KeywordHint {
 +    description: String,
 +    keyword_mod: String,
 +    actions: Vec<HoverAction>,
 +}
 +
 +impl KeywordHint {
 +    fn new(description: String, keyword_mod: String) -> Self {
 +        Self { description, keyword_mod, actions: Vec::default() }
 +    }
 +}
 +
 +fn keyword_hints(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: &SyntaxToken,
 +    parent: syntax::SyntaxNode,
 +) -> KeywordHint {
 +    match token.kind() {
 +        T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => {
 +            let keyword_mod = format!("{}_keyword", token.text());
 +
 +            match ast::Expr::cast(parent).and_then(|site| sema.type_of_expr(&site)) {
 +                // ignore the unit type ()
 +                Some(ty) if !ty.adjusted.as_ref().unwrap_or(&ty.original).is_unit() => {
 +                    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +                    let mut push_new_def = |item: hir::ModuleDef| {
 +                        if !targets.contains(&item) {
 +                            targets.push(item);
 +                        }
 +                    };
 +                    walk_and_push_ty(sema.db, &ty.original, &mut push_new_def);
 +
 +                    let ty = ty.adjusted();
 +                    let description = format!("{}: {}", token.text(), ty.display(sema.db));
 +
 +                    KeywordHint {
 +                        description,
 +                        keyword_mod,
 +                        actions: vec![HoverAction::goto_type_from_targets(sema.db, targets)],
 +                    }
 +                }
 +                _ => KeywordHint {
 +                    description: token.text().to_string(),
 +                    keyword_mod,
 +                    actions: Vec::new(),
 +                },
 +            }
 +        }
 +        T![fn] => {
 +            let module = match ast::FnPtrType::cast(parent) {
 +                // treat fn keyword inside function pointer type as primitive
 +                Some(_) => format!("prim_{}", token.text()),
 +                None => format!("{}_keyword", token.text()),
 +            };
 +            KeywordHint::new(token.text().to_string(), module)
 +        }
 +        T![Self] => KeywordHint::new(token.text().to_string(), "self_upper_keyword".into()),
 +        _ => KeywordHint::new(token.text().to_string(), format!("{}_keyword", token.text())),
 +    }
 +}
index 1fb3b5ec3f38b233270fd8e65d24e521d23434b5,0000000000000000000000000000000000000000..9f049e298ad119573cccfdc09fab0ea5c3524507
mode 100644,000000..100644
--- /dev/null
@@@ -1,621 -1,0 +1,623 @@@
 +//! See [`NavigationTarget`].
 +
 +use std::fmt;
 +
 +use either::Either;
 +use hir::{
 +    symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay,
 +    InFile, ModuleSource, Semantics,
 +};
 +use ide_db::{
 +    base_db::{FileId, FileRange},
 +    SymbolKind,
 +};
 +use ide_db::{defs::Definition, RootDatabase};
 +use stdx::never;
 +use syntax::{
 +    ast::{self, HasName},
 +    match_ast, AstNode, SmolStr, SyntaxNode, TextRange,
 +};
 +
 +/// `NavigationTarget` represents an element in the editor's UI which you can
 +/// click on to navigate to a particular piece of code.
 +///
 +/// Typically, a `NavigationTarget` corresponds to some element in the source
 +/// code, like a function or a struct, but this is not strictly required.
 +#[derive(Clone, PartialEq, Eq, Hash)]
 +pub struct NavigationTarget {
 +    pub file_id: FileId,
 +    /// Range which encompasses the whole element.
 +    ///
 +    /// Should include body, doc comments, attributes, etc.
 +    ///
 +    /// Clients should use this range to answer "is the cursor inside the
 +    /// element?" question.
 +    pub full_range: TextRange,
 +    /// A "most interesting" range within the `full_range`.
 +    ///
 +    /// Typically, `full_range` is the whole syntax node, including doc
 +    /// comments, and `focus_range` is the range of the identifier.
 +    ///
 +    /// Clients should place the cursor on this range when navigating to this target.
 +    pub focus_range: Option<TextRange>,
 +    pub name: SmolStr,
 +    pub kind: Option<SymbolKind>,
 +    pub container_name: Option<SmolStr>,
 +    pub description: Option<String>,
 +    pub docs: Option<Documentation>,
 +}
 +
 +impl fmt::Debug for NavigationTarget {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let mut f = f.debug_struct("NavigationTarget");
 +        macro_rules! opt {
 +            ($($name:ident)*) => {$(
 +                if let Some(it) = &self.$name {
 +                    f.field(stringify!($name), it);
 +                }
 +            )*}
 +        }
 +        f.field("file_id", &self.file_id).field("full_range", &self.full_range);
 +        opt!(focus_range);
 +        f.field("name", &self.name);
 +        opt!(kind container_name description docs);
 +        f.finish()
 +    }
 +}
 +
 +pub(crate) trait ToNav {
 +    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget;
 +}
 +
 +pub(crate) trait TryToNav {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget>;
 +}
 +
 +impl<T: TryToNav, U: TryToNav> TryToNav for Either<T, U> {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            Either::Left(it) => it.try_to_nav(db),
 +            Either::Right(it) => it.try_to_nav(db),
 +        }
 +    }
 +}
 +
 +impl NavigationTarget {
 +    pub fn focus_or_full_range(&self) -> TextRange {
 +        self.focus_range.unwrap_or(self.full_range)
 +    }
 +
 +    pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
 +        let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
 +        if let Some(src @ InFile { value, .. }) = &module.declaration_source(db) {
 +            let FileRange { file_id, range: full_range } = src.syntax().original_file_range(db);
 +            let focus_range =
 +                value.name().and_then(|it| orig_focus_range(db, src.file_id, it.syntax()));
 +            let mut res = NavigationTarget::from_syntax(
 +                file_id,
 +                name,
 +                focus_range,
 +                full_range,
 +                SymbolKind::Module,
 +            );
 +            res.docs = module.attrs(db).docs();
 +            res.description = Some(module.display(db).to_string());
 +            return res;
 +        }
 +        module.to_nav(db)
 +    }
 +
 +    #[cfg(test)]
 +    pub(crate) fn debug_render(&self) -> String {
 +        let mut buf = format!(
 +            "{} {:?} {:?} {:?}",
 +            self.name,
 +            self.kind.unwrap(),
 +            self.file_id,
 +            self.full_range
 +        );
 +        if let Some(focus_range) = self.focus_range {
 +            buf.push_str(&format!(" {:?}", focus_range))
 +        }
 +        if let Some(container_name) = &self.container_name {
 +            buf.push_str(&format!(" {}", container_name))
 +        }
 +        buf
 +    }
 +
 +    /// Allows `NavigationTarget` to be created from a `NameOwner`
 +    pub(crate) fn from_named(
 +        db: &RootDatabase,
 +        node @ InFile { file_id, value }: InFile<&dyn ast::HasName>,
 +        kind: SymbolKind,
 +    ) -> NavigationTarget {
 +        let name = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into());
 +        let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax()));
 +        let FileRange { file_id, range } = node.map(|it| it.syntax()).original_file_range(db);
 +
 +        NavigationTarget::from_syntax(file_id, name, focus_range, range, kind)
 +    }
 +
 +    fn from_syntax(
 +        file_id: FileId,
 +        name: SmolStr,
 +        focus_range: Option<TextRange>,
 +        full_range: TextRange,
 +        kind: SymbolKind,
 +    ) -> NavigationTarget {
 +        NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(kind),
 +            full_range,
 +            focus_range,
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        }
 +    }
 +}
 +
 +impl TryToNav for FileSymbol {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let full_range = self.loc.original_range(db)?;
 +        let name_range = self.loc.original_name_range(db)?;
 +
 +        Some(NavigationTarget {
 +            file_id: full_range.file_id,
 +            name: self.name.clone(),
 +            kind: Some(self.kind.into()),
 +            full_range: full_range.range,
 +            focus_range: Some(name_range.range),
 +            container_name: self.container_name.clone(),
 +            description: description_from_symbol(db, self),
 +            docs: None,
 +        })
 +    }
 +}
 +
 +impl TryToNav for Definition {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            Definition::Local(it) => Some(it.to_nav(db)),
 +            Definition::Label(it) => Some(it.to_nav(db)),
 +            Definition::Module(it) => Some(it.to_nav(db)),
 +            Definition::Macro(it) => it.try_to_nav(db),
 +            Definition::Field(it) => it.try_to_nav(db),
 +            Definition::SelfType(it) => it.try_to_nav(db),
 +            Definition::GenericParam(it) => it.try_to_nav(db),
 +            Definition::Function(it) => it.try_to_nav(db),
 +            Definition::Adt(it) => it.try_to_nav(db),
 +            Definition::Variant(it) => it.try_to_nav(db),
 +            Definition::Const(it) => it.try_to_nav(db),
 +            Definition::Static(it) => it.try_to_nav(db),
 +            Definition::Trait(it) => it.try_to_nav(db),
 +            Definition::TypeAlias(it) => it.try_to_nav(db),
 +            Definition::BuiltinType(_) => None,
 +            Definition::ToolModule(_) => None,
 +            Definition::BuiltinAttr(_) => None,
++            // FIXME: The focus range should be set to the helper declaration
++            Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
 +        }
 +    }
 +}
 +
 +impl TryToNav for hir::ModuleDef {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
 +            hir::ModuleDef::Function(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Adt(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Variant(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Const(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Static(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Trait(it) => it.try_to_nav(db),
 +            hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
 +            hir::ModuleDef::Macro(it) => it.try_to_nav(db),
 +            hir::ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +}
 +
 +pub(crate) trait ToNavFromAst {
 +    const KIND: SymbolKind;
 +}
 +impl ToNavFromAst for hir::Function {
 +    const KIND: SymbolKind = SymbolKind::Function;
 +}
 +impl ToNavFromAst for hir::Const {
 +    const KIND: SymbolKind = SymbolKind::Const;
 +}
 +impl ToNavFromAst for hir::Static {
 +    const KIND: SymbolKind = SymbolKind::Static;
 +}
 +impl ToNavFromAst for hir::Struct {
 +    const KIND: SymbolKind = SymbolKind::Struct;
 +}
 +impl ToNavFromAst for hir::Enum {
 +    const KIND: SymbolKind = SymbolKind::Enum;
 +}
 +impl ToNavFromAst for hir::Variant {
 +    const KIND: SymbolKind = SymbolKind::Variant;
 +}
 +impl ToNavFromAst for hir::Union {
 +    const KIND: SymbolKind = SymbolKind::Union;
 +}
 +impl ToNavFromAst for hir::TypeAlias {
 +    const KIND: SymbolKind = SymbolKind::TypeAlias;
 +}
 +impl ToNavFromAst for hir::Trait {
 +    const KIND: SymbolKind = SymbolKind::Trait;
 +}
 +
 +impl<D> TryToNav for D
 +where
 +    D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay,
 +    D::Ast: ast::HasName,
 +{
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let src = self.source(db)?;
 +        let mut res = NavigationTarget::from_named(
 +            db,
 +            src.as_ref().map(|it| it as &dyn ast::HasName),
 +            D::KIND,
 +        );
 +        res.docs = self.docs(db);
 +        res.description = Some(self.display(db).to_string());
 +        Some(res)
 +    }
 +}
 +
 +impl ToNav for hir::Module {
 +    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
 +        let InFile { file_id, value } = self.definition_source(db);
 +
 +        let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
 +        let (syntax, focus) = match &value {
 +            ModuleSource::SourceFile(node) => (node.syntax(), None),
 +            ModuleSource::Module(node) => (
 +                node.syntax(),
 +                node.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())),
 +            ),
 +            ModuleSource::BlockExpr(node) => (node.syntax(), None),
 +        };
 +        let FileRange { file_id, range: full_range } =
 +            InFile::new(file_id, syntax).original_file_range(db);
 +        NavigationTarget::from_syntax(file_id, name, focus, full_range, SymbolKind::Module)
 +    }
 +}
 +
 +impl TryToNav for hir::Impl {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let InFile { file_id, value } = self.source(db)?;
 +        let derive_attr = self.is_builtin_derive(db);
 +
 +        let focus_range = if derive_attr.is_some() {
 +            None
 +        } else {
 +            value.self_ty().and_then(|ty| orig_focus_range(db, file_id, ty.syntax()))
 +        };
 +
 +        let FileRange { file_id, range: full_range } = match &derive_attr {
 +            Some(attr) => attr.syntax().original_file_range(db),
 +            None => InFile::new(file_id, value.syntax()).original_file_range(db),
 +        };
 +
 +        Some(NavigationTarget::from_syntax(
 +            file_id,
 +            "impl".into(),
 +            focus_range,
 +            full_range,
 +            SymbolKind::Impl,
 +        ))
 +    }
 +}
 +
 +impl TryToNav for hir::Field {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let src = self.source(db)?;
 +
 +        let field_source = match &src.value {
 +            FieldSource::Named(it) => {
 +                let mut res =
 +                    NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
 +                res.docs = self.docs(db);
 +                res.description = Some(self.display(db).to_string());
 +                res
 +            }
 +            FieldSource::Pos(it) => {
 +                let FileRange { file_id, range } =
 +                    src.with_value(it.syntax()).original_file_range(db);
 +                NavigationTarget::from_syntax(file_id, "".into(), None, range, SymbolKind::Field)
 +            }
 +        };
 +        Some(field_source)
 +    }
 +}
 +
 +impl TryToNav for hir::Macro {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let src = self.source(db)?;
 +        let name_owner: &dyn ast::HasName = match &src.value {
 +            Either::Left(it) => it,
 +            Either::Right(it) => it,
 +        };
 +        let mut res = NavigationTarget::from_named(
 +            db,
 +            src.as_ref().with_value(name_owner),
 +            self.kind(db).into(),
 +        );
 +        res.docs = self.docs(db);
 +        Some(res)
 +    }
 +}
 +
 +impl TryToNav for hir::Adt {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            hir::Adt::Struct(it) => it.try_to_nav(db),
 +            hir::Adt::Union(it) => it.try_to_nav(db),
 +            hir::Adt::Enum(it) => it.try_to_nav(db),
 +        }
 +    }
 +}
 +
 +impl TryToNav for hir::AssocItem {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            AssocItem::Function(it) => it.try_to_nav(db),
 +            AssocItem::Const(it) => it.try_to_nav(db),
 +            AssocItem::TypeAlias(it) => it.try_to_nav(db),
 +        }
 +    }
 +}
 +
 +impl TryToNav for hir::GenericParam {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        match self {
 +            hir::GenericParam::TypeParam(it) => it.try_to_nav(db),
 +            hir::GenericParam::ConstParam(it) => it.try_to_nav(db),
 +            hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db),
 +        }
 +    }
 +}
 +
 +impl ToNav for hir::Local {
 +    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
 +        let InFile { file_id, value } = self.source(db);
 +        let (node, name) = match &value {
 +            Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()),
 +            Either::Right(it) => (it.syntax(), it.name()),
 +        };
 +        let focus_range = name.and_then(|it| orig_focus_range(db, file_id, it.syntax()));
 +        let FileRange { file_id, range: full_range } =
 +            InFile::new(file_id, node).original_file_range(db);
 +
 +        let name = self.name(db).to_smol_str();
 +        let kind = if self.is_self(db) {
 +            SymbolKind::SelfParam
 +        } else if self.is_param(db) {
 +            SymbolKind::ValueParam
 +        } else {
 +            SymbolKind::Local
 +        };
 +        NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(kind),
 +            full_range,
 +            focus_range,
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        }
 +    }
 +}
 +
 +impl ToNav for hir::Label {
 +    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
 +        let InFile { file_id, value } = self.source(db);
 +        let name = self.name(db).to_smol_str();
 +
 +        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
 +        let FileRange { file_id, range: full_range } = range(value.syntax());
 +        let focus_range = value.lifetime().map(|lt| range(lt.syntax()).range);
 +
 +        NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(SymbolKind::Label),
 +            full_range,
 +            focus_range,
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        }
 +    }
 +}
 +
 +impl TryToNav for hir::TypeParam {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let InFile { file_id, value } = self.merge().source(db)?;
 +        let name = self.name(db).to_smol_str();
 +
 +        let value = match value {
 +            Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x),
 +            Either::Left(ast::TypeOrConstParam::Const(_)) => {
 +                never!();
 +                return None;
 +            }
 +            Either::Right(x) => Either::Right(x),
 +        };
 +
 +        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
 +        let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db);
 +        let FileRange { file_id, range: full_range } = match &value {
 +            Either::Left(type_param) => range(type_param.syntax()),
 +            Either::Right(trait_) => trait_
 +                .name()
 +                .and_then(|name| focus_range(name.syntax()))
 +                .unwrap_or_else(|| range(trait_.syntax())),
 +        };
 +        let focus_range = value
 +            .either(|it| it.name(), |it| it.name())
 +            .and_then(|it| focus_range(it.syntax()))
 +            .map(|it| it.range);
 +        Some(NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(SymbolKind::TypeParam),
 +            full_range,
 +            focus_range,
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        })
 +    }
 +}
 +
 +impl TryToNav for hir::TypeOrConstParam {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        self.split(db).try_to_nav(db)
 +    }
 +}
 +
 +impl TryToNav for hir::LifetimeParam {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let InFile { file_id, value } = self.source(db)?;
 +        let name = self.name(db).to_smol_str();
 +
 +        let FileRange { file_id, range: full_range } =
 +            InFile::new(file_id, value.syntax()).original_file_range(db);
 +        Some(NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(SymbolKind::LifetimeParam),
 +            full_range,
 +            focus_range: Some(full_range),
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        })
 +    }
 +}
 +
 +impl TryToNav for hir::ConstParam {
 +    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
 +        let InFile { file_id, value } = self.merge().source(db)?;
 +        let name = self.name(db).to_smol_str();
 +
 +        let value = match value {
 +            Either::Left(ast::TypeOrConstParam::Const(x)) => x,
 +            _ => {
 +                never!();
 +                return None;
 +            }
 +        };
 +
 +        let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax()));
 +        let FileRange { file_id, range: full_range } =
 +            InFile::new(file_id, value.syntax()).original_file_range(db);
 +        Some(NavigationTarget {
 +            file_id,
 +            name,
 +            kind: Some(SymbolKind::ConstParam),
 +            full_range,
 +            focus_range,
 +            container_name: None,
 +            description: None,
 +            docs: None,
 +        })
 +    }
 +}
 +
 +/// Get a description of a symbol.
 +///
 +/// e.g. `struct Name`, `enum Name`, `fn Name`
 +pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
 +    let sema = Semantics::new(db);
 +    let node = symbol.loc.syntax(&sema)?;
 +
 +    match_ast! {
 +        match node {
 +            ast::Fn(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Static(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::RecordField(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Variant(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            ast::Union(it) => sema.to_def(&it).map(|it| it.display(db).to_string()),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +fn orig_focus_range(
 +    db: &RootDatabase,
 +    file_id: hir::HirFileId,
 +    syntax: &SyntaxNode,
 +) -> Option<TextRange> {
 +    InFile::new(file_id, syntax).original_file_range_opt(db).map(|it| it.range)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::expect;
 +
 +    use crate::{fixture, Query};
 +
 +    #[test]
 +    fn test_nav_for_symbol() {
 +        let (analysis, _) = fixture::file(
 +            r#"
 +enum FooInner { }
 +fn foo() { enum FooInner { } }
 +"#,
 +        );
 +
 +        let navs = analysis.symbol_search(Query::new("FooInner".to_string())).unwrap();
 +        expect![[r#"
 +            [
 +                NavigationTarget {
 +                    file_id: FileId(
 +                        0,
 +                    ),
 +                    full_range: 0..17,
 +                    focus_range: 5..13,
 +                    name: "FooInner",
 +                    kind: Enum,
 +                    description: "enum FooInner",
 +                },
 +                NavigationTarget {
 +                    file_id: FileId(
 +                        0,
 +                    ),
 +                    full_range: 29..46,
 +                    focus_range: 34..42,
 +                    name: "FooInner",
 +                    kind: Enum,
 +                    container_name: "foo",
 +                    description: "enum FooInner",
 +                },
 +            ]
 +        "#]]
 +        .assert_debug_eq(&navs);
 +    }
 +
 +    #[test]
 +    fn test_world_symbols_are_case_sensitive() {
 +        let (analysis, _) = fixture::file(
 +            r#"
 +fn foo() {}
 +struct Foo;
 +"#,
 +        );
 +
 +        let navs = analysis.symbol_search(Query::new("foo".to_string())).unwrap();
 +        assert_eq!(navs.len(), 2)
 +    }
 +}
index ba287d13aec1d2a341aac010a745431a7e83b687,0000000000000000000000000000000000000000..fedc1a435827233ac24135b0918167efa4238dc6
mode 100644,000000..100644
--- /dev/null
@@@ -1,1333 -1,0 +1,1334 @@@
-             | hir::PathResolution::SelfType(_) => return None,
 +//! This module provides primitives for showing type and function parameter information when editing
 +//! a call or use-site.
 +
 +use std::collections::BTreeSet;
 +
 +use either::Either;
 +use hir::{AssocItem, GenericParam, HasAttrs, HirDisplay, Semantics, Trait};
 +use ide_db::{active_parameter::callable_for_node, base_db::FilePosition};
 +use stdx::format_to;
 +use syntax::{
 +    algo,
 +    ast::{self, HasArgList},
 +    match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize,
 +};
 +
 +use crate::RootDatabase;
 +
 +/// Contains information about an item signature as seen from a use site.
 +///
 +/// This includes the "active parameter", which is the parameter whose value is currently being
 +/// edited.
 +#[derive(Debug)]
 +pub struct SignatureHelp {
 +    pub doc: Option<String>,
 +    pub signature: String,
 +    pub active_parameter: Option<usize>,
 +    parameters: Vec<TextRange>,
 +}
 +
 +impl SignatureHelp {
 +    pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
 +        self.parameters.iter().map(move |&it| &self.signature[it])
 +    }
 +
 +    pub fn parameter_ranges(&self) -> &[TextRange] {
 +        &self.parameters
 +    }
 +
 +    fn push_call_param(&mut self, param: &str) {
 +        self.push_param('(', param);
 +    }
 +
 +    fn push_generic_param(&mut self, param: &str) {
 +        self.push_param('<', param);
 +    }
 +
 +    fn push_param(&mut self, opening_delim: char, param: &str) {
 +        if !self.signature.ends_with(opening_delim) {
 +            self.signature.push_str(", ");
 +        }
 +        let start = TextSize::of(&self.signature);
 +        self.signature.push_str(param);
 +        let end = TextSize::of(&self.signature);
 +        self.parameters.push(TextRange::new(start, end))
 +    }
 +}
 +
 +/// Computes parameter information for the given position.
 +pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Option<SignatureHelp> {
 +    let sema = Semantics::new(db);
 +    let file = sema.parse(position.file_id);
 +    let file = file.syntax();
 +    let token = file
 +        .token_at_offset(position.offset)
 +        .left_biased()
 +        // if the cursor is sandwiched between two space tokens and the call is unclosed
 +        // this prevents us from leaving the CallExpression
 +        .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
 +    let token = sema.descend_into_macros_single(token);
 +
 +    for node in token.parent_ancestors() {
 +        match_ast! {
 +            match node {
 +                ast::ArgList(arg_list) => {
 +                    let cursor_outside = arg_list.r_paren_token().as_ref() == Some(&token);
 +                    if cursor_outside {
 +                        return None;
 +                    }
 +                    return signature_help_for_call(&sema, token);
 +                },
 +                ast::GenericArgList(garg_list) => {
 +                    let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);
 +                    if cursor_outside {
 +                        return None;
 +                    }
 +                    return signature_help_for_generics(&sema, token);
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn signature_help_for_call(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: SyntaxToken,
 +) -> Option<SignatureHelp> {
 +    // Find the calling expression and its NameRef
 +    let mut node = token.parent()?;
 +    let calling_node = loop {
 +        if let Some(callable) = ast::CallableExpr::cast(node.clone()) {
 +            if callable
 +                .arg_list()
 +                .map_or(false, |it| it.syntax().text_range().contains(token.text_range().start()))
 +            {
 +                break callable;
 +            }
 +        }
 +
 +        // Stop at multi-line expressions, since the signature of the outer call is not very
 +        // helpful inside them.
 +        if let Some(expr) = ast::Expr::cast(node.clone()) {
 +            if expr.syntax().text().contains_char('\n') {
 +                return None;
 +            }
 +        }
 +
 +        node = node.parent()?;
 +    };
 +
 +    let (callable, active_parameter) = callable_for_node(sema, &calling_node, &token)?;
 +
 +    let mut res =
 +        SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
 +
 +    let db = sema.db;
 +    let mut fn_params = None;
 +    match callable.kind() {
 +        hir::CallableKind::Function(func) => {
 +            res.doc = func.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "fn {}", func.name(db));
 +            fn_params = Some(match callable.receiver_param(db) {
 +                Some(_self) => func.params_without_self(db),
 +                None => func.assoc_fn_params(db),
 +            });
 +        }
 +        hir::CallableKind::TupleStruct(strukt) => {
 +            res.doc = strukt.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "struct {}", strukt.name(db));
 +        }
 +        hir::CallableKind::TupleEnumVariant(variant) => {
 +            res.doc = variant.docs(db).map(|it| it.into());
 +            format_to!(
 +                res.signature,
 +                "enum {}::{}",
 +                variant.parent_enum(db).name(db),
 +                variant.name(db)
 +            );
 +        }
 +        hir::CallableKind::Closure | hir::CallableKind::FnPtr => (),
 +    }
 +
 +    res.signature.push('(');
 +    {
 +        if let Some(self_param) = callable.receiver_param(db) {
 +            format_to!(res.signature, "{}", self_param)
 +        }
 +        let mut buf = String::new();
 +        for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() {
 +            buf.clear();
 +            if let Some(pat) = pat {
 +                match pat {
 +                    Either::Left(_self) => format_to!(buf, "self: "),
 +                    Either::Right(pat) => format_to!(buf, "{}: ", pat),
 +                }
 +            }
 +            // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is
 +            // in the middle of entering call arguments.
 +            // In that case, fall back to render definitions of the respective parameters.
 +            // This is overly conservative: we do not substitute known type vars
 +            // (see FIXME in tests::impl_trait) and falling back on any unknowns.
 +            match (ty.contains_unknown(), fn_params.as_deref()) {
 +                (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)),
 +                _ => format_to!(buf, "{}", ty.display(db)),
 +            }
 +            res.push_call_param(&buf);
 +        }
 +    }
 +    res.signature.push(')');
 +
 +    let mut render = |ret_type: hir::Type| {
 +        if !ret_type.is_unit() {
 +            format_to!(res.signature, " -> {}", ret_type.display(db));
 +        }
 +    };
 +    match callable.kind() {
 +        hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
 +            render(func.ret_type(db))
 +        }
 +        hir::CallableKind::Function(_) | hir::CallableKind::Closure | hir::CallableKind::FnPtr => {
 +            render(callable.return_type())
 +        }
 +        hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
 +    }
 +    Some(res)
 +}
 +
 +fn signature_help_for_generics(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: SyntaxToken,
 +) -> Option<SignatureHelp> {
 +    let parent = token.parent()?;
 +    let arg_list = parent
 +        .ancestors()
 +        .filter_map(ast::GenericArgList::cast)
 +        .find(|list| list.syntax().text_range().contains(token.text_range().start()))?;
 +
 +    let mut active_parameter = arg_list
 +        .generic_args()
 +        .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
 +        .count();
 +
 +    let first_arg_is_non_lifetime = arg_list
 +        .generic_args()
 +        .next()
 +        .map_or(false, |arg| !matches!(arg, ast::GenericArg::LifetimeArg(_)));
 +
 +    let mut generics_def = if let Some(path) =
 +        arg_list.syntax().ancestors().find_map(ast::Path::cast)
 +    {
 +        let res = sema.resolve_path(&path)?;
 +        let generic_def: hir::GenericDef = match res {
 +            hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(),
 +            hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(),
 +            hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(),
 +            hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(),
 +            hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(),
 +            hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))
 +            | hir::PathResolution::Def(hir::ModuleDef::Const(_))
 +            | hir::PathResolution::Def(hir::ModuleDef::Macro(_))
 +            | hir::PathResolution::Def(hir::ModuleDef::Module(_))
 +            | hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None,
 +            hir::PathResolution::BuiltinAttr(_)
 +            | hir::PathResolution::ToolModule(_)
 +            | hir::PathResolution::Local(_)
 +            | hir::PathResolution::TypeParam(_)
 +            | hir::PathResolution::ConstParam(_)
++            | hir::PathResolution::SelfType(_)
++            | hir::PathResolution::DeriveHelper(_) => return None,
 +        };
 +
 +        generic_def
 +    } else if let Some(method_call) = arg_list.syntax().parent().and_then(ast::MethodCallExpr::cast)
 +    {
 +        // recv.method::<$0>()
 +        let method = sema.resolve_method_call(&method_call)?;
 +        method.into()
 +    } else {
 +        return None;
 +    };
 +
 +    let mut res = SignatureHelp {
 +        doc: None,
 +        signature: String::new(),
 +        parameters: vec![],
 +        active_parameter: None,
 +    };
 +
 +    let db = sema.db;
 +    match generics_def {
 +        hir::GenericDef::Function(it) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "fn {}", it.name(db));
 +        }
 +        hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "enum {}", it.name(db));
 +        }
 +        hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "struct {}", it.name(db));
 +        }
 +        hir::GenericDef::Adt(hir::Adt::Union(it)) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "union {}", it.name(db));
 +        }
 +        hir::GenericDef::Trait(it) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "trait {}", it.name(db));
 +        }
 +        hir::GenericDef::TypeAlias(it) => {
 +            res.doc = it.docs(db).map(|it| it.into());
 +            format_to!(res.signature, "type {}", it.name(db));
 +        }
 +        hir::GenericDef::Variant(it) => {
 +            // In paths, generics of an enum can be specified *after* one of its variants.
 +            // eg. `None::<u8>`
 +            // We'll use the signature of the enum, but include the docs of the variant.
 +            res.doc = it.docs(db).map(|it| it.into());
 +            let it = it.parent_enum(db);
 +            format_to!(res.signature, "enum {}", it.name(db));
 +            generics_def = it.into();
 +        }
 +        // These don't have generic args that can be specified
 +        hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
 +    }
 +
 +    let params = generics_def.params(sema.db);
 +    let num_lifetime_params =
 +        params.iter().take_while(|param| matches!(param, GenericParam::LifetimeParam(_))).count();
 +    if first_arg_is_non_lifetime {
 +        // Lifetime parameters were omitted.
 +        active_parameter += num_lifetime_params;
 +    }
 +    res.active_parameter = Some(active_parameter);
 +
 +    res.signature.push('<');
 +    let mut buf = String::new();
 +    for param in params {
 +        if let hir::GenericParam::TypeParam(ty) = param {
 +            if ty.is_implicit(db) {
 +                continue;
 +            }
 +        }
 +
 +        buf.clear();
 +        format_to!(buf, "{}", param.display(db));
 +        res.push_generic_param(&buf);
 +    }
 +    if let hir::GenericDef::Trait(tr) = generics_def {
 +        add_assoc_type_bindings(db, &mut res, tr, arg_list);
 +    }
 +    res.signature.push('>');
 +
 +    Some(res)
 +}
 +
 +fn add_assoc_type_bindings(
 +    db: &RootDatabase,
 +    res: &mut SignatureHelp,
 +    tr: Trait,
 +    args: ast::GenericArgList,
 +) {
 +    if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() {
 +        // Assoc type bindings are only valid in type bound position.
 +        return;
 +    }
 +
 +    let present_bindings = args
 +        .generic_args()
 +        .filter_map(|arg| match arg {
 +            ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()),
 +            _ => None,
 +        })
 +        .collect::<BTreeSet<_>>();
 +
 +    let mut buf = String::new();
 +    for binding in &present_bindings {
 +        buf.clear();
 +        format_to!(buf, "{} = â€¦", binding);
 +        res.push_generic_param(&buf);
 +    }
 +
 +    for item in tr.items_with_supertraits(db) {
 +        if let AssocItem::TypeAlias(ty) = item {
 +            let name = ty.name(db).to_smol_str();
 +            if !present_bindings.contains(&*name) {
 +                buf.clear();
 +                format_to!(buf, "{} = â€¦", name);
 +                res.push_generic_param(&buf);
 +            }
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::iter;
 +
 +    use expect_test::{expect, Expect};
 +    use ide_db::base_db::{fixture::ChangeFixture, FilePosition};
 +    use stdx::format_to;
 +
 +    use crate::RootDatabase;
 +
 +    /// 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.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 })
 +    }
 +
 +    fn check(ra_fixture: &str, expect: Expect) {
 +        // Implicitly add `Sized` to avoid noisy `T: ?Sized` in the results.
 +        let fixture = format!(
 +            r#"
 +#[lang = "sized"] trait Sized {{}}
 +{ra_fixture}
 +            "#
 +        );
 +        let (db, position) = position(&fixture);
 +        let sig_help = crate::signature_help::signature_help(&db, position);
 +        let actual = match sig_help {
 +            Some(sig_help) => {
 +                let mut rendered = String::new();
 +                if let Some(docs) = &sig_help.doc {
 +                    format_to!(rendered, "{}\n------\n", docs.as_str());
 +                }
 +                format_to!(rendered, "{}\n", sig_help.signature);
 +                let mut offset = 0;
 +                for (i, range) in sig_help.parameter_ranges().iter().enumerate() {
 +                    let is_active = sig_help.active_parameter == Some(i);
 +
 +                    let start = u32::from(range.start());
 +                    let gap = start.checked_sub(offset).unwrap_or_else(|| {
 +                        panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges())
 +                    });
 +                    rendered.extend(iter::repeat(' ').take(gap as usize));
 +                    let param_text = &sig_help.signature[*range];
 +                    let width = param_text.chars().count(); // â€¦
 +                    let marker = if is_active { '^' } else { '-' };
 +                    rendered.extend(iter::repeat(marker).take(width));
 +                    offset += gap + u32::from(range.len());
 +                }
 +                if !sig_help.parameter_ranges().is_empty() {
 +                    format_to!(rendered, "\n");
 +                }
 +                rendered
 +            }
 +            None => String::new(),
 +        };
 +        expect.assert_eq(&actual);
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_two_args() {
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo($03, ); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: u32, y: u32) -> u32
 +                       ^^^^^^  ------
 +            "#]],
 +        );
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo(3$0, ); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: u32, y: u32) -> u32
 +                       ^^^^^^  ------
 +            "#]],
 +        );
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo(3,$0 ); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: u32, y: u32) -> u32
 +                       ------  ^^^^^^
 +            "#]],
 +        );
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo(3, $0); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: u32, y: u32) -> u32
 +                       ------  ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_two_args_empty() {
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo($0); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: u32, y: u32) -> u32
 +                       ^^^^^^  ------
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_two_args_first_generics() {
 +        check(
 +            r#"
 +fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
 +    where T: Copy + Display, U: Debug
 +{ x + y }
 +
 +fn bar() { foo($03, ); }
 +"#,
 +            expect![[r#"
 +                fn foo(x: i32, y: U) -> u32
 +                       ^^^^^^  ----
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_no_params() {
 +        check(
 +            r#"
 +fn foo<T>() -> T where T: Copy + Display {}
 +fn bar() { foo($0); }
 +"#,
 +            expect![[r#"
 +                fn foo() -> T
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_for_impl() {
 +        check(
 +            r#"
 +struct F;
 +impl F { pub fn new() { } }
 +fn bar() {
 +    let _ : F = F::new($0);
 +}
 +"#,
 +            expect![[r#"
 +                fn new()
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_for_method_self() {
 +        check(
 +            r#"
 +struct S;
 +impl S { pub fn do_it(&self) {} }
 +
 +fn bar() {
 +    let s: S = S;
 +    s.do_it($0);
 +}
 +"#,
 +            expect![[r#"
 +                fn do_it(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_for_method_with_arg() {
 +        check(
 +            r#"
 +struct S;
 +impl S {
 +    fn foo(&self, x: i32) {}
 +}
 +
 +fn main() { S.foo($0); }
 +"#,
 +            expect![[r#"
 +                fn foo(&self, x: i32)
 +                              ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_for_generic_method() {
 +        check(
 +            r#"
 +struct S<T>(T);
 +impl<T> S<T> {
 +    fn foo(&self, x: T) {}
 +}
 +
 +fn main() { S(1u32).foo($0); }
 +"#,
 +            expect![[r#"
 +                fn foo(&self, x: u32)
 +                              ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
 +        check(
 +            r#"
 +struct S;
 +impl S {
 +    fn foo(&self, x: i32) {}
 +}
 +
 +fn main() { S::foo($0); }
 +"#,
 +            expect![[r#"
 +                fn foo(self: &S, x: i32)
 +                       ^^^^^^^^  ------
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_with_docs_simple() {
 +        check(
 +            r#"
 +/// test
 +// non-doc-comment
 +fn foo(j: u32) -> u32 {
 +    j
 +}
 +
 +fn bar() {
 +    let _ = foo($0);
 +}
 +"#,
 +            expect![[r#"
 +                test
 +                ------
 +                fn foo(j: u32) -> u32
 +                       ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_with_docs() {
 +        check(
 +            r#"
 +/// Adds one to the number given.
 +///
 +/// # Examples
 +///
 +/// ```
 +/// let five = 5;
 +///
 +/// assert_eq!(6, my_crate::add_one(5));
 +/// ```
 +pub fn add_one(x: i32) -> i32 {
 +    x + 1
 +}
 +
 +pub fn do() {
 +    add_one($0
 +}"#,
 +            expect![[r##"
 +                Adds one to the number given.
 +
 +                # Examples
 +
 +                ```
 +                let five = 5;
 +
 +                assert_eq!(6, my_crate::add_one(5));
 +                ```
 +                ------
 +                fn add_one(x: i32) -> i32
 +                           ^^^^^^
 +            "##]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_with_docs_impl() {
 +        check(
 +            r#"
 +struct addr;
 +impl addr {
 +    /// Adds one to the number given.
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// let five = 5;
 +    ///
 +    /// assert_eq!(6, my_crate::add_one(5));
 +    /// ```
 +    pub fn add_one(x: i32) -> i32 {
 +        x + 1
 +    }
 +}
 +
 +pub fn do_it() {
 +    addr {};
 +    addr::add_one($0);
 +}
 +"#,
 +            expect![[r##"
 +                Adds one to the number given.
 +
 +                # Examples
 +
 +                ```
 +                let five = 5;
 +
 +                assert_eq!(6, my_crate::add_one(5));
 +                ```
 +                ------
 +                fn add_one(x: i32) -> i32
 +                           ^^^^^^
 +            "##]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_fn_signature_with_docs_from_actix() {
 +        check(
 +            r#"
 +trait Actor {
 +    /// Actor execution context type
 +    type Context;
 +}
 +trait WriteHandler<E>
 +where
 +    Self: Actor
 +{
 +    /// Method is called when writer finishes.
 +    ///
 +    /// By default this method stops actor's `Context`.
 +    fn finished(&mut self, ctx: &mut Self::Context) {}
 +}
 +
 +fn foo(mut r: impl WriteHandler<()>) {
 +    r.finished($0);
 +}
 +"#,
 +            expect![[r#"
 +                Method is called when writer finishes.
 +
 +                By default this method stops actor's `Context`.
 +                ------
 +                fn finished(&mut self, ctx: &mut <impl WriteHandler<()> as Actor>::Context)
 +                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn call_info_bad_offset() {
 +        check(
 +            r#"
 +fn foo(x: u32, y: u32) -> u32 {x + y}
 +fn bar() { foo $0 (3, ); }
 +"#,
 +            expect![[""]],
 +        );
 +    }
 +
 +    #[test]
 +    fn outside_of_arg_list() {
 +        check(
 +            r#"
 +fn foo(a: u8) {}
 +fn f() {
 +    foo(123)$0
 +}
 +"#,
 +            expect![[]],
 +        );
 +        check(
 +            r#"
 +fn foo<T>(a: u8) {}
 +fn f() {
 +    foo::<u32>$0()
 +}
 +"#,
 +            expect![[]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_nested_method_in_lambda() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo { fn bar(&self, _: u32) { } }
 +
 +fn bar(_: u32) { }
 +
 +fn main() {
 +    let foo = Foo;
 +    std::thread::spawn(move || foo.bar($0));
 +}
 +"#,
 +            expect![[r#"
 +                fn bar(&self, _: u32)
 +                              ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn works_for_tuple_structs() {
 +        check(
 +            r#"
 +/// A cool tuple struct
 +struct S(u32, i32);
 +fn main() {
 +    let s = S(0, $0);
 +}
 +"#,
 +            expect![[r#"
 +                A cool tuple struct
 +                ------
 +                struct S(u32, i32)
 +                         ---  ^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_struct() {
 +        check(
 +            r#"
 +struct S<T>(T);
 +fn main() {
 +    let s = S($0);
 +}
 +"#,
 +            expect![[r#"
 +                struct S({unknown})
 +                         ^^^^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn works_for_enum_variants() {
 +        check(
 +            r#"
 +enum E {
 +    /// A Variant
 +    A(i32),
 +    /// Another
 +    B,
 +    /// And C
 +    C { a: i32, b: i32 }
 +}
 +
 +fn main() {
 +    let a = E::A($0);
 +}
 +"#,
 +            expect![[r#"
 +                A Variant
 +                ------
 +                enum E::A(i32)
 +                          ^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn cant_call_struct_record() {
 +        check(
 +            r#"
 +struct S { x: u32, y: i32 }
 +fn main() {
 +    let s = S($0);
 +}
 +"#,
 +            expect![[""]],
 +        );
 +    }
 +
 +    #[test]
 +    fn cant_call_enum_record() {
 +        check(
 +            r#"
 +enum E {
 +    /// A Variant
 +    A(i32),
 +    /// Another
 +    B,
 +    /// And C
 +    C { a: i32, b: i32 }
 +}
 +
 +fn main() {
 +    let a = E::C($0);
 +}
 +"#,
 +            expect![[""]],
 +        );
 +    }
 +
 +    #[test]
 +    fn fn_signature_for_call_in_macro() {
 +        check(
 +            r#"
 +macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 +fn foo() { }
 +id! {
 +    fn bar() { foo($0); }
 +}
 +"#,
 +            expect![[r#"
 +                fn foo()
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn call_info_for_lambdas() {
 +        check(
 +            r#"
 +struct S;
 +fn foo(s: S) -> i32 { 92 }
 +fn main() {
 +    (|s| foo(s))($0)
 +}
 +        "#,
 +            expect![[r#"
 +                (s: S) -> i32
 +                 ^^^^
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn call_info_for_fn_ptr() {
 +        check(
 +            r#"
 +fn main(f: fn(i32, f64) -> char) {
 +    f(0, $0)
 +}
 +        "#,
 +            expect![[r#"
 +                (i32, f64) -> char
 +                 ---  ^^^
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn call_info_for_unclosed_call() {
 +        check(
 +            r#"
 +fn foo(foo: u32, bar: u32) {}
 +fn main() {
 +    foo($0
 +}"#,
 +            expect![[r#"
 +                fn foo(foo: u32, bar: u32)
 +                       ^^^^^^^^  --------
 +            "#]],
 +        );
 +        // check with surrounding space
 +        check(
 +            r#"
 +fn foo(foo: u32, bar: u32) {}
 +fn main() {
 +    foo( $0
 +}"#,
 +            expect![[r#"
 +                fn foo(foo: u32, bar: u32)
 +                       ^^^^^^^^  --------
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn test_multiline_argument() {
 +        check(
 +            r#"
 +fn callee(a: u8, b: u8) {}
 +fn main() {
 +    callee(match 0 {
 +        0 => 1,$0
 +    })
 +}"#,
 +            expect![[r#""#]],
 +        );
 +        check(
 +            r#"
 +fn callee(a: u8, b: u8) {}
 +fn main() {
 +    callee(match 0 {
 +        0 => 1,
 +    },$0)
 +}"#,
 +            expect![[r#"
 +                fn callee(a: u8, b: u8)
 +                          -----  ^^^^^
 +            "#]],
 +        );
 +        check(
 +            r#"
 +fn callee(a: u8, b: u8) {}
 +fn main() {
 +    callee($0match 0 {
 +        0 => 1,
 +    })
 +}"#,
 +            expect![[r#"
 +                fn callee(a: u8, b: u8)
 +                          ^^^^^  -----
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generics_simple() {
 +        check(
 +            r#"
 +/// Option docs.
 +enum Option<T> {
 +    Some(T),
 +    None,
 +}
 +
 +fn f() {
 +    let opt: Option<$0
 +}
 +        "#,
 +            expect![[r#"
 +                Option docs.
 +                ------
 +                enum Option<T>
 +                            ^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generics_on_variant() {
 +        check(
 +            r#"
 +/// Option docs.
 +enum Option<T> {
 +    /// Some docs.
 +    Some(T),
 +    /// None docs.
 +    None,
 +}
 +
 +use Option::*;
 +
 +fn f() {
 +    None::<$0
 +}
 +        "#,
 +            expect![[r#"
 +                None docs.
 +                ------
 +                enum Option<T>
 +                            ^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_lots_of_generics() {
 +        check(
 +            r#"
 +trait Tr<T> {}
 +
 +struct S<T>(T);
 +
 +impl<T> S<T> {
 +    fn f<G, H>(g: G, h: impl Tr<G>) where G: Tr<()> {}
 +}
 +
 +fn f() {
 +    S::<u8>::f::<(), $0
 +}
 +        "#,
 +            expect![[r#"
 +                fn f<G: Tr<()>, H>
 +                     ---------  ^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generics_in_trait_ufcs() {
 +        check(
 +            r#"
 +trait Tr {
 +    fn f<T: Tr, U>() {}
 +}
 +
 +struct S;
 +
 +impl Tr for S {}
 +
 +fn f() {
 +    <S as Tr>::f::<$0
 +}
 +        "#,
 +            expect![[r#"
 +                fn f<T: Tr, U>
 +                     ^^^^^  -
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generics_in_method_call() {
 +        check(
 +            r#"
 +struct S;
 +
 +impl S {
 +    fn f<T>(&self) {}
 +}
 +
 +fn f() {
 +    S.f::<$0
 +}
 +        "#,
 +            expect![[r#"
 +                fn f<T>
 +                     ^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generic_param_in_method_call() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn test<V>(&mut self, val: V) {}
 +}
 +fn sup() {
 +    Foo.test($0)
 +}
 +"#,
 +            expect![[r#"
 +                fn test(&mut self, val: V)
 +                                   ^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generic_kinds() {
 +        check(
 +            r#"
 +fn callee<'a, const A: u8, T, const C: u8>() {}
 +
 +fn f() {
 +    callee::<'static, $0
 +}
 +        "#,
 +            expect![[r#"
 +                fn callee<'a, const A: u8, T, const C: u8>
 +                          --  ^^^^^^^^^^^  -  -----------
 +            "#]],
 +        );
 +        check(
 +            r#"
 +fn callee<'a, const A: u8, T, const C: u8>() {}
 +
 +fn f() {
 +    callee::<NON_LIFETIME$0
 +}
 +        "#,
 +            expect![[r#"
 +                fn callee<'a, const A: u8, T, const C: u8>
 +                          --  ^^^^^^^^^^^  -  -----------
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_trait_assoc_types() {
 +        check(
 +            r#"
 +trait Trait<'a, T> {
 +    type Assoc;
 +}
 +fn f() -> impl Trait<(), $0
 +            "#,
 +            expect![[r#"
 +                trait Trait<'a, T, Assoc = â€¦>
 +                            --  -  ^^^^^^^^^
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Iterator {
 +    type Item;
 +}
 +fn f() -> impl Iterator<$0
 +            "#,
 +            expect![[r#"
 +                trait Iterator<Item = â€¦>
 +                               ^^^^^^^^
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Iterator {
 +    type Item;
 +}
 +fn f() -> impl Iterator<Item = $0
 +            "#,
 +            expect![[r#"
 +                trait Iterator<Item = â€¦>
 +                               ^^^^^^^^
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Tr {
 +    type A;
 +    type B;
 +}
 +fn f() -> impl Tr<$0
 +            "#,
 +            expect![[r#"
 +                trait Tr<A = â€¦, B = â€¦>
 +                         ^^^^^  -----
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Tr {
 +    type A;
 +    type B;
 +}
 +fn f() -> impl Tr<B$0
 +            "#,
 +            expect![[r#"
 +                trait Tr<A = â€¦, B = â€¦>
 +                         ^^^^^  -----
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Tr {
 +    type A;
 +    type B;
 +}
 +fn f() -> impl Tr<B = $0
 +            "#,
 +            expect![[r#"
 +                trait Tr<B = â€¦, A = â€¦>
 +                         ^^^^^  -----
 +            "#]],
 +        );
 +        check(
 +            r#"
 +trait Tr {
 +    type A;
 +    type B;
 +}
 +fn f() -> impl Tr<B = (), $0
 +            "#,
 +            expect![[r#"
 +                trait Tr<B = â€¦, A = â€¦>
 +                         -----  ^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_supertrait_assoc() {
 +        check(
 +            r#"
 +trait Super {
 +    type SuperTy;
 +}
 +trait Sub: Super + Super {
 +    type SubTy;
 +}
 +fn f() -> impl Sub<$0
 +            "#,
 +            expect![[r#"
 +                trait Sub<SubTy = â€¦, SuperTy = â€¦>
 +                          ^^^^^^^^^  -----------
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn no_assoc_types_outside_type_bounds() {
 +        check(
 +            r#"
 +trait Tr<T> {
 +    type Assoc;
 +}
 +
 +impl Tr<$0
 +        "#,
 +            expect![[r#"
 +            trait Tr<T>
 +                     ^
 +        "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn impl_trait() {
 +        // FIXME: Substitute type vars in impl trait (`U` -> `i8`)
 +        check(
 +            r#"
 +trait Trait<T> {}
 +struct Wrap<T>(T);
 +fn foo<U>(x: Wrap<impl Trait<U>>) {}
 +fn f() {
 +    foo::<i8>($0)
 +}
 +"#,
 +            expect![[r#"
 +                fn foo(x: Wrap<impl Trait<U>>)
 +                       ^^^^^^^^^^^^^^^^^^^^^^
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn fully_qualified_syntax() {
 +        check(
 +            r#"
 +fn f() {
 +    trait A { fn foo(&self, other: Self); }
 +    A::foo(&self$0, other);
 +}
 +"#,
 +            expect![[r#"
 +                fn foo(self: &Self, other: Self)
 +                       ^^^^^^^^^^^  -----------
 +            "#]],
 +        );
 +    }
 +}
index d7ad6a75799536f228fa15a8329d09af0f8988d7,0000000000000000000000000000000000000000..d013d6f4b19ff95b0ef03e178ed3a194983ca09a
mode 100644,000000..100644
--- /dev/null
@@@ -1,441 -1,0 +1,449 @@@
 +pub(crate) mod tags;
 +
 +mod highlights;
 +mod injector;
 +
 +mod highlight;
 +mod format;
 +mod macro_;
 +mod inject;
 +mod escape;
 +
 +mod html;
 +#[cfg(test)]
 +mod tests;
 +
 +use hir::{InFile, Name, Semantics};
 +use ide_db::{FxHashMap, RootDatabase};
 +use syntax::{
 +    ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
 +};
 +
 +use crate::{
 +    syntax_highlighting::{
 +        escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights,
 +        macro_::MacroHighlighter, tags::Highlight,
 +    },
 +    FileId, HlMod, HlTag,
 +};
 +
 +pub(crate) use html::highlight_as_html;
 +
 +#[derive(Debug, Clone, Copy)]
 +pub struct HlRange {
 +    pub range: TextRange,
 +    pub highlight: Highlight,
 +    pub binding_hash: Option<u64>,
 +}
 +
 +// Feature: Semantic Syntax Highlighting
 +//
 +// rust-analyzer highlights the code semantically.
 +// For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait.
 +// rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token.
 +// It's up to the client to map those to specific colors.
 +//
 +// The general rule is that a reference to an entity gets colored the same way as the entity itself.
 +// We also give special modifier for `mut` and `&mut` local variables.
 +//
 +//
 +// .Token Tags
 +//
 +// Rust-analyzer currently emits the following token tags:
 +//
 +// - For items:
 +// +
 +// [horizontal]
 +// attribute:: Emitted for attribute macros.
 +// enum:: Emitted for enums.
 +// function:: Emitted for free-standing functions.
 +// derive:: Emitted for derive macros.
 +// macro:: Emitted for function-like macros.
 +// method:: Emitted for associated functions, also knowns as methods.
 +// namespace:: Emitted for modules.
 +// struct:: Emitted for structs.
 +// trait:: Emitted for traits.
 +// typeAlias:: Emitted for type aliases and `Self` in `impl`s.
 +// union:: Emitted for unions.
 +//
 +// - For literals:
 +// +
 +// [horizontal]
 +// boolean:: Emitted for the boolean literals `true` and `false`.
 +// character:: Emitted for character literals.
 +// number:: Emitted for numeric literals.
 +// string:: Emitted for string literals.
 +// escapeSequence:: Emitted for escaped sequences inside strings like `\n`.
 +// formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros.
 +//
 +// - For operators:
 +// +
 +// [horizontal]
 +// operator:: Emitted for general operators.
 +// arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.
 +// bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.
 +// comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`.
 +// logical:: Emitted for the logical operators `||`, `&&`, `!`.
 +//
 +// - For punctuation:
 +// +
 +// [horizontal]
 +// punctuation:: Emitted for general punctuation.
 +// attributeBracket:: Emitted for attribute invocation brackets, that is the `#[` and `]` tokens.
 +// angle:: Emitted for `<>` angle brackets.
 +// brace:: Emitted for `{}` braces.
 +// bracket:: Emitted for `[]` brackets.
 +// parenthesis:: Emitted for `()` parentheses.
 +// colon:: Emitted for the `:` token.
 +// comma:: Emitted for the `,` token.
 +// dot:: Emitted for the `.` token.
 +// semi:: Emitted for the `;` token.
 +// macroBang:: Emitted for the `!` token in macro calls.
 +//
 +// //-
 +//
 +// [horizontal]
 +// builtinAttribute:: Emitted for names to builtin attributes in attribute path, the `repr` in `#[repr(u8)]` for example.
 +// builtinType:: Emitted for builtin types like `u32`, `str` and `f32`.
 +// comment:: Emitted for comments.
 +// constParameter:: Emitted for const parameters.
++// deriveHelper:: Emitted for derive helper attributes.
 +// enumMember:: Emitted for enum variants.
 +// generic:: Emitted for generic tokens that have no mapping.
 +// keyword:: Emitted for keywords.
 +// label:: Emitted for labels.
 +// lifetime:: Emitted for lifetimes.
 +// parameter:: Emitted for non-self function parameters.
 +// property:: Emitted for struct and union fields.
 +// selfKeyword:: Emitted for the self function parameter and self path-specifier.
 +// selfTypeKeyword:: Emitted for the Self type parameter.
 +// toolModule:: Emitted for tool modules.
 +// typeParameter:: Emitted for type parameters.
 +// unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of.
 +// variable:: Emitted for locals, constants and statics.
 +//
 +//
 +// .Token Modifiers
 +//
 +// Token modifiers allow to style some elements in the source code more precisely.
 +//
 +// Rust-analyzer currently emits the following token modifiers:
 +//
 +// [horizontal]
 +// async:: Emitted for async functions and the `async` and `await` keywords.
 +// attribute:: Emitted for tokens inside attributes.
 +// callable:: Emitted for locals whose types implements one of the `Fn*` traits.
 +// constant:: Emitted for consts.
 +// consuming:: Emitted for locals that are being consumed when use in a function call.
 +// controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator.
 +// crateRoot:: Emitted for crate names, like `serde` and `crate`.
 +// declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`.
 +// defaultLibrary:: Emitted for items from built-in crates (std, core, alloc, test and proc_macro).
 +// documentation:: Emitted for documentation comments.
 +// injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation.
 +// intraDocLink:: Emitted for intra doc links in doc-strings.
 +// library:: Emitted for items that are defined outside of the current crate.
 +// mutable:: Emitted for mutable locals and statics as well as functions taking `&mut self`.
 +// public:: Emitted for items that are from the current crate and are `pub`.
 +// reference:: Emitted for locals behind a reference and functions taking `self` by reference.
 +// static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts.
 +// trait:: Emitted for associated trait items.
 +// unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token.
 +//
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[]
 +// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
 +pub(crate) fn highlight(
 +    db: &RootDatabase,
 +    file_id: FileId,
 +    range_to_highlight: Option<TextRange>,
 +    syntactic_name_ref_highlighting: bool,
 +) -> Vec<HlRange> {
 +    let _p = profile::span("highlight");
 +    let sema = Semantics::new(db);
 +
 +    // Determine the root based on the given range.
 +    let (root, range_to_highlight) = {
 +        let source_file = sema.parse(file_id);
 +        let source_file = source_file.syntax();
 +        match range_to_highlight {
 +            Some(range) => {
 +                let node = match source_file.covering_element(range) {
 +                    NodeOrToken::Node(it) => it,
 +                    NodeOrToken::Token(it) => it.parent().unwrap_or_else(|| source_file.clone()),
 +                };
 +                (node, range)
 +            }
 +            None => (source_file.clone(), source_file.text_range()),
 +        }
 +    };
 +
 +    let mut hl = highlights::Highlights::new(root.text_range());
 +    let krate = match sema.scope(&root) {
 +        Some(it) => it.krate(),
 +        None => return hl.to_vec(),
 +    };
 +    traverse(
 +        &mut hl,
 +        &sema,
 +        file_id,
 +        &root,
 +        krate,
 +        range_to_highlight,
 +        syntactic_name_ref_highlighting,
 +    );
 +    hl.to_vec()
 +}
 +
 +fn traverse(
 +    hl: &mut Highlights,
 +    sema: &Semantics<'_, RootDatabase>,
 +    file_id: FileId,
 +    root: &SyntaxNode,
 +    krate: hir::Crate,
 +    range_to_highlight: TextRange,
 +    syntactic_name_ref_highlighting: bool,
 +) {
 +    let is_unlinked = sema.to_module_def(file_id).is_none();
 +    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
 +
 +    enum AttrOrDerive {
 +        Attr(ast::Item),
 +        Derive(ast::Item),
 +    }
 +
 +    impl AttrOrDerive {
 +        fn item(&self) -> &ast::Item {
 +            match self {
 +                AttrOrDerive::Attr(item) | AttrOrDerive::Derive(item) => item,
 +            }
 +        }
 +    }
 +
 +    let mut tt_level = 0;
 +    let mut attr_or_derive_item = None;
 +    let mut current_macro: Option<ast::Macro> = None;
 +    let mut macro_highlighter = MacroHighlighter::default();
 +    let mut inside_attribute = false;
 +
 +    // Walk all nodes, keeping track of whether we are inside a macro or not.
 +    // If in macro, expand it first and highlight the expanded code.
 +    for event in root.preorder_with_tokens() {
 +        use WalkEvent::{Enter, Leave};
 +
 +        let range = match &event {
 +            Enter(it) | Leave(it) => it.text_range(),
 +        };
 +
 +        // Element outside of the viewport, no need to highlight
 +        if range_to_highlight.intersect(range).is_none() {
 +            continue;
 +        }
 +
 +        // set macro and attribute highlighting states
 +        match event.clone() {
 +            Enter(NodeOrToken::Node(node)) if ast::TokenTree::can_cast(node.kind()) => {
 +                tt_level += 1;
 +            }
 +            Leave(NodeOrToken::Node(node)) if ast::TokenTree::can_cast(node.kind()) => {
 +                tt_level -= 1;
 +            }
 +            Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
 +                inside_attribute = true
 +            }
 +            Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
 +                inside_attribute = false
 +            }
 +
 +            Enter(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => {
 +                match ast::Item::cast(node.clone()) {
 +                    Some(ast::Item::MacroRules(mac)) => {
 +                        macro_highlighter.init();
 +                        current_macro = Some(mac.into());
 +                        continue;
 +                    }
 +                    Some(ast::Item::MacroDef(mac)) => {
 +                        macro_highlighter.init();
 +                        current_macro = Some(mac.into());
 +                        continue;
 +                    }
 +                    Some(item) => {
 +                        if matches!(node.kind(), FN | CONST | STATIC) {
 +                            bindings_shadow_count.clear();
 +                        }
 +
 +                        if attr_or_derive_item.is_none() {
 +                            if sema.is_attr_macro_call(&item) {
 +                                attr_or_derive_item = Some(AttrOrDerive::Attr(item));
 +                            } else {
 +                                let adt = match item {
 +                                    ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
 +                                    ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
 +                                    ast::Item::Union(it) => Some(ast::Adt::Union(it)),
 +                                    _ => None,
 +                                };
 +                                match adt {
 +                                    Some(adt) if sema.is_derive_annotated(&adt) => {
 +                                        attr_or_derive_item =
 +                                            Some(AttrOrDerive::Derive(ast::Item::from(adt)));
 +                                    }
 +                                    _ => (),
 +                                }
 +                            }
 +                        }
 +                    }
 +                    _ => (),
 +                }
 +            }
 +            Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => {
 +                match ast::Item::cast(node.clone()) {
 +                    Some(ast::Item::MacroRules(mac)) => {
 +                        assert_eq!(current_macro, Some(mac.into()));
 +                        current_macro = None;
 +                        macro_highlighter = MacroHighlighter::default();
 +                    }
 +                    Some(ast::Item::MacroDef(mac)) => {
 +                        assert_eq!(current_macro, Some(mac.into()));
 +                        current_macro = None;
 +                        macro_highlighter = MacroHighlighter::default();
 +                    }
 +                    Some(item)
 +                        if attr_or_derive_item.as_ref().map_or(false, |it| *it.item() == item) =>
 +                    {
 +                        attr_or_derive_item = None;
 +                    }
 +                    _ => (),
 +                }
 +            }
 +            _ => (),
 +        }
 +
 +        let element = match event {
 +            Enter(NodeOrToken::Token(tok)) if tok.kind() == WHITESPACE => continue,
 +            Enter(it) => it,
 +            Leave(NodeOrToken::Token(_)) => continue,
 +            Leave(NodeOrToken::Node(node)) => {
 +                // Doc comment highlighting injection, we do this when leaving the node
 +                // so that we overwrite the highlighting of the doc comment itself.
 +                inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
 +                continue;
 +            }
 +        };
 +
 +        if current_macro.is_some() {
 +            if let Some(tok) = element.as_token() {
 +                macro_highlighter.advance(tok);
 +            }
 +        }
 +
 +        let element = match element.clone() {
 +            NodeOrToken::Node(n) => match ast::NameLike::cast(n) {
 +                Some(n) => NodeOrToken::Node(n),
 +                None => continue,
 +            },
 +            NodeOrToken::Token(t) => NodeOrToken::Token(t),
 +        };
 +        let token = element.as_token().cloned();
 +
 +        // Descending tokens into macros is expensive even if no descending occurs, so make sure
 +        // that we actually are in a position where descending is possible.
 +        let in_macro = tt_level > 0
 +            || match attr_or_derive_item {
 +                Some(AttrOrDerive::Attr(_)) => true,
 +                Some(AttrOrDerive::Derive(_)) => inside_attribute,
 +                None => false,
 +            };
 +        let descended_element = if in_macro {
 +            // Attempt to descend tokens into macro-calls.
 +            match element {
 +                NodeOrToken::Token(token) if token.kind() != COMMENT => {
 +                    let token = match attr_or_derive_item {
 +                        Some(AttrOrDerive::Attr(_)) => {
 +                            sema.descend_into_macros_with_kind_preference(token)
 +                        }
 +                        Some(AttrOrDerive::Derive(_)) | None => {
 +                            sema.descend_into_macros_single(token)
 +                        }
 +                    };
 +                    match token.parent().and_then(ast::NameLike::cast) {
 +                        // Remap the token into the wrapping single token nodes
 +                        Some(parent) => match (token.kind(), parent.syntax().kind()) {
 +                            (T![self] | T![ident], NAME | NAME_REF) => NodeOrToken::Node(parent),
 +                            (T![self] | T![super] | T![crate] | T![Self], NAME_REF) => {
 +                                NodeOrToken::Node(parent)
 +                            }
 +                            (INT_NUMBER, NAME_REF) => NodeOrToken::Node(parent),
 +                            (LIFETIME_IDENT, LIFETIME) => NodeOrToken::Node(parent),
 +                            _ => NodeOrToken::Token(token),
 +                        },
 +                        None => NodeOrToken::Token(token),
 +                    }
 +                }
 +                e => e,
 +            }
 +        } else {
 +            element
 +        };
 +
 +        // FIXME: do proper macro def highlighting https://github.com/rust-lang/rust-analyzer/issues/6232
 +        // Skip metavariables from being highlighted to prevent keyword highlighting in them
 +        if descended_element.as_token().and_then(|t| macro_highlighter.highlight(t)).is_some() {
 +            continue;
 +        }
 +
 +        // string highlight injections, note this does not use the descended element as proc-macros
 +        // can rewrite string literals which invalidates our indices
 +        if let (Some(token), Some(descended_token)) = (token, descended_element.as_token()) {
 +            if ast::String::can_cast(token.kind()) && ast::String::can_cast(descended_token.kind())
 +            {
 +                let string = ast::String::cast(token);
 +                let string_to_highlight = ast::String::cast(descended_token.clone());
 +                if let Some((string, expanded_string)) = string.zip(string_to_highlight) {
 +                    if string.is_raw() {
 +                        if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() {
 +                            continue;
 +                        }
 +                    }
 +                    highlight_format_string(hl, &string, &expanded_string, range);
 +                    highlight_escape_string(hl, &string, range.start());
 +                }
 +            } else if ast::ByteString::can_cast(token.kind())
 +                && ast::ByteString::can_cast(descended_token.kind())
 +            {
 +                if let Some(byte_string) = ast::ByteString::cast(token) {
 +                    highlight_escape_string(hl, &byte_string, range.start());
 +                }
 +            }
 +        }
 +
 +        let element = match descended_element {
 +            NodeOrToken::Node(name_like) => highlight::name_like(
 +                sema,
 +                krate,
 +                &mut bindings_shadow_count,
 +                syntactic_name_ref_highlighting,
 +                name_like,
 +            ),
 +            NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)),
 +        };
 +        if let Some((mut highlight, binding_hash)) = element {
 +            if is_unlinked && highlight.tag == HlTag::UnresolvedReference {
 +                // do not emit unresolved references if the file is unlinked
 +                // let the editor do its highlighting for these tokens instead
 +                continue;
 +            }
++            if highlight.tag == HlTag::UnresolvedReference
++                && matches!(attr_or_derive_item, Some(AttrOrDerive::Derive(_)) if inside_attribute)
++            {
++                // do not emit unresolved references in derive helpers if the token mapping maps to
++                // something unresolvable. FIXME: There should be a way to prevent that
++                continue;
++            }
 +            if inside_attribute {
 +                highlight |= HlMod::Attribute
 +            }
 +
 +            hl.add(HlRange { range, highlight, binding_hash });
 +        }
 +    }
 +}
index fd3723ed454859719e8a9726019e5cd7e01d90ba,0000000000000000000000000000000000000000..9395e914c43aa6ad796215cf1f5b926f2a7df8dd
mode 100644,000000..100644
--- /dev/null
@@@ -1,689 -1,0 +1,690 @@@
 +//! Computes color for a single element.
 +
 +use hir::{AsAssocItem, HasVisibility, Semantics};
 +use ide_db::{
 +    defs::{Definition, IdentClass, NameClass, NameRefClass},
 +    FxHashMap, RootDatabase, SymbolKind,
 +};
 +use syntax::{
 +    ast, match_ast, AstNode, AstToken, NodeOrToken,
 +    SyntaxKind::{self, *},
 +    SyntaxNode, SyntaxToken, T,
 +};
 +
 +use crate::{
 +    syntax_highlighting::tags::{HlOperator, HlPunct},
 +    Highlight, HlMod, HlTag,
 +};
 +
 +pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Highlight> {
 +    if let Some(comment) = ast::Comment::cast(token.clone()) {
 +        let h = HlTag::Comment;
 +        return Some(match comment.kind().doc {
 +            Some(_) => h | HlMod::Documentation,
 +            None => h.into(),
 +        });
 +    }
 +
 +    let highlight: Highlight = match token.kind() {
 +        STRING | BYTE_STRING => HlTag::StringLiteral.into(),
 +        INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => {
 +            SymbolKind::Field.into()
 +        }
 +        INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
 +        BYTE => HlTag::ByteLiteral.into(),
 +        CHAR => HlTag::CharLiteral.into(),
 +        IDENT if token.parent().and_then(ast::TokenTree::cast).is_some() => {
 +            // from this point on we are inside a token tree, this only happens for identifiers
 +            // that were not mapped down into macro invocations
 +            HlTag::None.into()
 +        }
 +        p if p.is_punct() => punctuation(sema, token, p),
 +        k if k.is_keyword() => keyword(sema, token, k)?,
 +        _ => return None,
 +    };
 +    Some(highlight)
 +}
 +
 +pub(super) fn name_like(
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
 +    syntactic_name_ref_highlighting: bool,
 +    name_like: ast::NameLike,
 +) -> Option<(Highlight, Option<u64>)> {
 +    let mut binding_hash = None;
 +    let highlight = match name_like {
 +        ast::NameLike::NameRef(name_ref) => highlight_name_ref(
 +            sema,
 +            krate,
 +            bindings_shadow_count,
 +            &mut binding_hash,
 +            syntactic_name_ref_highlighting,
 +            name_ref,
 +        ),
 +        ast::NameLike::Name(name) => {
 +            highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
 +        }
 +        ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
 +            Some(IdentClass::NameClass(NameClass::Definition(def))) => {
 +                highlight_def(sema, krate, def) | HlMod::Definition
 +            }
 +            Some(IdentClass::NameRefClass(NameRefClass::Definition(def))) => {
 +                highlight_def(sema, krate, def)
 +            }
 +            // FIXME: Fallback for 'static and '_, as we do not resolve these yet
 +            _ => SymbolKind::LifetimeParam.into(),
 +        },
 +    };
 +    Some((highlight, binding_hash))
 +}
 +
 +fn punctuation(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: SyntaxToken,
 +    kind: SyntaxKind,
 +) -> Highlight {
 +    let parent = token.parent();
 +    let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind);
 +    match (kind, parent_kind) {
 +        (T![?], _) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
 +        (T![&], BIN_EXPR) => HlOperator::Bitwise.into(),
 +        (T![&], _) => {
 +            let h = HlTag::Operator(HlOperator::Other).into();
 +            let is_unsafe = parent
 +                .and_then(ast::RefExpr::cast)
 +                .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
 +            if let Some(true) = is_unsafe {
 +                h | HlMod::Unsafe
 +            } else {
 +                h
 +            }
 +        }
 +        (T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(),
 +        (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(),
 +        (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
 +        (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
 +        (T![*], PTR_TYPE) => HlTag::Keyword.into(),
 +        (T![*], PREFIX_EXPR) => {
 +            let is_raw_ptr = (|| {
 +                let prefix_expr = parent.and_then(ast::PrefixExpr::cast)?;
 +                let expr = prefix_expr.expr()?;
 +                sema.type_of_expr(&expr)?.original.is_raw_ptr().then(|| ())
 +            })();
 +            if let Some(()) = is_raw_ptr {
 +                HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
 +            } else {
 +                HlOperator::Other.into()
 +            }
 +        }
 +        (T![-], PREFIX_EXPR) => {
 +            let prefix_expr = parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
 +            match prefix_expr {
 +                Some(ast::Expr::Literal(_)) => HlTag::NumericLiteral,
 +                _ => HlTag::Operator(HlOperator::Other),
 +            }
 +            .into()
 +        }
 +        (T![+] | T![-] | T![*] | T![/] | T![%], BIN_EXPR) => HlOperator::Arithmetic.into(),
 +        (T![+=] | T![-=] | T![*=] | T![/=] | T![%=], BIN_EXPR) => {
 +            Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable
 +        }
 +        (T![|] | T![&] | T![!] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(),
 +        (T![|=] | T![&=] | T![^=] | T![>>=] | T![<<=], BIN_EXPR) => {
 +            Highlight::from(HlOperator::Bitwise) | HlMod::Mutable
 +        }
 +        (T![&&] | T![||], BIN_EXPR) => HlOperator::Logical.into(),
 +        (T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=], BIN_EXPR) => {
 +            HlOperator::Comparison.into()
 +        }
 +        (_, PREFIX_EXPR | BIN_EXPR | RANGE_EXPR | RANGE_PAT | REST_PAT) => HlOperator::Other.into(),
 +        (_, ATTR) => HlTag::AttributeBracket.into(),
 +        (kind, _) => match kind {
 +            T!['['] | T![']'] => HlPunct::Bracket,
 +            T!['{'] | T!['}'] => HlPunct::Brace,
 +            T!['('] | T![')'] => HlPunct::Parenthesis,
 +            T![<] | T![>] => HlPunct::Angle,
 +            T![,] => HlPunct::Comma,
 +            T![:] => HlPunct::Colon,
 +            T![;] => HlPunct::Semi,
 +            T![.] => HlPunct::Dot,
 +            _ => HlPunct::Other,
 +        }
 +        .into(),
 +    }
 +}
 +
 +fn keyword(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: SyntaxToken,
 +    kind: SyntaxKind,
 +) -> Option<Highlight> {
 +    let h = Highlight::new(HlTag::Keyword);
 +    let h = match kind {
 +        T![await] => h | HlMod::Async | HlMod::ControlFlow,
 +        T![async] => h | HlMod::Async,
 +        T![break]
 +        | T![continue]
 +        | T![else]
 +        | T![if]
 +        | T![in]
 +        | T![loop]
 +        | T![match]
 +        | T![return]
 +        | T![while]
 +        | T![yield] => h | HlMod::ControlFlow,
 +        T![for] if parent_matches::<ast::ForExpr>(&token) => h | HlMod::ControlFlow,
 +        T![unsafe] => h | HlMod::Unsafe,
 +        T![true] | T![false] => HlTag::BoolLiteral.into(),
 +        // crate is handled just as a token if it's in an `extern crate`
 +        T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
 +        // self, crate, super and `Self` are handled as either a Name or NameRef already, unless they
 +        // are inside unmapped token trees
 +        T![self] | T![crate] | T![super] | T![Self] if parent_matches::<ast::NameRef>(&token) => {
 +            return None
 +        }
 +        T![self] if parent_matches::<ast::Name>(&token) => return None,
 +        T![ref] => match token.parent().and_then(ast::IdentPat::cast) {
 +            Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe,
 +            _ => h,
 +        },
 +        _ => h,
 +    };
 +    Some(h)
 +}
 +
 +fn highlight_name_ref(
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
 +    binding_hash: &mut Option<u64>,
 +    syntactic_name_ref_highlighting: bool,
 +    name_ref: ast::NameRef,
 +) -> Highlight {
 +    let db = sema.db;
 +    if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref) {
 +        return res;
 +    }
 +
 +    let name_class = match NameRefClass::classify(sema, &name_ref) {
 +        Some(name_kind) => name_kind,
 +        None if syntactic_name_ref_highlighting => {
 +            return highlight_name_ref_by_syntax(name_ref, sema, krate)
 +        }
 +        // FIXME: This is required for helper attributes used by proc-macros, as those do not map down
 +        // to anything when used.
 +        // We can fix this for derive attributes since derive helpers are recorded, but not for
 +        // general attributes.
 +        None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR) => {
 +            return HlTag::Symbol(SymbolKind::Attribute).into();
 +        }
 +        None => return HlTag::UnresolvedReference.into(),
 +    };
 +    let mut h = match name_class {
 +        NameRefClass::Definition(def) => {
 +            if let Definition::Local(local) = &def {
 +                let name = local.name(db);
 +                let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
 +                *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
 +            };
 +
 +            let mut h = highlight_def(sema, krate, def);
 +
 +            match def {
 +                Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => {
 +                    h |= HlMod::Consuming;
 +                }
 +                Definition::Trait(trait_) if trait_.is_unsafe(db) => {
 +                    if ast::Impl::for_trait_name_ref(&name_ref)
 +                        .map_or(false, |impl_| impl_.unsafe_token().is_some())
 +                    {
 +                        h |= HlMod::Unsafe;
 +                    }
 +                }
 +                Definition::Field(field) => {
 +                    if let Some(parent) = name_ref.syntax().parent() {
 +                        if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
 +                            if let hir::VariantDef::Union(_) = field.parent_def(db) {
 +                                h |= HlMod::Unsafe;
 +                            }
 +                        }
 +                    }
 +                }
 +                Definition::Macro(_) => {
 +                    if let Some(macro_call) =
 +                        ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
 +                            .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
 +                    {
 +                        if sema.is_unsafe_macro_call(&macro_call) {
 +                            h |= HlMod::Unsafe;
 +                        }
 +                    }
 +                }
 +                _ => (),
 +            }
 +
 +            h
 +        }
 +        NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
 +    };
 +
 +    h.tag = match name_ref.token_kind() {
 +        T![Self] => HlTag::Symbol(SymbolKind::SelfType),
 +        T![self] => HlTag::Symbol(SymbolKind::SelfParam),
 +        T![super] | T![crate] => HlTag::Keyword,
 +        _ => h.tag,
 +    };
 +    h
 +}
 +
 +fn highlight_name(
 +    sema: &Semantics<'_, RootDatabase>,
 +    bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
 +    binding_hash: &mut Option<u64>,
 +    krate: hir::Crate,
 +    name: ast::Name,
 +) -> Highlight {
 +    let name_kind = NameClass::classify(sema, &name);
 +    if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
 +        let name = local.name(sema.db);
 +        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
 +        *shadow_count += 1;
 +        *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
 +    };
 +    match name_kind {
 +        Some(NameClass::Definition(def)) => {
 +            let mut h = highlight_def(sema, krate, def) | HlMod::Definition;
 +            if let Definition::Trait(trait_) = &def {
 +                if trait_.is_unsafe(sema.db) {
 +                    h |= HlMod::Unsafe;
 +                }
 +            }
 +            h
 +        }
 +        Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def),
 +        Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
 +            let mut h = HlTag::Symbol(SymbolKind::Field).into();
 +            if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) {
 +                h |= HlMod::Unsafe;
 +            }
 +            h
 +        }
 +        None => highlight_name_by_syntax(name) | HlMod::Definition,
 +    }
 +}
 +
 +fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
 +    fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
 +        use std::{collections::hash_map::DefaultHasher, hash::Hasher};
 +
 +        let mut hasher = DefaultHasher::new();
 +        x.hash(&mut hasher);
 +        hasher.finish()
 +    }
 +
 +    hash((name, shadow_count))
 +}
 +
 +fn highlight_def(
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +    def: Definition,
 +) -> Highlight {
 +    let db = sema.db;
 +    let mut h = match def {
 +        Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind(sema.db).into())),
 +        Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
 +        Definition::Module(module) => {
 +            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
 +            if module.is_crate_root(db) {
 +                h |= HlMod::CrateRoot;
 +            }
 +            h
 +        }
 +        Definition::Function(func) => {
 +            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
 +            if let Some(item) = func.as_assoc_item(db) {
 +                h |= HlMod::Associated;
 +                match func.self_param(db) {
 +                    Some(sp) => match sp.access(db) {
 +                        hir::Access::Exclusive => {
 +                            h |= HlMod::Mutable;
 +                            h |= HlMod::Reference;
 +                        }
 +                        hir::Access::Shared => h |= HlMod::Reference,
 +                        hir::Access::Owned => h |= HlMod::Consuming,
 +                    },
 +                    None => h |= HlMod::Static,
 +                }
 +
 +                match item.container(db) {
 +                    hir::AssocItemContainer::Impl(i) => {
 +                        if i.trait_(db).is_some() {
 +                            h |= HlMod::Trait;
 +                        }
 +                    }
 +                    hir::AssocItemContainer::Trait(_t) => {
 +                        h |= HlMod::Trait;
 +                    }
 +                }
 +            }
 +
 +            if func.is_unsafe_to_call(db) {
 +                h |= HlMod::Unsafe;
 +            }
 +            if func.is_async(db) {
 +                h |= HlMod::Async;
 +            }
 +
 +            h
 +        }
 +        Definition::Adt(adt) => {
 +            let h = match adt {
 +                hir::Adt::Struct(_) => HlTag::Symbol(SymbolKind::Struct),
 +                hir::Adt::Enum(_) => HlTag::Symbol(SymbolKind::Enum),
 +                hir::Adt::Union(_) => HlTag::Symbol(SymbolKind::Union),
 +            };
 +
 +            Highlight::new(h)
 +        }
 +        Definition::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)),
 +        Definition::Const(konst) => {
 +            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
 +
 +            if let Some(item) = konst.as_assoc_item(db) {
 +                h |= HlMod::Associated;
 +                match item.container(db) {
 +                    hir::AssocItemContainer::Impl(i) => {
 +                        if i.trait_(db).is_some() {
 +                            h |= HlMod::Trait;
 +                        }
 +                    }
 +                    hir::AssocItemContainer::Trait(_t) => {
 +                        h |= HlMod::Trait;
 +                    }
 +                }
 +            }
 +
 +            h
 +        }
 +        Definition::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)),
 +        Definition::TypeAlias(type_) => {
 +            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
 +
 +            if let Some(item) = type_.as_assoc_item(db) {
 +                h |= HlMod::Associated;
 +                match item.container(db) {
 +                    hir::AssocItemContainer::Impl(i) => {
 +                        if i.trait_(db).is_some() {
 +                            h |= HlMod::Trait;
 +                        }
 +                    }
 +                    hir::AssocItemContainer::Trait(_t) => {
 +                        h |= HlMod::Trait;
 +                    }
 +                }
 +            }
 +
 +            h
 +        }
 +        Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType),
 +        Definition::Static(s) => {
 +            let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
 +
 +            if s.is_mut(db) {
 +                h |= HlMod::Mutable;
 +                h |= HlMod::Unsafe;
 +            }
 +
 +            h
 +        }
 +        Definition::SelfType(_) => Highlight::new(HlTag::Symbol(SymbolKind::Impl)),
 +        Definition::GenericParam(it) => match it {
 +            hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)),
 +            hir::GenericParam::ConstParam(_) => {
 +                Highlight::new(HlTag::Symbol(SymbolKind::ConstParam))
 +            }
 +            hir::GenericParam::LifetimeParam(_) => {
 +                Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam))
 +            }
 +        },
 +        Definition::Local(local) => {
 +            let tag = if local.is_self(db) {
 +                HlTag::Symbol(SymbolKind::SelfParam)
 +            } else if local.is_param(db) {
 +                HlTag::Symbol(SymbolKind::ValueParam)
 +            } else {
 +                HlTag::Symbol(SymbolKind::Local)
 +            };
 +            let mut h = Highlight::new(tag);
 +            let ty = local.ty(db);
 +            if local.is_mut(db) || ty.is_mutable_reference() {
 +                h |= HlMod::Mutable;
 +            }
 +            if local.is_ref(db) || ty.is_reference() {
 +                h |= HlMod::Reference;
 +            }
 +            if ty.as_callable(db).is_some() || ty.impls_fnonce(db) {
 +                h |= HlMod::Callable;
 +            }
 +            h
 +        }
 +        Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)),
 +        Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)),
 +        Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)),
++        Definition::DeriveHelper(_) => Highlight::new(HlTag::Symbol(SymbolKind::DeriveHelper)),
 +    };
 +
 +    let def_crate = def.krate(db);
 +    let is_from_other_crate = def_crate != Some(krate);
 +    let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db));
 +    let is_builtin_type = matches!(def, Definition::BuiltinType(_));
 +    let is_public = def.visibility(db) == Some(hir::Visibility::Public);
 +
 +    match (is_from_other_crate, is_builtin_type, is_public) {
 +        (true, false, _) => h |= HlMod::Library,
 +        (false, _, true) => h |= HlMod::Public,
 +        _ => {}
 +    }
 +
 +    if is_from_builtin_crate {
 +        h |= HlMod::DefaultLibrary;
 +    }
 +
 +    h
 +}
 +
 +fn highlight_method_call_by_name_ref(
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +    name_ref: &ast::NameRef,
 +) -> Option<Highlight> {
 +    let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
 +    highlight_method_call(sema, krate, &mc)
 +}
 +
 +fn highlight_method_call(
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +    method_call: &ast::MethodCallExpr,
 +) -> Option<Highlight> {
 +    let func = sema.resolve_method_call(method_call)?;
 +
 +    let mut h = SymbolKind::Function.into();
 +    h |= HlMod::Associated;
 +
 +    if func.is_unsafe_to_call(sema.db) || sema.is_unsafe_method_call(method_call) {
 +        h |= HlMod::Unsafe;
 +    }
 +    if func.is_async(sema.db) {
 +        h |= HlMod::Async;
 +    }
 +    if func
 +        .as_assoc_item(sema.db)
 +        .and_then(|it| it.containing_trait_or_trait_impl(sema.db))
 +        .is_some()
 +    {
 +        h |= HlMod::Trait;
 +    }
 +
 +    let def_crate = func.module(sema.db).krate();
 +    let is_from_other_crate = def_crate != krate;
 +    let is_from_builtin_crate = def_crate.is_builtin(sema.db);
 +    let is_public = func.visibility(sema.db) == hir::Visibility::Public;
 +
 +    if is_from_other_crate {
 +        h |= HlMod::Library;
 +    } else if is_public {
 +        h |= HlMod::Public;
 +    }
 +
 +    if is_from_builtin_crate {
 +        h |= HlMod::DefaultLibrary;
 +    }
 +
 +    if let Some(self_param) = func.self_param(sema.db) {
 +        match self_param.access(sema.db) {
 +            hir::Access::Shared => h |= HlMod::Reference,
 +            hir::Access::Exclusive => {
 +                h |= HlMod::Mutable;
 +                h |= HlMod::Reference;
 +            }
 +            hir::Access::Owned => {
 +                if let Some(receiver_ty) =
 +                    method_call.receiver().and_then(|it| sema.type_of_expr(&it))
 +                {
 +                    if !receiver_ty.adjusted().is_copy(sema.db) {
 +                        h |= HlMod::Consuming
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    Some(h)
 +}
 +
 +fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
 +    let default = HlTag::UnresolvedReference;
 +
 +    let parent = match name.syntax().parent() {
 +        Some(it) => it,
 +        _ => return default.into(),
 +    };
 +
 +    let tag = match parent.kind() {
 +        STRUCT => SymbolKind::Struct,
 +        ENUM => SymbolKind::Enum,
 +        VARIANT => SymbolKind::Variant,
 +        UNION => SymbolKind::Union,
 +        TRAIT => SymbolKind::Trait,
 +        TYPE_ALIAS => SymbolKind::TypeAlias,
 +        TYPE_PARAM => SymbolKind::TypeParam,
 +        RECORD_FIELD => SymbolKind::Field,
 +        MODULE => SymbolKind::Module,
 +        FN => SymbolKind::Function,
 +        CONST => SymbolKind::Const,
 +        STATIC => SymbolKind::Static,
 +        IDENT_PAT => SymbolKind::Local,
 +        _ => return default.into(),
 +    };
 +
 +    tag.into()
 +}
 +
 +fn highlight_name_ref_by_syntax(
 +    name: ast::NameRef,
 +    sema: &Semantics<'_, RootDatabase>,
 +    krate: hir::Crate,
 +) -> Highlight {
 +    let default = HlTag::UnresolvedReference;
 +
 +    let parent = match name.syntax().parent() {
 +        Some(it) => it,
 +        _ => return default.into(),
 +    };
 +
 +    match parent.kind() {
 +        METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
 +            .and_then(|it| highlight_method_call(sema, krate, &it))
 +            .unwrap_or_else(|| SymbolKind::Function.into()),
 +        FIELD_EXPR => {
 +            let h = HlTag::Symbol(SymbolKind::Field);
 +            let is_union = ast::FieldExpr::cast(parent)
 +                .and_then(|field_expr| sema.resolve_field(&field_expr))
 +                .map_or(false, |field| {
 +                    matches!(field.parent_def(sema.db), hir::VariantDef::Union(_))
 +                });
 +            if is_union {
 +                h | HlMod::Unsafe
 +            } else {
 +                h.into()
 +            }
 +        }
 +        PATH_SEGMENT => {
 +            let name_based_fallback = || {
 +                if name.text().chars().next().unwrap_or_default().is_uppercase() {
 +                    SymbolKind::Struct.into()
 +                } else {
 +                    SymbolKind::Module.into()
 +                }
 +            };
 +            let path = match parent.parent().and_then(ast::Path::cast) {
 +                Some(it) => it,
 +                _ => return name_based_fallback(),
 +            };
 +            let expr = match path.syntax().parent() {
 +                Some(parent) => match_ast! {
 +                    match parent {
 +                        ast::PathExpr(path) => path,
 +                        ast::MacroCall(_) => return SymbolKind::Macro.into(),
 +                        _ => return name_based_fallback(),
 +                    }
 +                },
 +                // within path, decide whether it is module or adt by checking for uppercase name
 +                None => return name_based_fallback(),
 +            };
 +            let parent = match expr.syntax().parent() {
 +                Some(it) => it,
 +                None => return default.into(),
 +            };
 +
 +            match parent.kind() {
 +                CALL_EXPR => SymbolKind::Function.into(),
 +                _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
 +                    SymbolKind::Struct
 +                } else {
 +                    SymbolKind::Const
 +                }
 +                .into(),
 +            }
 +        }
 +        _ => default.into(),
 +    }
 +}
 +
 +fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local, db: &RootDatabase) -> bool {
 +    // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming.
 +    parents_match(node.clone().into(), &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST])
 +        && !local.ty(db).is_copy(db)
 +}
 +
 +/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly.
 +fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool {
 +    while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) {
 +        if parent.kind() != *kind {
 +            return false;
 +        }
 +
 +        // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value
 +        // in the same pattern is unstable: rust-lang/rust#68354.
 +        node = node.parent().unwrap().into();
 +        kinds = rest;
 +    }
 +
 +    // Only true if we matched all expected kinds
 +    kinds.is_empty()
 +}
 +
 +fn parent_matches<N: AstNode>(token: &SyntaxToken) -> bool {
 +    token.parent().map_or(false, |it| N::can_cast(it.kind()))
 +}
index 94d573a30b0412f5895bb63a0574ad83a334086c,0000000000000000000000000000000000000000..f779a985a99ae60eb9289044d604b64775532a35
mode 100644,000000..100644
--- /dev/null
@@@ -1,275 -1,0 +1,276 @@@
 +//! "Recursive" Syntax highlighting for code in doctests and fixtures.
 +
 +use std::mem;
 +
 +use either::Either;
 +use hir::{InFile, Semantics};
 +use ide_db::{
 +    active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
 +};
 +use syntax::{
 +    ast::{self, AstNode, IsString, QuoteOffsets},
 +    AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
 +    syntax_highlighting::{highlights::Highlights, injector::Injector},
 +    Analysis, HlMod, HlRange, HlTag, RootDatabase,
 +};
 +
 +pub(super) fn ra_fixture(
 +    hl: &mut Highlights,
 +    sema: &Semantics<'_, RootDatabase>,
 +    literal: &ast::String,
 +    expanded: &ast::String,
 +) -> Option<()> {
 +    let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?;
 +    if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) {
 +        return None;
 +    }
 +    let value = literal.value()?;
 +
 +    if let Some(range) = literal.open_quote_text_range() {
 +        hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
 +    }
 +
 +    let mut inj = Injector::default();
 +
 +    let mut text = &*value;
 +    let mut offset: TextSize = 0.into();
 +
 +    while !text.is_empty() {
 +        let marker = "$0";
 +        let idx = text.find(marker).unwrap_or(text.len());
 +        let (chunk, next) = text.split_at(idx);
 +        inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
 +
 +        text = next;
 +        offset += TextSize::of(chunk);
 +
 +        if let Some(next) = text.strip_prefix(marker) {
 +            if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
 +                hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None });
 +            }
 +
 +            text = next;
 +
 +            let marker_len = TextSize::of(marker);
 +            offset += marker_len;
 +        }
 +    }
 +
 +    let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
 +
 +    for mut hl_range in analysis.highlight(tmp_file_id).unwrap() {
 +        for range in inj.map_range_up(hl_range.range) {
 +            if let Some(range) = literal.map_range_up(range) {
 +                hl_range.range = range;
 +                hl.add(hl_range);
 +            }
 +        }
 +    }
 +
 +    if let Some(range) = literal.close_quote_text_range() {
 +        hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
 +    }
 +
 +    Some(())
 +}
 +
 +const RUSTDOC_FENCE_LENGTH: usize = 3;
 +const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
 +
 +/// Injection of syntax highlighting of doctests.
 +pub(super) fn doc_comment(
 +    hl: &mut Highlights,
 +    sema: &Semantics<'_, RootDatabase>,
 +    InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
 +) {
 +    let (attributes, def) = match doc_attributes(sema, node) {
 +        Some(it) => it,
 +        None => return,
 +    };
 +
 +    // Extract intra-doc links and emit highlights for them.
 +    if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
 +        extract_definitions_from_docs(&docs)
 +            .into_iter()
 +            .filter_map(|(range, link, ns)| {
 +                doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then(
 +                    |InFile { value: mapped_range, .. }| {
 +                        Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
 +                    },
 +                )
 +            })
 +            .for_each(|(range, def)| {
 +                hl.add(HlRange {
 +                    range,
 +                    highlight: module_def_to_hl_tag(def)
 +                        | HlMod::Documentation
 +                        | HlMod::Injected
 +                        | HlMod::IntraDocLink,
 +                    binding_hash: None,
 +                })
 +            });
 +    }
 +
 +    // Extract doc-test sources from the docs and calculate highlighting for them.
 +
 +    let mut inj = Injector::default();
 +    inj.add_unmapped("fn doctest() {\n");
 +
 +    let attrs_source_map = attributes.source_map(sema.db);
 +
 +    let mut is_codeblock = false;
 +    let mut is_doctest = false;
 +
 +    let mut new_comments = Vec::new();
 +    let mut string;
 +
 +    for attr in attributes.by_key("doc").attrs() {
 +        let InFile { file_id, value: src } = attrs_source_map.source_of(attr);
 +        if file_id != src_file_id {
 +            continue;
 +        }
 +        let (line, range) = match &src {
 +            Either::Left(it) => {
 +                string = match find_doc_string_in_attr(attr, it) {
 +                    Some(it) => it,
 +                    None => continue,
 +                };
 +                let text = string.text();
 +                let text_range = string.syntax().text_range();
 +                match string.quote_offsets() {
 +                    Some(QuoteOffsets { contents, .. }) => {
 +                        (&text[contents - text_range.start()], contents)
 +                    }
 +                    None => (text, text_range),
 +                }
 +            }
 +            Either::Right(comment) => {
 +                let value = comment.prefix().len();
 +                let range = comment.syntax().text_range();
 +                (
 +                    &comment.text()[value..],
 +                    TextRange::new(range.start() + TextSize::try_from(value).unwrap(), range.end()),
 +                )
 +            }
 +        };
 +
 +        let mut range_start = range.start();
 +        for line in line.split('\n') {
 +            let line_len = TextSize::from(line.len() as u32);
 +            let prev_range_start = {
 +                let next_range_start = range_start + line_len + TextSize::from(1);
 +                mem::replace(&mut range_start, next_range_start)
 +            };
 +            let mut pos = TextSize::from(0);
 +
 +            match RUSTDOC_FENCES.into_iter().find_map(|fence| line.find(fence)) {
 +                Some(idx) => {
 +                    is_codeblock = !is_codeblock;
 +                    // Check whether code is rust by inspecting fence guards
 +                    let guards = &line[idx + RUSTDOC_FENCE_LENGTH..];
 +                    let is_rust = is_rust_fence(guards);
 +                    is_doctest = is_codeblock && is_rust;
 +                    continue;
 +                }
 +                None if !is_doctest => continue,
 +                None => (),
 +            }
 +
 +            // whitespace after comment is ignored
 +            if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) {
 +                pos += TextSize::of(ws);
 +            }
 +            // lines marked with `#` should be ignored in output, we skip the `#` char
 +            if line[pos.into()..].starts_with('#') {
 +                pos += TextSize::of('#');
 +            }
 +
 +            new_comments.push(TextRange::at(prev_range_start, pos));
 +            inj.add(&line[pos.into()..], TextRange::new(pos, line_len) + prev_range_start);
 +            inj.add_unmapped("\n");
 +        }
 +    }
 +
 +    if new_comments.is_empty() {
 +        return; // no need to run an analysis on an empty file
 +    }
 +
 +    inj.add_unmapped("\n}");
 +
 +    let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
 +
 +    if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) {
 +        for HlRange { range, highlight, binding_hash } in ranges {
 +            for range in inj.map_range_up(range) {
 +                hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash });
 +            }
 +        }
 +    }
 +
 +    for range in new_comments {
 +        hl.add(HlRange {
 +            range,
 +            highlight: HlTag::Comment | HlMod::Documentation,
 +            binding_hash: None,
 +        });
 +    }
 +}
 +
 +fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::String> {
 +    match it.expr() {
 +        // #[doc = lit]
 +        Some(ast::Expr::Literal(lit)) => match lit.kind() {
 +            ast::LiteralKind::String(it) => Some(it),
 +            _ => None,
 +        },
 +        // #[cfg_attr(..., doc = "", ...)]
 +        None => {
 +            // We gotta hunt the string token manually here
 +            let text = attr.string_value()?;
 +            // FIXME: We just pick the first string literal that has the same text as the doc attribute
 +            // This means technically we might highlight the wrong one
 +            it.syntax()
 +                .descendants_with_tokens()
 +                .filter_map(NodeOrToken::into_token)
 +                .filter_map(ast::String::cast)
 +                .find(|string| {
 +                    string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text)
 +                })
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn module_def_to_hl_tag(def: Definition) -> HlTag {
 +    let symbol = match def {
 +        Definition::Module(_) => SymbolKind::Module,
 +        Definition::Function(_) => SymbolKind::Function,
 +        Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct,
 +        Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum,
 +        Definition::Adt(hir::Adt::Union(_)) => SymbolKind::Union,
 +        Definition::Variant(_) => SymbolKind::Variant,
 +        Definition::Const(_) => SymbolKind::Const,
 +        Definition::Static(_) => SymbolKind::Static,
 +        Definition::Trait(_) => SymbolKind::Trait,
 +        Definition::TypeAlias(_) => SymbolKind::TypeAlias,
 +        Definition::BuiltinType(_) => return HlTag::BuiltinType,
 +        Definition::Macro(_) => SymbolKind::Macro,
 +        Definition::Field(_) => SymbolKind::Field,
 +        Definition::SelfType(_) => SymbolKind::Impl,
 +        Definition::Local(_) => SymbolKind::Local,
 +        Definition::GenericParam(gp) => match gp {
 +            hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
 +            hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
 +            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
 +        },
 +        Definition::Label(_) => SymbolKind::Label,
 +        Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr,
 +        Definition::ToolModule(_) => SymbolKind::ToolModule,
++        Definition::DeriveHelper(_) => SymbolKind::DeriveHelper,
 +    };
 +    HlTag::Symbol(symbol)
 +}
index b900dadcfa3c953094ebc57b31acd0b0d23ff14d,0000000000000000000000000000000000000000..5262770f30317f9312cc156f5664f1185ceba8f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,339 -1,0 +1,340 @@@
 +//! Defines token tags we use for syntax highlighting.
 +//! A tag is not unlike a CSS class.
 +
 +use std::{
 +    fmt::{self, Write},
 +    ops,
 +};
 +
 +use ide_db::SymbolKind;
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct Highlight {
 +    pub tag: HlTag,
 +    pub mods: HlMods,
 +}
 +
 +#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct HlMods(u32);
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum HlTag {
 +    Symbol(SymbolKind),
 +
 +    AttributeBracket,
 +    BoolLiteral,
 +    BuiltinType,
 +    ByteLiteral,
 +    CharLiteral,
 +    Comment,
 +    EscapeSequence,
 +    FormatSpecifier,
 +    Keyword,
 +    NumericLiteral,
 +    Operator(HlOperator),
 +    Punctuation(HlPunct),
 +    StringLiteral,
 +    UnresolvedReference,
 +
 +    // For things which don't have a specific highlight.
 +    None,
 +}
 +
 +// Don't forget to adjust the feature description in crates/ide/src/syntax_highlighting.rs.
 +// And make sure to use the lsp strings used when converting to the protocol in crates\rust-analyzer\src\semantic_tokens.rs, not the names of the variants here.
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +#[repr(u8)]
 +pub enum HlMod {
 +    /// Used for items in traits and impls.
 +    Associated = 0,
 +    /// Used with keywords like `async` and `await`.
 +    Async,
 +    /// Used to differentiate individual elements within attributes.
 +    Attribute,
 +    /// Callable item or value.
 +    Callable,
 +    /// Value that is being consumed in a function call
 +    Consuming,
 +    /// Used with keywords like `if` and `break`.
 +    ControlFlow,
 +    /// Used for crate names, like `serde`.
 +    CrateRoot,
 +    /// Used for items from built-in crates (std, core, alloc, test and proc_macro).
 +    DefaultLibrary,
 +    /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
 +    /// not.
 +    Definition,
 +    /// Doc-strings like this one.
 +    Documentation,
 +    /// Highlighting injection like rust code in doc strings or ra_fixture.
 +    Injected,
 +    /// Used for intra doc links in doc injection.
 +    IntraDocLink,
 +    /// Used for items from other crates.
 +    Library,
 +    /// Mutable binding.
 +    Mutable,
 +    /// Used for public items.
 +    Public,
 +    /// Immutable reference.
 +    Reference,
 +    /// Used for associated functions.
 +    Static,
 +    /// Used for items in traits and trait impls.
 +    Trait,
 +    // Keep this last!
 +    /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations.
 +    Unsafe,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum HlPunct {
 +    /// []
 +    Bracket,
 +    /// {}
 +    Brace,
 +    /// ()
 +    Parenthesis,
 +    /// <>
 +    Angle,
 +    /// ,
 +    Comma,
 +    /// .
 +    Dot,
 +    /// :
 +    Colon,
 +    /// ;
 +    Semi,
 +    /// ! (only for macro calls)
 +    MacroBang,
 +    ///
 +    Other,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum HlOperator {
 +    /// |, &, !, ^, |=, &=, ^=
 +    Bitwise,
 +    /// +, -, *, /, +=, -=, *=, /=
 +    Arithmetic,
 +    /// &&, ||, !
 +    Logical,
 +    /// >, <, ==, >=, <=, !=
 +    Comparison,
 +    ///
 +    Other,
 +}
 +
 +impl HlTag {
 +    fn as_str(self) -> &'static str {
 +        match self {
 +            HlTag::Symbol(symbol) => match symbol {
 +                SymbolKind::Attribute => "attribute",
 +                SymbolKind::BuiltinAttr => "builtin_attr",
 +                SymbolKind::Const => "constant",
 +                SymbolKind::ConstParam => "const_param",
 +                SymbolKind::Derive => "derive",
++                SymbolKind::DeriveHelper => "derive_helper",
 +                SymbolKind::Enum => "enum",
 +                SymbolKind::Field => "field",
 +                SymbolKind::Function => "function",
 +                SymbolKind::Impl => "self_type",
 +                SymbolKind::Label => "label",
 +                SymbolKind::LifetimeParam => "lifetime",
 +                SymbolKind::Local => "variable",
 +                SymbolKind::Macro => "macro",
 +                SymbolKind::Module => "module",
 +                SymbolKind::SelfParam => "self_keyword",
 +                SymbolKind::SelfType => "self_type_keyword",
 +                SymbolKind::Static => "static",
 +                SymbolKind::Struct => "struct",
 +                SymbolKind::ToolModule => "tool_module",
 +                SymbolKind::Trait => "trait",
 +                SymbolKind::TypeAlias => "type_alias",
 +                SymbolKind::TypeParam => "type_param",
 +                SymbolKind::Union => "union",
 +                SymbolKind::ValueParam => "value_param",
 +                SymbolKind::Variant => "enum_variant",
 +            },
 +            HlTag::AttributeBracket => "attribute_bracket",
 +            HlTag::BoolLiteral => "bool_literal",
 +            HlTag::BuiltinType => "builtin_type",
 +            HlTag::ByteLiteral => "byte_literal",
 +            HlTag::CharLiteral => "char_literal",
 +            HlTag::Comment => "comment",
 +            HlTag::EscapeSequence => "escape_sequence",
 +            HlTag::FormatSpecifier => "format_specifier",
 +            HlTag::Keyword => "keyword",
 +            HlTag::Punctuation(punct) => match punct {
 +                HlPunct::Bracket => "bracket",
 +                HlPunct::Brace => "brace",
 +                HlPunct::Parenthesis => "parenthesis",
 +                HlPunct::Angle => "angle",
 +                HlPunct::Comma => "comma",
 +                HlPunct::Dot => "dot",
 +                HlPunct::Colon => "colon",
 +                HlPunct::Semi => "semicolon",
 +                HlPunct::MacroBang => "macro_bang",
 +                HlPunct::Other => "punctuation",
 +            },
 +            HlTag::NumericLiteral => "numeric_literal",
 +            HlTag::Operator(op) => match op {
 +                HlOperator::Bitwise => "bitwise",
 +                HlOperator::Arithmetic => "arithmetic",
 +                HlOperator::Logical => "logical",
 +                HlOperator::Comparison => "comparison",
 +                HlOperator::Other => "operator",
 +            },
 +            HlTag::StringLiteral => "string_literal",
 +            HlTag::UnresolvedReference => "unresolved_reference",
 +            HlTag::None => "none",
 +        }
 +    }
 +}
 +
 +impl fmt::Display for HlTag {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(self.as_str(), f)
 +    }
 +}
 +
 +impl HlMod {
 +    const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[
 +        HlMod::Associated,
 +        HlMod::Async,
 +        HlMod::Attribute,
 +        HlMod::Callable,
 +        HlMod::Consuming,
 +        HlMod::ControlFlow,
 +        HlMod::CrateRoot,
 +        HlMod::DefaultLibrary,
 +        HlMod::Definition,
 +        HlMod::Documentation,
 +        HlMod::Injected,
 +        HlMod::IntraDocLink,
 +        HlMod::Library,
 +        HlMod::Mutable,
 +        HlMod::Public,
 +        HlMod::Reference,
 +        HlMod::Static,
 +        HlMod::Trait,
 +        HlMod::Unsafe,
 +    ];
 +
 +    fn as_str(self) -> &'static str {
 +        match self {
 +            HlMod::Associated => "associated",
 +            HlMod::Async => "async",
 +            HlMod::Attribute => "attribute",
 +            HlMod::Callable => "callable",
 +            HlMod::Consuming => "consuming",
 +            HlMod::ControlFlow => "control",
 +            HlMod::CrateRoot => "crate_root",
 +            HlMod::DefaultLibrary => "default_library",
 +            HlMod::Definition => "declaration",
 +            HlMod::Documentation => "documentation",
 +            HlMod::Injected => "injected",
 +            HlMod::IntraDocLink => "intra_doc_link",
 +            HlMod::Library => "library",
 +            HlMod::Mutable => "mutable",
 +            HlMod::Public => "public",
 +            HlMod::Reference => "reference",
 +            HlMod::Static => "static",
 +            HlMod::Trait => "trait",
 +            HlMod::Unsafe => "unsafe",
 +        }
 +    }
 +
 +    fn mask(self) -> u32 {
 +        1 << (self as u32)
 +    }
 +}
 +
 +impl fmt::Display for HlMod {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(self.as_str(), f)
 +    }
 +}
 +
 +impl fmt::Display for Highlight {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        self.tag.fmt(f)?;
 +        for modifier in self.mods.iter() {
 +            f.write_char('.')?;
 +            modifier.fmt(f)?;
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl From<HlTag> for Highlight {
 +    fn from(tag: HlTag) -> Highlight {
 +        Highlight::new(tag)
 +    }
 +}
 +
 +impl From<HlOperator> for Highlight {
 +    fn from(op: HlOperator) -> Highlight {
 +        Highlight::new(HlTag::Operator(op))
 +    }
 +}
 +
 +impl From<HlPunct> for Highlight {
 +    fn from(punct: HlPunct) -> Highlight {
 +        Highlight::new(HlTag::Punctuation(punct))
 +    }
 +}
 +
 +impl From<SymbolKind> for Highlight {
 +    fn from(sym: SymbolKind) -> Highlight {
 +        Highlight::new(HlTag::Symbol(sym))
 +    }
 +}
 +
 +impl Highlight {
 +    pub(crate) fn new(tag: HlTag) -> Highlight {
 +        Highlight { tag, mods: HlMods::default() }
 +    }
 +    pub fn is_empty(&self) -> bool {
 +        self.tag == HlTag::None && self.mods == HlMods::default()
 +    }
 +}
 +
 +impl ops::BitOr<HlMod> for HlTag {
 +    type Output = Highlight;
 +
 +    fn bitor(self, rhs: HlMod) -> Highlight {
 +        Highlight::new(self) | rhs
 +    }
 +}
 +
 +impl ops::BitOrAssign<HlMod> for HlMods {
 +    fn bitor_assign(&mut self, rhs: HlMod) {
 +        self.0 |= rhs.mask();
 +    }
 +}
 +
 +impl ops::BitOrAssign<HlMod> for Highlight {
 +    fn bitor_assign(&mut self, rhs: HlMod) {
 +        self.mods |= rhs;
 +    }
 +}
 +
 +impl ops::BitOr<HlMod> for Highlight {
 +    type Output = Highlight;
 +
 +    fn bitor(mut self, rhs: HlMod) -> Highlight {
 +        self |= rhs;
 +        self
 +    }
 +}
 +
 +impl HlMods {
 +    pub fn contains(self, m: HlMod) -> bool {
 +        self.0 & m.mask() == m.mask()
 +    }
 +
 +    pub fn iter(self) -> impl Iterator<Item = HlMod> {
 +        HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
 +    }
 +}
index ff4c59447d879e3b9815663554dbfd03b746facd,0000000000000000000000000000000000000000..c4018d3b39e7705fabcdc36424a9de5a2d37aae3
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,107 @@@
 +//! Handle process life-time and message passing for proc-macro client
 +
 +use std::{
 +    ffi::{OsStr, OsString},
 +    io::{self, BufRead, BufReader, Write},
 +    process::{Child, ChildStdin, ChildStdout, Command, Stdio},
 +};
 +
 +use paths::{AbsPath, AbsPathBuf};
 +use stdx::JodChild;
 +
 +use crate::{
 +    msg::{Message, Request, Response},
 +    ProcMacroKind, ServerError,
 +};
 +
 +#[derive(Debug)]
 +pub(crate) struct ProcMacroProcessSrv {
 +    _process: Process,
 +    stdin: ChildStdin,
 +    stdout: BufReader<ChildStdout>,
 +}
 +
 +impl ProcMacroProcessSrv {
 +    pub(crate) fn run(
 +        process_path: AbsPathBuf,
 +        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
 +    ) -> io::Result<ProcMacroProcessSrv> {
 +        let mut process = Process::run(process_path, args)?;
 +        let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 +
 +        let srv = ProcMacroProcessSrv { _process: process, stdin, stdout };
 +
 +        Ok(srv)
 +    }
 +
 +    pub(crate) fn find_proc_macros(
 +        &mut self,
 +        dylib_path: &AbsPath,
 +    ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
 +        let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() };
 +
 +        let response = self.send_task(request)?;
 +
 +        match response {
 +            Response::ListMacros(it) => Ok(it),
 +            Response::ExpandMacro { .. } => {
 +                Err(ServerError { message: "unexpected response".to_string(), io: None })
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
 +        let mut buf = String::new();
 +        send_request(&mut self.stdin, &mut self.stdout, req, &mut buf)
 +    }
 +}
 +
 +#[derive(Debug)]
 +struct Process {
 +    child: JodChild,
 +}
 +
 +impl Process {
 +    fn run(
 +        path: AbsPathBuf,
 +        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
 +    ) -> io::Result<Process> {
 +        let args: Vec<OsString> = args.into_iter().map(|s| s.as_ref().into()).collect();
 +        let child = JodChild(mk_child(&path, &args)?);
 +        Ok(Process { child })
 +    }
 +
 +    fn stdio(&mut self) -> Option<(ChildStdin, BufReader<ChildStdout>)> {
 +        let stdin = self.child.stdin.take()?;
 +        let stdout = self.child.stdout.take()?;
 +        let read = BufReader::new(stdout);
 +
 +        Some((stdin, read))
 +    }
 +}
 +
 +fn mk_child(
 +    path: &AbsPath,
 +    args: impl IntoIterator<Item = impl AsRef<OsStr>>,
 +) -> io::Result<Child> {
 +    Command::new(path.as_os_str())
 +        .args(args)
++        .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::inherit())
 +        .spawn()
 +}
 +
 +fn send_request(
 +    mut writer: &mut impl Write,
 +    mut reader: &mut impl BufRead,
 +    req: Request,
 +    buf: &mut String,
 +) -> Result<Response, ServerError> {
 +    req.write(&mut writer)
 +        .map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
 +    let res = Response::read(&mut reader, buf)
 +        .map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
 +    res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9d0da5dee9c109e28e3f803d329a9f34b89115de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++[package]
++name = "proc-macro-srv-cli"
++version = "0.0.0"
++description = "TBD"
++license = "MIT OR Apache-2.0"
++edition = "2021"
++rust-version = "1.57"
++
++[dependencies]
++proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" }
++
++[features]
++sysroot-abi = ["proc-macro-srv/sysroot-abi"]
++
++[[bin]]
++name = "rust-analyzer-proc-macro-srv"
++path = "src/main.rs"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac9fa9f5a4ce5fa38668fe81ce48b87539905339
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++//! A standalone binary for `proc-macro-srv`.
++
++use proc_macro_srv::cli;
++
++fn main() -> std::io::Result<()> {
++    let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE");
++    match v.as_deref() {
++        Ok("this is unstable") => {
++            // very well, if you must
++        }
++        _ => {
++            eprintln!("If you're rust-analyzer, you can use this tool by exporting RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'.");
++            eprintln!("If not, you probably shouldn't use this tool. But do what you want: I'm an error message, not a cop.");
++            std::process::exit(122);
++        }
++    }
++
++    cli::run()
++}
index c90144509dec5c1c88681a02eae495e8b87b645b,0000000000000000000000000000000000000000..a80c962617bb3611a746e0d4482a3143621e4e65
mode 100644,000000..100644
--- /dev/null
@@@ -1,107 -1,0 +1,106 @@@
-     cmd
-         .current_dir(&staging_dir)
 +//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
 +//! `OUT_DIR`.
 +//!
 +//! `proc-macro-test` itself contains only a path to that artifact.
 +//!
 +//! The `PROC_MACRO_TEST_TOOLCHAIN` environment variable can be exported to use
 +//! a specific rustup toolchain: this allows testing against older ABIs (e.g.
 +//! 1.58) and future ABIs (stage1, nightly)
 +
 +use std::{
 +    env, fs,
 +    path::{Path, PathBuf},
 +    process::Command,
 +};
 +
 +use cargo_metadata::Message;
 +
 +fn main() {
 +    println!("cargo:rerun-if-changed=imp");
 +    println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN");
 +
 +    let out_dir = env::var_os("OUT_DIR").unwrap();
 +    let out_dir = Path::new(&out_dir);
 +
 +    let name = "proc-macro-test-impl";
 +    let version = "0.0.0";
 +
 +    let imp_dir = std::env::current_dir().unwrap().join("imp");
 +
 +    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
 +    // this'll error out if the staging dir didn't previously exist. using
 +    // `std::fs::exists` would suffer from TOCTOU so just do our best to
 +    // wipe it and ignore errors.
 +    let _ = std::fs::remove_dir_all(&staging_dir);
 +
 +    println!("Creating {}", staging_dir.display());
 +    std::fs::create_dir_all(&staging_dir).unwrap();
 +
 +    let src_dir = staging_dir.join("src");
 +    println!("Creating {}", src_dir.display());
 +    std::fs::create_dir_all(src_dir).unwrap();
 +
 +    for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] {
 +        let mut src = imp_dir.clone();
 +        let mut dst = staging_dir.clone();
 +        for el in item_els {
 +            src.push(el);
 +            dst.push(el);
 +        }
 +        println!("Copying {} to {}", src.display(), dst.display());
 +        std::fs::copy(src, dst).unwrap();
 +    }
 +
 +    let target_dir = out_dir.join("target");
 +
 +    let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
 +        // leverage rustup to find user-specific toolchain
 +        let mut cmd = Command::new("cargo");
 +        cmd.arg(format!("+{toolchain}"));
 +        cmd
 +    } else {
 +        Command::new(toolchain::cargo())
 +    };
 +
++    cmd.current_dir(&staging_dir)
 +        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
 +        // Explicit override the target directory to avoid using the same one which the parent
 +        // cargo is using, or we'll deadlock.
 +        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
 +        // instance to use the same target directory.
 +        .arg("--target-dir")
 +        .arg(&target_dir);
 +
 +    println!("Running {:?}", cmd);
 +
 +    let output = cmd.output().unwrap();
 +    if !output.status.success() {
 +        println!("proc-macro-test-impl failed to build");
 +        println!("============ stdout ============");
 +        println!("{}", String::from_utf8_lossy(&output.stdout));
 +        println!("============ stderr ============");
 +        println!("{}", String::from_utf8_lossy(&output.stderr));
 +        panic!("proc-macro-test-impl failed to build");
 +    }
 +
 +    let mut artifact_path = None;
 +    for message in Message::parse_stream(output.stdout.as_slice()) {
 +        match message.unwrap() {
 +            Message::CompilerArtifact(artifact) => {
 +                if artifact.target.kind.contains(&"proc-macro".to_string()) {
 +                    let repr = format!("{} {}", name, version);
 +                    if artifact.package_id.repr.starts_with(&repr) {
 +                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
 +                    }
 +                }
 +            }
 +            _ => (), // Unknown message
 +        }
 +    }
 +
 +    // This file is under `target_dir` and is already under `OUT_DIR`.
 +    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");
 +
 +    let info_path = out_dir.join("proc_macro_test_location.txt");
 +    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
 +}
index a3c5ac167406d7f7ca8641f0d1aa3b087d4201d4,0000000000000000000000000000000000000000..63d1d0ace96b973bd84f22e61f83348c120f34c6
mode 100644,000000..100644
--- /dev/null
@@@ -1,193 -1,0 +1,198 @@@
 +//! `rust-project.json` file format.
 +//!
 +//! This format is spiritually a serialization of [`base_db::CrateGraph`]. The
 +//! idea here is that people who do not use Cargo, can instead teach their build
 +//! system to generate `rust-project.json` which can be ingested by
 +//! rust-analyzer.
 +
 +use std::path::PathBuf;
 +
 +use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::FxHashMap;
 +use serde::{de, Deserialize};
 +
 +use crate::cfg_flag::CfgFlag;
 +
 +/// Roots and crates that compose this Rust project.
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +pub struct ProjectJson {
++    /// e.g. `path/to/sysroot`
++    pub(crate) sysroot: Option<AbsPathBuf>,
++    /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
 +    pub(crate) sysroot_src: Option<AbsPathBuf>,
 +    project_root: AbsPathBuf,
 +    crates: Vec<Crate>,
 +}
 +
 +/// A crate points to the root module of a crate and lists the dependencies of the crate. This is
 +/// useful in creating the crate graph.
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +pub struct Crate {
 +    pub(crate) display_name: Option<CrateDisplayName>,
 +    pub(crate) root_module: AbsPathBuf,
 +    pub(crate) edition: Edition,
 +    pub(crate) version: Option<String>,
 +    pub(crate) deps: Vec<Dependency>,
 +    pub(crate) cfg: Vec<CfgFlag>,
 +    pub(crate) target: Option<String>,
 +    pub(crate) env: FxHashMap<String, String>,
 +    pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
 +    pub(crate) is_workspace_member: bool,
 +    pub(crate) include: Vec<AbsPathBuf>,
 +    pub(crate) exclude: Vec<AbsPathBuf>,
 +    pub(crate) is_proc_macro: bool,
 +    pub(crate) repository: Option<String>,
 +}
 +
 +impl ProjectJson {
 +    /// Create a new ProjectJson instance.
 +    ///
 +    /// # Arguments
 +    ///
 +    /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
 +    /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
 +    ///            configuration.
 +    pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
 +        ProjectJson {
++            sysroot: data.sysroot.map(|it| base.join(it)),
 +            sysroot_src: data.sysroot_src.map(|it| base.join(it)),
 +            project_root: base.to_path_buf(),
 +            crates: data
 +                .crates
 +                .into_iter()
 +                .map(|crate_data| {
 +                    let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| {
 +                        crate_data.root_module.is_relative()
 +                            && !crate_data.root_module.starts_with("..")
 +                            || crate_data.root_module.starts_with(base)
 +                    });
 +                    let root_module = base.join(crate_data.root_module).normalize();
 +                    let (include, exclude) = match crate_data.source {
 +                        Some(src) => {
 +                            let absolutize = |dirs: Vec<PathBuf>| {
 +                                dirs.into_iter()
 +                                    .map(|it| base.join(it).normalize())
 +                                    .collect::<Vec<_>>()
 +                            };
 +                            (absolutize(src.include_dirs), absolutize(src.exclude_dirs))
 +                        }
 +                        None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
 +                    };
 +
 +                    Crate {
 +                        display_name: crate_data
 +                            .display_name
 +                            .map(CrateDisplayName::from_canonical_name),
 +                        root_module,
 +                        edition: crate_data.edition.into(),
 +                        version: crate_data.version.as_ref().map(ToString::to_string),
 +                        deps: crate_data
 +                            .deps
 +                            .into_iter()
 +                            .map(|dep_data| {
 +                                Dependency::new(dep_data.name, CrateId(dep_data.krate as u32))
 +                            })
 +                            .collect::<Vec<_>>(),
 +                        cfg: crate_data.cfg,
 +                        target: crate_data.target,
 +                        env: crate_data.env,
 +                        proc_macro_dylib_path: crate_data
 +                            .proc_macro_dylib_path
 +                            .map(|it| base.join(it)),
 +                        is_workspace_member,
 +                        include,
 +                        exclude,
 +                        is_proc_macro: crate_data.is_proc_macro,
 +                        repository: crate_data.repository,
 +                    }
 +                })
 +                .collect::<Vec<_>>(),
 +        }
 +    }
 +    /// Returns the number of crates in the project.
 +    pub fn n_crates(&self) -> usize {
 +        self.crates.len()
 +    }
 +    /// Returns an iterator over the crates in the project.
 +    pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
 +        self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate))
 +    }
 +    /// Returns the path to the project's root folder.
 +    pub fn path(&self) -> &AbsPath {
 +        &self.project_root
 +    }
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +pub struct ProjectJsonData {
++    sysroot: Option<PathBuf>,
 +    sysroot_src: Option<PathBuf>,
 +    crates: Vec<CrateData>,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +struct CrateData {
 +    display_name: Option<String>,
 +    root_module: PathBuf,
 +    edition: EditionData,
 +    #[serde(default)]
 +    version: Option<semver::Version>,
 +    deps: Vec<DepData>,
 +    #[serde(default)]
 +    cfg: Vec<CfgFlag>,
 +    target: Option<String>,
 +    #[serde(default)]
 +    env: FxHashMap<String, String>,
 +    proc_macro_dylib_path: Option<PathBuf>,
 +    is_workspace_member: Option<bool>,
 +    source: Option<CrateSource>,
 +    #[serde(default)]
 +    is_proc_macro: bool,
 +    #[serde(default)]
 +    repository: Option<String>,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename = "edition")]
 +enum EditionData {
 +    #[serde(rename = "2015")]
 +    Edition2015,
 +    #[serde(rename = "2018")]
 +    Edition2018,
 +    #[serde(rename = "2021")]
 +    Edition2021,
 +}
 +
 +impl From<EditionData> for Edition {
 +    fn from(data: EditionData) -> Self {
 +        match data {
 +            EditionData::Edition2015 => Edition::Edition2015,
 +            EditionData::Edition2018 => Edition::Edition2018,
 +            EditionData::Edition2021 => Edition::Edition2021,
 +        }
 +    }
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +struct DepData {
 +    /// Identifies a crate by position in the crates array.
 +    #[serde(rename = "crate")]
 +    krate: usize,
 +    #[serde(deserialize_with = "deserialize_crate_name")]
 +    name: CrateName,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +struct CrateSource {
 +    include_dirs: Vec<PathBuf>,
 +    exclude_dirs: Vec<PathBuf>,
 +}
 +
 +fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
 +where
 +    D: de::Deserializer<'de>,
 +{
 +    let name = String::deserialize(de)?;
 +    CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {:?}", err)))
 +}
index 52750f48969f7032fa6384242a43fa5dbc3cc992,0000000000000000000000000000000000000000..362bb0f5e79cdb8fea2bb68e7a0591f978c81c90
mode 100644,000000..100644
--- /dev/null
@@@ -1,221 -1,0 +1,232 @@@
-         let res = Sysroot::load(sysroot_src_dir)?;
 +//! 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};
 +
 +use crate::{utf8_stdout, 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)
 +    }
 +
 +    pub fn discover(dir: &AbsPath) -> Result<Sysroot> {
 +        tracing::debug!("Discovering sysroot for {}", dir.display());
 +        let sysroot_dir = discover_sysroot_dir(dir)?;
 +        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?;
-     pub fn load(sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
-         let mut sysroot = Sysroot { root: sysroot_src_dir, crates: Arena::default() };
++        let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
 +        Ok(res)
 +    }
 +
 +    pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option<ManifestPath> {
 +        tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
 +        let current_dir = cargo_toml.parent();
 +        discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
 +    }
 +
-                 .map(|it| sysroot.root.join(it))
++    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()
-                 sysroot.root.as_path().display(),
++                .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) -> Result<AbsPathBuf> {
 +    let mut rustc = Command::new(toolchain::rustc());
 +    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,
 +) -> 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.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 ddfea0ce4c4f1af0f188cdb83b984790a7802342,0000000000000000000000000000000000000000..e304a59c0180bf7ef9c38e8f6269c35f4c167973
mode 100644,000000..100644
--- /dev/null
@@@ -1,1817 -1,0 +1,1820 @@@
-     let sysroot_src_dir = AbsPathBuf::assert(sysroot_path);
-     Sysroot::load(sysroot_src_dir).unwrap()
 +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::{
 +    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,
 +    };
 +    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))
 +        }
 +    })
 +}
 +
 +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(
 +                        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(
 +                        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,
 +                    },
 +                    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(
 +                        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,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[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(
 +                        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(
 +                        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,
 +                    },
 +                    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(
 +                        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,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[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(
 +                        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(
 +                        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,
 +                    },
 +                    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(
 +                        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,
 +                    },
 +                },
 +            }"#]],
 +    )
 +}
 +
 +#[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(
 +                        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(
 +                        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(
 +                        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(
 +                        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(
 +                        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,
 +                    },
 +                    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(
 +                        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(
 +                        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(
 +                        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(
 +                        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(
 +                        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,
 +                    },
 +                },
 +            }"#]],
 +    );
 +}
 +
 +#[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 de42458354566f481b944db43b753c2328c3cefd,0000000000000000000000000000000000000000..b144006b44e037580db5354357c564ea466698ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,1016 -1,0 +1,1032 @@@
-         let sysroot = match &project_json.sysroot_src {
-             Some(path) => Some(Sysroot::load(path.clone())?),
-             None => None,
 +//! 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 stdx::always;
 +
 +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,
 +    },
 +    /// 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,
 +            } => 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())
 +                .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);
 +                ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
 +            }
 +            ProjectManifest::CargoToml(cargo_toml) => {
 +                let cargo_version = utf8_stdout({
 +                    let mut cmd = Command::new(toolchain::cargo());
 +                    cmd.arg("--version");
 +                    cmd
 +                })?;
 +
 +                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(),
 +                        cargo_version
 +                    )
 +                })?;
 +                let cargo = CargoWorkspace::new(meta);
 +
 +                let sysroot = if config.no_sysroot {
 +                    None
 +                } else {
 +                    Some(Sysroot::discover(cargo_toml.parent()).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(),
 +                    Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml),
 +                    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(Some(&cargo_toml), config.target.as_deref());
 +
 +                let cfg_overrides = config.cfg_overrides();
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    build_scripts: WorkspaceBuildScripts::default(),
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +                }
 +            }
 +        };
 +
 +        Ok(res)
 +    }
 +
 +    pub fn load_inline(
 +        project_json: ProjectJson,
 +        target: Option<&str>,
 +    ) -> Result<ProjectWorkspace> {
-                         include: vec![sysroot.root().to_path_buf()],
++        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, target);
 +        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"))?,
 +        )?;
 +        let rustc_cfg = rustc_cfg::get(None, None);
 +        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, .. } => {
 +                WorkspaceBuildScripts::run(config, cargo, progress).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,
 +            } => {
 +                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>,
 +    ) -> 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,
 +            ),
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                sysroot,
 +                rustc,
 +                rustc_cfg,
 +                cfg_overrides,
 +                build_scripts,
 +            } => 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>,
 +) -> 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: FxHashMap<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)))
 +                }
 +                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 ommitted, 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 4243af25ff1a19d47147494215fa3ca8441e0c2a,0000000000000000000000000000000000000000..0ada4b73e842d9d7f814bf71f74c9dc4441158c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,162 @@@
-         Some(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap())
 +//! 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, 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,
 +    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()?);
-         None
++        Ok(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap())
 +    } else {
-     Ok((host, vfs, proc_macro_client))
++        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(), 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)
 +        },
 +    );
 +
 +    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 4af60035a20e0e21c78daa8a1a3d0833dface9d6,0000000000000000000000000000000000000000..8f881cba4dbd7b113534e3cfdf1d6aa85bf95d27
mode 100644,000000..100644
--- /dev/null
@@@ -1,375 -1,0 +1,375 @@@
-     pub(crate) proc_macro_client: Option<ProcMacroServer>,
 +//! The context or environment in which the language server functions. In our
 +//! server implementation this is know as the `WorldState`.
 +//!
 +//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 +
 +use std::{sync::Arc, time::Instant};
 +
 +use crossbeam_channel::{unbounded, Receiver, Sender};
 +use flycheck::FlycheckHandle;
 +use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
 +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
 +use lsp_types::{SemanticTokens, Url};
 +use parking_lot::{Mutex, RwLock};
 +use proc_macro_api::ProcMacroServer;
 +use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
 +use rustc_hash::FxHashMap;
 +use vfs::AnchoredPathBuf;
 +
 +use crate::{
 +    config::Config,
 +    diagnostics::{CheckFixes, DiagnosticCollection},
 +    from_proto,
 +    line_index::{LineEndings, LineIndex},
 +    lsp_ext,
 +    main_loop::Task,
 +    mem_docs::MemDocs,
 +    op_queue::OpQueue,
 +    reload::{self, SourceRootConfig},
 +    task_pool::TaskPool,
 +    to_proto::url_from_abs_path,
 +    Result,
 +};
 +
 +// Enforces drop order
 +pub(crate) struct Handle<H, C> {
 +    pub(crate) handle: H,
 +    pub(crate) receiver: C,
 +}
 +
 +pub(crate) type ReqHandler = fn(&mut GlobalState, lsp_server::Response);
 +pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
 +
 +/// `GlobalState` is the primary mutable state of the language server
 +///
 +/// The most interesting components are `vfs`, which stores a consistent
 +/// snapshot of the file systems, and `analysis_host`, which stores our
 +/// incremental salsa database.
 +///
 +/// Note that this struct has more than one impl in various modules!
 +pub(crate) struct GlobalState {
 +    sender: Sender<lsp_server::Message>,
 +    req_queue: ReqQueue,
 +    pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
 +    pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis_host: AnalysisHost,
 +    pub(crate) diagnostics: DiagnosticCollection,
 +    pub(crate) mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    pub(crate) shutdown_requested: bool,
 +    pub(crate) proc_macro_changed: bool,
 +    pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
 +    pub(crate) source_root_config: SourceRootConfig,
-             proc_macro_client: None,
++    pub(crate) proc_macro_clients: Vec<Result<ProcMacroServer, String>>,
 +
 +    pub(crate) flycheck: Vec<FlycheckHandle>,
 +    pub(crate) flycheck_sender: Sender<flycheck::Message>,
 +    pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 +
 +    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
 +    pub(crate) vfs_config_version: u32,
 +    pub(crate) vfs_progress_config_version: u32,
 +    pub(crate) vfs_progress_n_total: usize,
 +    pub(crate) vfs_progress_n_done: usize,
 +
 +    /// `workspaces` field stores the data we actually use, while the `OpQueue`
 +    /// stores the result of the last fetch.
 +    ///
 +    /// If the fetch (partially) fails, we do not update the current value.
 +    ///
 +    /// The handling of build data is subtle. We fetch workspace in two phases:
 +    ///
 +    /// *First*, we run `cargo metadata`, which gives us fast results for
 +    /// initial analysis.
 +    ///
 +    /// *Second*, we run `cargo check` which runs build scripts and compiles
 +    /// proc macros.
 +    ///
 +    /// We need both for the precise analysis, but we want rust-analyzer to be
 +    /// at least partially available just after the first phase. That's because
 +    /// first phase is much faster, and is much less likely to fail.
 +    ///
 +    /// This creates a complication -- by the time the second phase completes,
 +    /// the results of the fist phase could be invalid. That is, while we run
 +    /// `cargo check`, the user edits `Cargo.toml`, we notice this, and the new
 +    /// `cargo metadata` completes before `cargo check`.
 +    ///
 +    /// An additional complication is that we want to avoid needless work. When
 +    /// the user just adds comments or whitespace to Cargo.toml, we do not want
 +    /// to invalidate any salsa caches.
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +    pub(crate) fetch_workspaces_queue: OpQueue<Vec<anyhow::Result<ProjectWorkspace>>>,
 +    pub(crate) fetch_build_data_queue:
 +        OpQueue<(Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
 +
 +    pub(crate) prime_caches_queue: OpQueue<()>,
 +}
 +
 +/// An immutable snapshot of the world's state at a point in time.
 +pub(crate) struct GlobalStateSnapshot {
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis: Analysis,
 +    pub(crate) check_fixes: CheckFixes,
 +    mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +}
 +
 +impl std::panic::UnwindSafe for GlobalStateSnapshot {}
 +
 +impl GlobalState {
 +    pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> GlobalState {
 +        let loader = {
 +            let (sender, receiver) = unbounded::<vfs::loader::Message>();
 +            let handle: vfs_notify::NotifyHandle =
 +                vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
 +            let handle = Box::new(handle) as Box<dyn vfs::loader::Handle>;
 +            Handle { handle, receiver }
 +        };
 +
 +        let task_pool = {
 +            let (sender, receiver) = unbounded();
 +            let handle = TaskPool::new(sender);
 +            Handle { handle, receiver }
 +        };
 +
 +        let analysis_host = AnalysisHost::new(config.lru_capacity());
 +        let (flycheck_sender, flycheck_receiver) = unbounded();
 +        let mut this = GlobalState {
 +            sender,
 +            req_queue: ReqQueue::default(),
 +            task_pool,
 +            loader,
 +            config: Arc::new(config.clone()),
 +            analysis_host,
 +            diagnostics: Default::default(),
 +            mem_docs: MemDocs::default(),
 +            semantic_tokens_cache: Arc::new(Default::default()),
 +            shutdown_requested: false,
 +            proc_macro_changed: false,
 +            last_reported_status: None,
 +            source_root_config: SourceRootConfig::default(),
++            proc_macro_clients: vec![],
 +
 +            flycheck: Vec::new(),
 +            flycheck_sender,
 +            flycheck_receiver,
 +
 +            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
 +            vfs_config_version: 0,
 +            vfs_progress_config_version: 0,
 +            vfs_progress_n_total: 0,
 +            vfs_progress_n_done: 0,
 +
 +            workspaces: Arc::new(Vec::new()),
 +            fetch_workspaces_queue: OpQueue::default(),
 +            prime_caches_queue: OpQueue::default(),
 +
 +            fetch_build_data_queue: OpQueue::default(),
 +        };
 +        // Apply any required database inputs from the config.
 +        this.update_configuration(config);
 +        this
 +    }
 +
 +    pub(crate) fn process_changes(&mut self) -> bool {
 +        let _p = profile::span("GlobalState::process_changes");
 +        let mut fs_changes = Vec::new();
 +        // A file was added or deleted
 +        let mut has_structure_changes = false;
 +
 +        let (change, changed_files) = {
 +            let mut change = Change::new();
 +            let (vfs, line_endings_map) = &mut *self.vfs.write();
 +            let changed_files = vfs.take_changes();
 +            if changed_files.is_empty() {
 +                return false;
 +            }
 +
 +            for file in &changed_files {
 +                if let Some(path) = vfs.file_path(file.file_id).as_path() {
 +                    let path = path.to_path_buf();
 +                    if reload::should_refresh_for_change(&path, file.change_kind) {
 +                        self.fetch_workspaces_queue
 +                            .request_op(format!("vfs file change: {}", path.display()));
 +                    }
 +                    fs_changes.push((path, file.change_kind));
 +                    if file.is_created_or_deleted() {
 +                        has_structure_changes = true;
 +                    }
 +                }
 +
 +                if !file.exists() {
 +                    self.diagnostics.clear_native_for(file.file_id);
 +                }
 +
 +                let text = if file.exists() {
 +                    let bytes = vfs.file_contents(file.file_id).to_vec();
 +                    String::from_utf8(bytes).ok().and_then(|text| {
 +                        let (text, line_endings) = LineEndings::normalize(text);
 +                        line_endings_map.insert(file.file_id, line_endings);
 +                        Some(Arc::new(text))
 +                    })
 +                } else {
 +                    None
 +                };
 +                change.change_file(file.file_id, text);
 +            }
 +            if has_structure_changes {
 +                let roots = self.source_root_config.partition(vfs);
 +                change.set_roots(roots);
 +            }
 +            (change, changed_files)
 +        };
 +
 +        self.analysis_host.apply_change(change);
 +
 +        let raw_database = &self.analysis_host.raw_database();
 +        self.proc_macro_changed =
 +            changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
 +                let crates = raw_database.relevant_crates(file.file_id);
 +                let crate_graph = raw_database.crate_graph();
 +
 +                crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
 +            });
 +        true
 +    }
 +
 +    pub(crate) fn snapshot(&self) -> GlobalStateSnapshot {
 +        GlobalStateSnapshot {
 +            config: Arc::clone(&self.config),
 +            workspaces: Arc::clone(&self.workspaces),
 +            analysis: self.analysis_host.analysis(),
 +            vfs: Arc::clone(&self.vfs),
 +            check_fixes: Arc::clone(&self.diagnostics.check_fixes),
 +            mem_docs: self.mem_docs.clone(),
 +            semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
 +        }
 +    }
 +
 +    pub(crate) fn send_request<R: lsp_types::request::Request>(
 +        &mut self,
 +        params: R::Params,
 +        handler: ReqHandler,
 +    ) {
 +        let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
 +        self.send(request.into());
 +    }
 +
 +    pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
 +        let handler = self
 +            .req_queue
 +            .outgoing
 +            .complete(response.id.clone())
 +            .expect("received response for unknown request");
 +        handler(self, response)
 +    }
 +
 +    pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
 +        &mut self,
 +        params: N::Params,
 +    ) {
 +        let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
 +        self.send(not.into());
 +    }
 +
 +    pub(crate) fn register_request(
 +        &mut self,
 +        request: &lsp_server::Request,
 +        request_received: Instant,
 +    ) {
 +        self.req_queue
 +            .incoming
 +            .register(request.id.clone(), (request.method.clone(), request_received));
 +    }
 +
 +    pub(crate) fn respond(&mut self, response: lsp_server::Response) {
 +        if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
 +            if let Some(err) = &response.error {
 +                if err.message.starts_with("server panicked") {
 +                    self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))
 +                }
 +            }
 +
 +            let duration = start.elapsed();
 +            tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
 +            self.send(response.into());
 +        }
 +    }
 +
 +    pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
 +        if let Some(response) = self.req_queue.incoming.cancel(request_id) {
 +            self.send(response.into());
 +        }
 +    }
 +
 +    fn send(&mut self, message: lsp_server::Message) {
 +        self.sender.send(message).unwrap()
 +    }
 +}
 +
 +impl Drop for GlobalState {
 +    fn drop(&mut self) {
 +        self.analysis_host.request_cancellation();
 +    }
 +}
 +
 +impl GlobalStateSnapshot {
 +    pub(crate) fn url_to_file_id(&self, url: &Url) -> Result<FileId> {
 +        url_to_file_id(&self.vfs.read().0, url)
 +    }
 +
 +    pub(crate) fn file_id_to_url(&self, id: FileId) -> Url {
 +        file_id_to_url(&self.vfs.read().0, id)
 +    }
 +
 +    pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
 +        let endings = self.vfs.read().1[&file_id];
 +        let index = self.analysis.file_line_index(file_id)?;
 +        let res = LineIndex { index, endings, encoding: self.config.offset_encoding() };
 +        Ok(res)
 +    }
 +
 +    pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
 +        let path = from_proto::vfs_path(url).ok()?;
 +        Some(self.mem_docs.get(&path)?.version)
 +    }
 +
 +    pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
 +        let mut base = self.vfs.read().0.file_path(path.anchor);
 +        base.pop();
 +        let path = base.join(&path.path).unwrap();
 +        let path = path.as_path().unwrap();
 +        url_from_abs_path(path)
 +    }
 +
 +    pub(crate) fn cargo_target_for_crate_root(
 +        &self,
 +        crate_id: CrateId,
 +    ) -> Option<(&CargoWorkspace, Target)> {
 +        let file_id = self.analysis.crate_root(crate_id).ok()?;
 +        let path = self.vfs.read().0.file_path(file_id);
 +        let path = path.as_path()?;
 +        self.workspaces.iter().find_map(|ws| match ws {
 +            ProjectWorkspace::Cargo { cargo, .. } => {
 +                cargo.target_by_root(path).map(|it| (cargo, it))
 +            }
 +            ProjectWorkspace::Json { .. } => None,
 +            ProjectWorkspace::DetachedFiles { .. } => None,
 +        })
 +    }
 +}
 +
 +pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
 +    let path = vfs.file_path(id);
 +    let path = path.as_path().unwrap();
 +    url_from_abs_path(path)
 +}
 +
 +pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> Result<FileId> {
 +    let path = from_proto::vfs_path(url)?;
 +    let res = vfs.file_id(&path).ok_or_else(|| format!("file not found: {}", path))?;
 +    Ok(res)
 +}
index 520aa7d1dd4874d5370bfaeed310d796e10cb3ae,0000000000000000000000000000000000000000..deb777c952fdf7d7658f92b77b8d50f68244499c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1892 -1,0 +1,1892 @@@
-     state.proc_macro_client = None;
 +//! 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,
 +    HoverAction, HoverGotoTypeData, Query, RangeInfo, 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_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 let Some(offset) = offset {
 +            if !runnable.nav.full_range.contains_inclusive(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)
 +}
 +
 +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 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)| {
 +                    refs.into_iter().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.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,
 +        },
 +        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.map(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()),
 +            // https://github.com/rust-lang/rust-analyzer/issues/11404
 +            message: if !d.message.is_empty() { d.message } else { " ".to_string() },
 +            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(),
 +    ))
 +}
 +
 +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 highlights = snap.analysis.highlight(file_id)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +
 +    // 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 highlights = snap.analysis.highlight(file_id)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +
 +    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(frange)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +    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 rustfmt = match snap.config.rustfmt() {
 +        RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
 +            let mut cmd = process::Command::new(toolchain::rustfmt());
 +            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.args(args);
 +            cmd
 +        }
 +    };
 +
 +    let mut rustfmt = rustfmt
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .context(format!("Failed to spawn {:?}", rustfmt))?;
 +
 +    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::info!("rustfmt exited with status 1, assuming parse error and ignoring");
 +                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 77125f88f473d1907e50d78966d574250f8f7461,0000000000000000000000000000000000000000..9ae361b034e28959043b1fbd2a40298fb86a7146
mode 100644,000000..100644
--- /dev/null
@@@ -1,664 -1,0 +1,701 @@@
-         if self.proc_macro_client.is_none() {
 +//! 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(),
 +                            )
 +                        }
 +                    })
 +                    .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(
 +                "rust-analyzer 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: _,
 +                } => 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);
 +
-                 match ProcMacroServer::spawn(path.clone(), args) {
-                     Ok(it) => self.proc_macro_client = Some(it),
-                     Err(err) => {
-                         tracing::error!(
-                             "Failed to run proc_macro_srv from path {}, error: {:?}",
++        if self.proc_macro_clients.is_empty() {
 +            if let Some((path, args)) = self.config.proc_macro_srv() {
-                             err
++                self.proc_macro_clients = self
++                    .workspaces
++                    .iter()
++                    .map(|ws| {
++                        let mut args = args.clone();
++                        let mut path = path.clone();
++
++                        if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
++                            tracing::info!("Found a cargo workspace...");
++                            if let Some(sysroot) = sysroot.as_ref() {
++                                tracing::info!("Found a cargo workspace with a sysroot...");
++                                let server_path = sysroot
++                                    .root()
++                                    .join("libexec")
++                                    .join("rust-analyzer-proc-macro-srv");
++                                if std::fs::metadata(&server_path).is_ok() {
++                                    tracing::info!(
++                                        "And the server exists at {}",
++                                        server_path.display()
++                                    );
++                                    path = server_path;
++                                    args = vec![];
++                                } else {
++                                    tracing::info!(
++                                        "And the server does not exist at {}",
++                                        server_path.display()
++                                    );
++                                }
++                            }
++                        }
++
++                        tracing::info!(
++                            "Using proc-macro server at {} with args {:?}",
 +                            path.display(),
-                     }
-                 }
++                            args
 +                        );
-             let proc_macro_client = self.proc_macro_client.as_ref();
++                        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
++                            let error = format!(
++                                "Failed to run proc_macro_srv 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 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(),
-                 )
-             };
 +            let dummy_replacements = self.config.dummy_replacements();
-             for ws in self.workspaces.iter() {
 +
 +            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();
-     server: Option<&ProcMacroServer>,
++            for (idx, ws) in self.workspaces.iter().enumerate() {
++                let proc_macro_client = self.proc_macro_clients[idx].as_ref();
++                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));
 +            }
 +            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();
 +                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(
-         let server = server.ok_or_else(|| format!("Proc-macro server not started"))?;
++    server: Result<&ProcMacroServer, &String>,
 +    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) {
 +                Arc::new(DummyExpander)
 +            } 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 proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct DummyExpander;
 +
 +    impl ProcMacroExpander for DummyExpander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(subtree.clone())
 +        }
 +    }
 +}
 +
 +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 = path.file_name().unwrap_or_default();
 +
 +    if file_name == "Cargo.toml" || file_name == "Cargo.lock" {
 +        return true;
 +    }
 +    if change_kind == ChangeKind::Modify {
 +        return false;
 +    }
 +    if path.extension().unwrap_or_default() != "rs" {
 +        if (file_name == "config.toml" || file_name == "config")
 +            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true)
 +        {
 +            return true;
 +        }
 +        return false;
 +    }
 +    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 5fb945ea98727c50875ae87fabba8b9297a45ac9,0000000000000000000000000000000000000000..6c78b5df1a7050472d9cacb304bb799792aa4ee0
mode 100644,000000..100644
--- /dev/null
@@@ -1,300 -1,0 +1,301 @@@
 +//! Semantic Tokens helpers
 +
 +use std::ops;
 +
 +use lsp_types::{
 +    Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens,
 +    SemanticTokensEdit,
 +};
 +
 +macro_rules! define_semantic_token_types {
 +    ($(($ident:ident, $string:literal)),*$(,)?) => {
 +        $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*
 +
 +        pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
 +            SemanticTokenType::COMMENT,
 +            SemanticTokenType::KEYWORD,
 +            SemanticTokenType::STRING,
 +            SemanticTokenType::NUMBER,
 +            SemanticTokenType::REGEXP,
 +            SemanticTokenType::OPERATOR,
 +            SemanticTokenType::NAMESPACE,
 +            SemanticTokenType::TYPE,
 +            SemanticTokenType::STRUCT,
 +            SemanticTokenType::CLASS,
 +            SemanticTokenType::INTERFACE,
 +            SemanticTokenType::ENUM,
 +            SemanticTokenType::ENUM_MEMBER,
 +            SemanticTokenType::TYPE_PARAMETER,
 +            SemanticTokenType::FUNCTION,
 +            SemanticTokenType::METHOD,
 +            SemanticTokenType::PROPERTY,
 +            SemanticTokenType::MACRO,
 +            SemanticTokenType::VARIABLE,
 +            SemanticTokenType::PARAMETER,
 +            $($ident),*
 +        ];
 +    };
 +}
 +
 +define_semantic_token_types![
 +    (ANGLE, "angle"),
 +    (ARITHMETIC, "arithmetic"),
 +    (ATTRIBUTE, "attribute"),
 +    (ATTRIBUTE_BRACKET, "attributeBracket"),
 +    (BITWISE, "bitwise"),
 +    (BOOLEAN, "boolean"),
 +    (BRACE, "brace"),
 +    (BRACKET, "bracket"),
 +    (BUILTIN_ATTRIBUTE, "builtinAttribute"),
 +    (BUILTIN_TYPE, "builtinType"),
 +    (CHAR, "character"),
 +    (COLON, "colon"),
 +    (COMMA, "comma"),
 +    (COMPARISON, "comparison"),
 +    (CONST_PARAMETER, "constParameter"),
 +    (DERIVE, "derive"),
++    (DERIVE_HELPER, "deriveHelper"),
 +    (DOT, "dot"),
 +    (ESCAPE_SEQUENCE, "escapeSequence"),
 +    (FORMAT_SPECIFIER, "formatSpecifier"),
 +    (GENERIC, "generic"),
 +    (LABEL, "label"),
 +    (LIFETIME, "lifetime"),
 +    (LOGICAL, "logical"),
 +    (MACRO_BANG, "macroBang"),
 +    (OPERATOR, "operator"),
 +    (PARENTHESIS, "parenthesis"),
 +    (PUNCTUATION, "punctuation"),
 +    (SELF_KEYWORD, "selfKeyword"),
 +    (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
 +    (SEMICOLON, "semicolon"),
 +    (TYPE_ALIAS, "typeAlias"),
 +    (TOOL_MODULE, "toolModule"),
 +    (UNION, "union"),
 +    (UNRESOLVED_REFERENCE, "unresolvedReference"),
 +];
 +
 +macro_rules! define_semantic_token_modifiers {
 +    ($(($ident:ident, $string:literal)),*$(,)?) => {
 +        $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
 +
 +        pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
 +            SemanticTokenModifier::DOCUMENTATION,
 +            SemanticTokenModifier::DECLARATION,
 +            SemanticTokenModifier::DEFINITION,
 +            SemanticTokenModifier::STATIC,
 +            SemanticTokenModifier::ABSTRACT,
 +            SemanticTokenModifier::DEPRECATED,
 +            SemanticTokenModifier::READONLY,
 +            SemanticTokenModifier::DEFAULT_LIBRARY,
 +            $($ident),*
 +        ];
 +    };
 +}
 +
 +define_semantic_token_modifiers![
 +    (ASYNC, "async"),
 +    (ATTRIBUTE_MODIFIER, "attribute"),
 +    (CALLABLE, "callable"),
 +    (CONSTANT, "constant"),
 +    (CONSUMING, "consuming"),
 +    (CONTROL_FLOW, "controlFlow"),
 +    (CRATE_ROOT, "crateRoot"),
 +    (INJECTED, "injected"),
 +    (INTRA_DOC_LINK, "intraDocLink"),
 +    (LIBRARY, "library"),
 +    (MUTABLE, "mutable"),
 +    (PUBLIC, "public"),
 +    (REFERENCE, "reference"),
 +    (TRAIT_MODIFIER, "trait"),
 +    (UNSAFE, "unsafe"),
 +];
 +
 +#[derive(Default)]
 +pub(crate) struct ModifierSet(pub(crate) u32);
 +
 +impl ops::BitOrAssign<SemanticTokenModifier> for ModifierSet {
 +    fn bitor_assign(&mut self, rhs: SemanticTokenModifier) {
 +        let idx = SUPPORTED_MODIFIERS.iter().position(|it| it == &rhs).unwrap();
 +        self.0 |= 1 << idx;
 +    }
 +}
 +
 +/// Tokens are encoded relative to each other.
 +///
 +/// This is a direct port of <https://github.com/microsoft/vscode-languageserver-node/blob/f425af9de46a0187adb78ec8a46b9b2ce80c5412/server/src/sematicTokens.proposed.ts#L45>
 +pub(crate) struct SemanticTokensBuilder {
 +    id: String,
 +    prev_line: u32,
 +    prev_char: u32,
 +    data: Vec<SemanticToken>,
 +}
 +
 +impl SemanticTokensBuilder {
 +    pub(crate) fn new(id: String) -> Self {
 +        SemanticTokensBuilder { id, prev_line: 0, prev_char: 0, data: Default::default() }
 +    }
 +
 +    /// Push a new token onto the builder
 +    pub(crate) fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) {
 +        let mut push_line = range.start.line as u32;
 +        let mut push_char = range.start.character as u32;
 +
 +        if !self.data.is_empty() {
 +            push_line -= self.prev_line;
 +            if push_line == 0 {
 +                push_char -= self.prev_char;
 +            }
 +        }
 +
 +        // A token cannot be multiline
 +        let token_len = range.end.character - range.start.character;
 +
 +        let token = SemanticToken {
 +            delta_line: push_line,
 +            delta_start: push_char,
 +            length: token_len as u32,
 +            token_type: token_index,
 +            token_modifiers_bitset: modifier_bitset,
 +        };
 +
 +        self.data.push(token);
 +
 +        self.prev_line = range.start.line as u32;
 +        self.prev_char = range.start.character as u32;
 +    }
 +
 +    pub(crate) fn build(self) -> SemanticTokens {
 +        SemanticTokens { result_id: Some(self.id), data: self.data }
 +    }
 +}
 +
 +pub(crate) fn diff_tokens(old: &[SemanticToken], new: &[SemanticToken]) -> Vec<SemanticTokensEdit> {
 +    let offset = new.iter().zip(old.iter()).take_while(|&(n, p)| n == p).count();
 +
 +    let (_, old) = old.split_at(offset);
 +    let (_, new) = new.split_at(offset);
 +
 +    let offset_from_end =
 +        new.iter().rev().zip(old.iter().rev()).take_while(|&(n, p)| n == p).count();
 +
 +    let (old, _) = old.split_at(old.len() - offset_from_end);
 +    let (new, _) = new.split_at(new.len() - offset_from_end);
 +
 +    if old.is_empty() && new.is_empty() {
 +        vec![]
 +    } else {
 +        // The lsp data field is actually a byte-diff but we
 +        // travel in tokens so `start` and `delete_count` are in multiples of the
 +        // serialized size of `SemanticToken`.
 +        vec![SemanticTokensEdit {
 +            start: 5 * offset as u32,
 +            delete_count: 5 * old.len() as u32,
 +            data: Some(new.into()),
 +        }]
 +    }
 +}
 +
 +pub(crate) fn type_index(ty: SemanticTokenType) -> u32 {
 +    SUPPORTED_TYPES.iter().position(|it| *it == ty).unwrap() as u32
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    fn from(t: (u32, u32, u32, u32, u32)) -> SemanticToken {
 +        SemanticToken {
 +            delta_line: t.0,
 +            delta_start: t.1,
 +            length: t.2,
 +            token_type: t.3,
 +            token_modifiers_bitset: t.4,
 +        }
 +    }
 +
 +    #[test]
 +    fn test_diff_insert_at_end() {
 +        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(
 +            edits[0],
 +            SemanticTokensEdit {
 +                start: 10,
 +                delete_count: 0,
 +                data: Some(vec![from((11, 12, 13, 14, 15))])
 +            }
 +        );
 +    }
 +
 +    #[test]
 +    fn test_diff_insert_at_beginning() {
 +        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +        let after = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(
 +            edits[0],
 +            SemanticTokensEdit {
 +                start: 0,
 +                delete_count: 0,
 +                data: Some(vec![from((11, 12, 13, 14, 15))])
 +            }
 +        );
 +    }
 +
 +    #[test]
 +    fn test_diff_insert_in_middle() {
 +        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +        let after = [
 +            from((1, 2, 3, 4, 5)),
 +            from((10, 20, 30, 40, 50)),
 +            from((60, 70, 80, 90, 100)),
 +            from((6, 7, 8, 9, 10)),
 +        ];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(
 +            edits[0],
 +            SemanticTokensEdit {
 +                start: 5,
 +                delete_count: 0,
 +                data: Some(vec![from((10, 20, 30, 40, 50)), from((60, 70, 80, 90, 100))])
 +            }
 +        );
 +    }
 +
 +    #[test]
 +    fn test_diff_remove_from_end() {
 +        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];
 +        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(edits[0], SemanticTokensEdit { start: 10, delete_count: 5, data: Some(vec![]) });
 +    }
 +
 +    #[test]
 +    fn test_diff_remove_from_beginning() {
 +        let before = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(edits[0], SemanticTokensEdit { start: 0, delete_count: 5, data: Some(vec![]) });
 +    }
 +
 +    #[test]
 +    fn test_diff_remove_from_middle() {
 +        let before = [
 +            from((1, 2, 3, 4, 5)),
 +            from((10, 20, 30, 40, 50)),
 +            from((60, 70, 80, 90, 100)),
 +            from((6, 7, 8, 9, 10)),
 +        ];
 +        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
 +
 +        let edits = diff_tokens(&before, &after);
 +        assert_eq!(edits[0], SemanticTokensEdit { start: 5, delete_count: 10, data: Some(vec![]) });
 +    }
 +}
index 9c8e618b6ed05cf5fa009f7e7ad8ee5dd18486b0,0000000000000000000000000000000000000000..7f4fa57fa1e095f2138d6924815c9a7643a3c82b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1394 -1,0 +1,1397 @@@
-         | SymbolKind::Derive => lsp_types::SymbolKind::FUNCTION,
 +//! 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,
 +    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,
 +) -> lsp_types::DocumentHighlightKind {
 +    match category {
 +        ReferenceCategory::Read => lsp_types::DocumentHighlightKind::READ,
 +        ReferenceCategory::Write => lsp_types::DocumentHighlightKind::WRITE,
 +    }
 +}
 +
 +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,
 +    inlay_hint: InlayHint,
 +) -> lsp_types::InlayHint {
 +    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 != "&",
 +            InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
 +        }),
 +        label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
 +            InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
 +            InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
 +            InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label),
 +            _ => inlay_hint.label.clone(),
 +        }),
 +        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),
 +        }),
 +    }
 +}
 +
 +static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
 +
 +pub(crate) fn semantic_tokens(
 +    text: &str,
 +    line_index: &LineIndex,
 +    highlights: Vec<HlRange>,
 +    highlight_strings: bool,
 +) -> 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);
 +        if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING {
 +            continue;
 +        }
 +        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::ATTRIBUTE,
 +            SymbolKind::Derive => semantic_tokens::DERIVE,
++            SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER,
 +            SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
 +            SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
 +            SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
 +            SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
 +            SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
 +            SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
 +            SymbolKind::Label => semantic_tokens::LABEL,
 +            SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
 +            SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
 +            SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
 +            SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
 +            SymbolKind::Function => {
 +                if highlight.mods.contains(HlMod::Associated) {
 +                    lsp_types::SemanticTokenType::METHOD
 +                } else {
 +                    lsp_types::SemanticTokenType::FUNCTION
 +                }
 +            }
 +            SymbolKind::Const => {
 +                mods |= semantic_tokens::CONSTANT;
 +                mods |= lsp_types::SemanticTokenModifier::STATIC;
 +                lsp_types::SemanticTokenType::VARIABLE
 +            }
 +            SymbolKind::Static => {
 +                mods |= lsp_types::SemanticTokenModifier::STATIC;
 +                lsp_types::SemanticTokenType::VARIABLE
 +            }
 +            SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT,
 +            SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM,
 +            SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER,
 +            SymbolKind::Union => semantic_tokens::UNION,
 +            SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS,
 +            SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
 +            SymbolKind::Macro => lsp_types::SemanticTokenType::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 => lsp_types::SemanticTokenType::NUMBER,
 +        HlTag::CharLiteral => semantic_tokens::CHAR,
 +        HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
 +        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
 +        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
 +        HlTag::Keyword => lsp_types::SemanticTokenType::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 => lsp_types::SemanticTokenType::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 => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY,
 +            HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION,
 +            HlMod::Documentation => lsp_types::SemanticTokenModifier::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 => lsp_types::SemanticTokenModifier::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::{convert::TryInto, 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");
 +    }
 +}