about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-23 17:11:16 +0000
committerbors <bors@rust-lang.org>2024-06-23 17:11:16 +0000
commit33422e72c8a66bdb5ee21246a948a1a02ca91674 (patch)
treec1c0a241bdaef5d0ad75b0b556fe5f168bc7377b
parentaabbf84b45a5e7b868c33e959d7e5cc985097d19 (diff)
parent70e9582f4c076a6b22ba4844f075762a1ed2296b (diff)
downloadrust-33422e72c8a66bdb5ee21246a948a1a02ca91674.tar.gz
rust-33422e72c8a66bdb5ee21246a948a1a02ca91674.zip
Auto merge of #126865 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer`

r? `@ghost`
-rw-r--r--src/tools/rust-analyzer/.cargo/config.toml1
-rw-r--r--src/tools/rust-analyzer/Cargo.lock15
-rw-r--r--src/tools/rust-analyzer/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/change.rs2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs61
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs52
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs313
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs105
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs159
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/eager.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs151
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs (renamed from src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs)9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs127
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/quote.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs97
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs263
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs308
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs297
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs296
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs75
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs134
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs283
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs362
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs41
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs51
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs145
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs89
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/helpers.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs54
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/extend_selection.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/interpret_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs48
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs2
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs116
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/parser.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/shortcuts.rs2
-rw-r--r--src/tools/rust-analyzer/crates/paths/src/lib.rs22
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs3
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs180
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs1461
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs52
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs169
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs237
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs41
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs184
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs84
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs100
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs)110
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs947
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs35
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs21
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs20
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/interned.rs37
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/cycles.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs8
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs2
-rw-r--r--src/tools/rust-analyzer/crates/span/src/hygiene.rs2
-rw-r--r--src/tools/rust-analyzer/crates/span/src/lib.rs13
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/anymap.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/algo.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs48
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/parsing.rs17
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs8
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs3
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md2
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md15
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc2
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc4
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json14
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json3630
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ast_inspector.ts3
-rw-r--r--src/tools/rust-analyzer/editors/code/src/bootstrap.ts76
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts91
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts50
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts62
-rw-r--r--src/tools/rust-analyzer/editors/code/src/debug.ts43
-rw-r--r--src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts2
-rw-r--r--src/tools/rust-analyzer/editors/code/src/diagnostics.ts2
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts36
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts13
-rw-r--r--src/tools/rust-analyzer/editors/code/src/nullable.ts19
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts90
-rw-r--r--src/tools/rust-analyzer/editors/code/src/snippets.ts3
-rw-r--r--src/tools/rust-analyzer/editors/code/src/tasks.ts100
-rw-r--r--src/tools/rust-analyzer/editors/code/src/toolchain.ts7
-rw-r--r--src/tools/rust-analyzer/editors/code/src/undefinable.ts19
-rw-r--r--src/tools/rust-analyzer/editors/code/src/util.ts67
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts4
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/dist.rs4
-rw-r--r--src/tools/rust-analyzer/xtask/src/metrics.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/src/publish.rs9
284 files changed, 8836 insertions, 4787 deletions
diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml
index 070560dfbc3..0193a9566e2 100644
--- a/src/tools/rust-analyzer/.cargo/config.toml
+++ b/src/tools/rust-analyzer/.cargo/config.toml
@@ -4,6 +4,7 @@ tq = "test -- -q"
 qt = "tq"
 lint = "clippy --all-targets -- --cap-lints warn"
 codegen = "run --package xtask --bin xtask -- codegen"
+dist = "run --package xtask --bin xtask -- dist"
 
 [target.x86_64-pc-windows-msvc]
 linker = "rust-lld"
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 3558c39bb32..57d43dad3fd 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -329,6 +329,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
 name = "dirs-sys"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -503,6 +512,7 @@ dependencies = [
  "hir-def",
  "hir-expand",
  "hir-ty",
+ "intern",
  "itertools",
  "once_cell",
  "rustc-hash",
@@ -891,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libloading"
@@ -1665,6 +1675,7 @@ dependencies = [
  "anyhow",
  "cfg",
  "crossbeam-channel",
+ "dirs",
  "dissimilar",
  "expect-test",
  "flycheck",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index ccc27e21333..583c7bbe338 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -162,7 +162,11 @@ xshell = "0.2.5"
 dashmap = { version = "=5.5.3", features = ["raw-api"] }
 
 [workspace.lints.rust]
-rust_2018_idioms = "warn"
+bare_trait_objects = "warn"
+elided_lifetimes_in_paths = "warn"
+ellipsis_inclusive_range_patterns = "warn"
+explicit_outlives_requirements = "warn"
+unused_extern_crates = "warn"
 unused_lifetimes = "warn"
 unreachable_pub = "warn"
 semicolon_in_expressions_from_macros = "warn"
diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs
index 927b2108a6c..0fd54e1211c 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/change.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs
@@ -51,7 +51,7 @@ impl FileChange {
     }
 
     pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
-        let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered();
+        let _p = tracing::info_span!("FileChange::apply").entered();
         if let Some(roots) = self.roots {
             for (idx, root) in roots.into_iter().enumerate() {
                 let root_id = SourceRootId(idx as u32);
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index b2c3f38ab4f..1d172ab9e40 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -412,7 +412,7 @@ impl CrateGraph {
         from: CrateId,
         dep: Dependency,
     ) -> Result<(), CyclicDependenciesError> {
-        let _p = tracing::span!(tracing::Level::INFO, "add_dep").entered();
+        let _p = tracing::info_span!("add_dep").entered();
 
         self.check_cycle_after_dependency(from, dep.crate_id)?;
 
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 2c13eed56c3..f5165ea8a7b 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -85,7 +85,7 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option<ReleaseC
 }
 
 fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
-    let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered();
+    let _p = tracing::info_span!("parse", ?file_id).entered();
     let text = db.file_text(file_id);
     // FIXME: Edition based parsing
     SourceFile::parse(&text, span::Edition::CURRENT)
@@ -187,7 +187,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
     }
 
     fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
-        let _p = tracing::span!(tracing::Level::INFO, "relevant_crates").entered();
+        let _p = tracing::info_span!("relevant_crates").entered();
         let source_root = self.0.file_source_root(file_id);
         self.0.source_root_crates(source_root)
     }
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index afdc3e389b3..4584400e66f 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -304,7 +304,7 @@ impl FlycheckActor {
                             Some(c) => c,
                             None => continue,
                         };
-                    let formatted_command = format!("{:?}", command);
+                    let formatted_command = format!("{command:?}");
 
                     tracing::debug!(?command, "will restart flycheck");
                     let (sender, receiver) = unbounded();
@@ -318,8 +318,7 @@ impl FlycheckActor {
                         }
                         Err(error) => {
                             self.report_progress(Progress::DidFailToRestart(format!(
-                                "Failed to run the following command: {} error={}",
-                                formatted_command, error
+                                "Failed to run the following command: {formatted_command} error={error}"
                             )));
                             self.status = FlycheckStatus::Finished;
                         }
@@ -331,7 +330,7 @@ impl FlycheckActor {
                     // Watcher finished
                     let command_handle = self.command_handle.take().unwrap();
                     self.command_receiver.take();
-                    let formatted_handle = format!("{:?}", command_handle);
+                    let formatted_handle = format!("{command_handle:?}");
 
                     let res = command_handle.join();
                     if let Err(error) = &res {
@@ -387,6 +386,7 @@ impl FlycheckActor {
                 "did  cancel flycheck"
             );
             command_handle.cancel();
+            self.command_receiver.take();
             self.report_progress(Progress::DidCancel);
             self.status = FlycheckStatus::Finished;
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index d9eeffd7983..184dab8367c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -1,10 +1,5 @@
 //! A higher level attributes based on TokenTree, with also some shortcuts.
 
-pub mod builtin;
-
-#[cfg(test)]
-mod tests;
-
 use std::{borrow::Cow, hash::Hash, ops, slice::Iter as SliceIter};
 
 use base_db::CrateId;
@@ -75,7 +70,7 @@ impl Attrs {
         db: &dyn DefDatabase,
         v: VariantId,
     ) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
-        let _p = tracing::span!(tracing::Level::INFO, "fields_attrs_query").entered();
+        let _p = tracing::info_span!("fields_attrs_query").entered();
         // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
         let mut res = ArenaMap::default();
 
@@ -326,7 +321,7 @@ impl AttrsWithOwner {
     }
 
     pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
-        let _p = tracing::span!(tracing::Level::INFO, "attrs_query").entered();
+        let _p = tracing::info_span!("attrs_query").entered();
         // FIXME: this should use `Trace` to avoid duplication in `source_map` below
         let raw_attrs = match def {
             AttrDefId::ModuleId(module) => {
@@ -646,3 +641,55 @@ pub(crate) fn fields_attrs_source_map(
 
     Arc::new(res)
 }
+
+#[cfg(test)]
+mod tests {
+    //! This module contains tests for doc-expression parsing.
+    //! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`.
+
+    use triomphe::Arc;
+
+    use base_db::FileId;
+    use hir_expand::span_map::{RealSpanMap, SpanMap};
+    use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
+    use syntax::{ast, AstNode, TextRange};
+
+    use crate::attr::{DocAtom, DocExpr};
+
+    fn assert_parse_result(input: &str, expected: DocExpr) {
+        let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap();
+        let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
+        let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0))));
+        let tt = syntax_node_to_token_tree(
+            tt.syntax(),
+            map.as_ref(),
+            map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::ProcMacro,
+        );
+        let cfg = DocExpr::parse(&tt);
+        assert_eq!(cfg, expected);
+    }
+
+    #[test]
+    fn test_doc_expr_parser() {
+        assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into());
+
+        assert_parse_result(
+            r#"#![doc(alias = "foo")]"#,
+            DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(),
+        );
+
+        assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into()));
+        assert_parse_result(
+            r#"#![doc(alias("foo", "bar", "baz"))]"#,
+            DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()),
+        );
+
+        assert_parse_result(
+            r#"
+        #[doc(alias("Bar", "Qux"))]
+        struct Foo;"#,
+            DocExpr::Alias(["Bar".into(), "Qux".into()].into()),
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
deleted file mode 100644
index 727f4429802..00000000000
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-//! This module contains tests for doc-expression parsing.
-//! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`.
-
-use triomphe::Arc;
-
-use base_db::FileId;
-use hir_expand::span_map::{RealSpanMap, SpanMap};
-use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
-use syntax::{ast, AstNode, TextRange};
-
-use crate::attr::{DocAtom, DocExpr};
-
-fn assert_parse_result(input: &str, expected: DocExpr) {
-    let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap();
-    let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0))));
-    let tt = syntax_node_to_token_tree(
-        tt.syntax(),
-        map.as_ref(),
-        map.span_for_range(TextRange::empty(0.into())),
-        DocCommentDesugarMode::ProcMacro,
-    );
-    let cfg = DocExpr::parse(&tt);
-    assert_eq!(cfg, expected);
-}
-
-#[test]
-fn test_doc_expr_parser() {
-    assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into());
-
-    assert_parse_result(
-        r#"#![doc(alias = "foo")]"#,
-        DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(),
-    );
-
-    assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into()));
-    assert_parse_result(
-        r#"#![doc(alias("foo", "bar", "baz"))]"#,
-        DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()),
-    );
-
-    assert_parse_result(
-        r#"
-        #[doc(alias("Bar", "Qux"))]
-        struct Foo;"#,
-        DocExpr::Alias(["Bar".into(), "Qux".into()].into()),
-    );
-}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index d2f4d7b7e56..ca4a3f5217c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -124,7 +124,7 @@ impl Body {
         db: &dyn DefDatabase,
         def: DefWithBodyId,
     ) -> (Arc<Body>, Arc<BodySourceMap>) {
-        let _p = tracing::span!(tracing::Level::INFO, "body_with_source_map_query").entered();
+        let _p = tracing::info_span!("body_with_source_map_query").entered();
         let mut params = None;
 
         let mut is_async_fn = false;
@@ -395,6 +395,12 @@ impl BodySourceMap {
         self.expr_map.get(&src).copied()
     }
 
+    pub fn expansions(
+        &self,
+    ) -> impl Iterator<Item = (&InFile<AstPtr<ast::MacroCall>>, &MacroFileId)> {
+        self.expansions.iter()
+    }
+
     pub fn implicit_format_args(
         &self,
         node: InFile<&ast::FormatArgsExpr>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index c6d9ba6cfe4..faba9050fc4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -12,6 +12,7 @@ use intern::Interned;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::AstIdMap;
+use stdx::never;
 use syntax::{
     ast::{
         self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName,
@@ -480,7 +481,8 @@ impl ExprCollector<'_> {
                     } else if e.const_token().is_some() {
                         Mutability::Shared
                     } else {
-                        unreachable!("parser only remaps to raw_token() if matching mutability token follows")
+                        never!("parser only remaps to raw_token() if matching mutability token follows");
+                        Mutability::Shared
                     }
                 } else {
                     Mutability::from_mutable(e.mut_token().is_some())
@@ -963,7 +965,7 @@ impl ExprCollector<'_> {
                     .resolve_path(
                         self.db,
                         module,
-                        &path,
+                        path,
                         crate::item_scope::BuiltinShadowMode::Other,
                         Some(MacroSubNs::Bang),
                     )
@@ -1006,9 +1008,9 @@ impl ExprCollector<'_> {
             Some((mark, expansion)) => {
                 // Keep collecting even with expansion errors so we can provide completions and
                 // other services in incomplete macro expressions.
-                self.source_map
-                    .expansions
-                    .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap());
+                if let Some(macro_file) = self.expander.current_file_id().macro_file() {
+                    self.source_map.expansions.insert(macro_call_ptr, macro_file);
+                }
                 let prev_ast_id_map = mem::replace(
                     &mut self.ast_id_map,
                     self.db.ast_id_map(self.expander.current_file_id()),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index cbb5ca887f4..c48d16d0530 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -48,21 +48,30 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
     let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
-        let params = &db.function_data(it).params;
-        let mut params = params.iter();
+        let function_data = &db.function_data(it);
+        let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
         if let Some(self_param) = body.self_param {
             p.print_binding(self_param);
-            p.buf.push(':');
+            p.buf.push_str(": ");
             if let Some(ty) = params.next() {
                 p.print_type_ref(ty);
+                p.buf.push_str(", ");
             }
         }
         body.params.iter().zip(params).for_each(|(&param, ty)| {
             p.print_pat(param);
-            p.buf.push(':');
+            p.buf.push_str(": ");
             p.print_type_ref(ty);
+            p.buf.push_str(", ");
         });
+        // remove the last ", " in param list
+        if body.params.len() > 0 {
+            p.buf.truncate(p.buf.len() - 2);
+        }
         p.buf.push(')');
+        // return type
+        p.buf.push_str(" -> ");
+        p.print_type_ref(ret_type);
         p.buf.push(' ');
     }
     p.print_expr(body.body_expr);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index e8b26d53734..0011d3a20c2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -156,7 +156,7 @@ fn main() {
     );
 
     expect![[r#"
-        fn main() {
+        fn main() -> () {
             let are = "are";
             let count = 10;
             builtin#lang(Arguments::new_v1_formatted)(
@@ -258,7 +258,7 @@ impl SsrError {
 
     assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]);
     expect![[r#"
-        fn main() {
+        fn main() -> () {
             _ = $crate::error::SsrError::new(
                 builtin#lang(Arguments::new_v1_formatted)(
                     &[
@@ -303,7 +303,7 @@ macro_rules! m {
     };
 }
 
-fn f() {
+fn f(a: i32, b: u32) -> String {
     m!();
 }
 "#,
@@ -317,7 +317,7 @@ fn f() {
     }
 
     expect![[r#"
-        fn f() {
+        fn f(a: i32, b: u32) -> String {
             {
                 $crate::panicking::panic_fmt(
                     builtin#lang(Arguments::new_v1_formatted)(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index 0b41984bdd8..106109eb184 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -6,7 +6,7 @@
 
 use either::Either;
 use hir_expand::{attrs::collect_attrs, HirFileId};
-use syntax::ast;
+use syntax::{ast, AstPtr};
 
 use crate::{
     db::DefDatabase,
@@ -38,7 +38,7 @@ impl ChildBySource for TraitId {
 
         data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
-                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id);
+                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id);
             },
         );
         data.items.iter().for_each(|&(_, item)| {
@@ -50,9 +50,10 @@ impl ChildBySource for TraitId {
 impl ChildBySource for ImplId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let data = db.impl_data(*self);
+        // FIXME: Macro calls
         data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
-                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id);
+                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id);
             },
         );
         data.items.iter().for_each(|&item| {
@@ -80,7 +81,7 @@ impl ChildBySource for ItemScope {
             .for_each(|konst| insert_item_loc(db, res, file_id, konst, keys::CONST));
         self.attr_macro_invocs().filter(|(id, _)| id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
-                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id);
+                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id);
             },
         );
         self.legacy_macros().for_each(|(_, ids)| {
@@ -88,7 +89,7 @@ impl ChildBySource for ItemScope {
                 if let MacroId::MacroRulesId(id) = id {
                     let loc = id.lookup(db);
                     if loc.id.file_id() == file_id {
-                        res[keys::MACRO_RULES].insert(loc.source(db).value, id);
+                        res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id);
                     }
                 }
             })
@@ -100,12 +101,18 @@ impl ChildBySource for ItemScope {
                     if let Some((_, Either::Left(attr))) =
                         collect_attrs(&adt).nth(attr_id.ast_index())
                     {
-                        res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into()));
+                        res[keys::DERIVE_MACRO_CALL]
+                            .insert(AstPtr::new(&attr), (attr_id, call_id, calls.into()));
                     }
                 });
             },
         );
-
+        self.iter_macro_invoc().filter(|(id, _)| id.file_id == file_id).for_each(
+            |(ast_id, &call)| {
+                let ast = ast_id.to_ptr(db.upcast());
+                res[keys::MACRO_CALL].insert(ast, call);
+            },
+        );
         fn add_module_def(
             db: &dyn DefDatabase,
             map: &mut DynMap,
@@ -155,8 +162,8 @@ impl ChildBySource for VariantId {
         for (local_id, source) in arena_map.value.iter() {
             let id = FieldId { parent, local_id };
             match source.clone() {
-                Either::Left(source) => res[keys::TUPLE_FIELD].insert(source, id),
-                Either::Right(source) => res[keys::RECORD_FIELD].insert(source, id),
+                Either::Left(source) => res[keys::TUPLE_FIELD].insert(AstPtr::new(&source), id),
+                Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id),
             }
         }
     }
@@ -171,29 +178,30 @@ impl ChildBySource for EnumId {
 
         let tree = loc.id.item_tree(db);
         let ast_id_map = db.ast_id_map(loc.id.file_id());
-        let root = db.parse_or_expand(loc.id.file_id());
 
         db.enum_data(*self).variants.iter().for_each(|&(variant, _)| {
-            res[keys::ENUM_VARIANT].insert(
-                ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root),
-                variant,
-            );
+            res[keys::ENUM_VARIANT]
+                .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
         });
     }
 }
 
 impl ChildBySource for DefWithBodyId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
-        let body = db.body(*self);
+        let (body, sm) = db.body_with_source_map(*self);
         if let &DefWithBodyId::VariantId(v) = self {
             VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
         }
 
+        sm.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each(|(ast, &exp_id)| {
+            res[keys::MACRO_CALL].insert(ast.value, exp_id.macro_call_id);
+        });
+
         for (block, def_map) in body.blocks(db) {
             // All block expressions are merged into the same map, because they logically all add
             // inner items to the containing `DefWithBodyId`.
             def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id);
-            res[keys::BLOCK].insert(block.lookup(db).ast_id.to_node(db.upcast()), block);
+            res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db.upcast()), block);
         }
     }
 }
@@ -220,13 +228,17 @@ impl ChildBySource for GenericDefId {
             {
                 let id = TypeOrConstParamId { parent: *self, local_id };
                 match ast_param {
-                    ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id),
-                    ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id),
+                    ast::TypeOrConstParam::Type(a) => {
+                        res[keys::TYPE_PARAM].insert(AstPtr::new(&a), id)
+                    }
+                    ast::TypeOrConstParam::Const(a) => {
+                        res[keys::CONST_PARAM].insert(AstPtr::new(&a), id)
+                    }
                 }
             }
             for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
                 let id = LifetimeParamId { parent: *self, local_id };
-                res[keys::LIFETIME_PARAM].insert(ast_param, id);
+                res[keys::LIFETIME_PARAM].insert(AstPtr::new(&ast_param), id);
             }
         }
     }
@@ -246,7 +258,7 @@ fn insert_item_loc<ID, N, Data>(
 {
     let loc = id.lookup(db);
     if loc.item_tree_id().file_id() == file_id {
-        res[key].insert(loc.source(db).value, id)
+        res[key].insert(loc.ast_ptr(db).value, id)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 51a4dd6f42a..43381636721 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -340,7 +340,7 @@ impl ImplData {
         db: &dyn DefDatabase,
         id: ImplId,
     ) -> (Arc<ImplData>, DefDiagnostics) {
-        let _p = tracing::span!(tracing::Level::INFO, "impl_data_with_diagnostics_query").entered();
+        let _p = tracing::info_span!("impl_data_with_diagnostics_query").entered();
         let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
 
         let item_tree = tree_id.item_tree(db);
@@ -628,7 +628,7 @@ impl<'a> AssocItemCollector<'a> {
             '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 };
+                let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
 
                 match self.def_map.resolve_attr_macro(
                     self.db,
@@ -642,7 +642,7 @@ impl<'a> AssocItemCollector<'a> {
                             continue 'attrs;
                         }
                         let loc = self.db.lookup_intern_macro_call(call_id);
-                        if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
+                        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
@@ -719,12 +719,12 @@ impl<'a> AssocItemCollector<'a> {
                 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
                 let module = self.expander.module.local_id;
 
-                let resolver = |path| {
+                let resolver = |path: &_| {
                     self.def_map
                         .resolve_path(
                             self.db,
                             module,
-                            &path,
+                            path,
                             crate::item_scope::BuiltinShadowMode::Other,
                             Some(MacroSubNs::Bang),
                         )
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 55ecabdc38e..61fed71218e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -294,10 +294,10 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
         let in_file = InFile::new(file_id, m);
         match expander {
             MacroExpander::Declarative => MacroDefKind::Declarative(in_file),
-            MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file),
-            MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(it, in_file),
-            MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(it, in_file),
-            MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(it, in_file),
+            MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it),
+            MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it),
+            MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it),
+            MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it),
         }
     };
 
@@ -338,9 +338,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
             MacroDefId {
                 krate: loc.container.krate,
                 kind: MacroDefKind::ProcMacro(
+                    InFile::new(loc.id.file_id(), makro.ast_id),
                     loc.expander,
                     loc.kind,
-                    InFile::new(loc.id.file_id(), makro.ast_id),
                 ),
                 local_inner: false,
                 allow_internal_unsafe: false,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
index f83ab1e1a05..9d330a7bf1c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
@@ -13,7 +13,7 @@ use crate::{
     TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId,
 };
 
-pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>;
+pub type Key<K, V> = crate::dyn_map::Key<AstPtr<K>, V, AstPtrPolicy<K, V>>;
 
 pub const BLOCK: Key<ast::BlockExpr, BlockId> = Key::new();
 pub const FUNCTION: Key<ast::Fn, FunctionId> = Key::new();
@@ -39,6 +39,7 @@ pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
 pub const MACRO_RULES: Key<ast::MacroRules, MacroRulesId> = Key::new();
 pub const MACRO2: Key<ast::MacroDef, Macro2Id> = Key::new();
 pub const PROC_MACRO: Key<ast::Fn, ProcMacroId> = Key::new();
+pub const MACRO_CALL: Key<ast::MacroCall, MacroCallId> = Key::new();
 pub const ATTR_MACRO_CALL: Key<ast::Item, MacroCallId> = Key::new();
 pub const DERIVE_MACRO_CALL: Key<ast::Attr, (AttrId, MacroCallId, Box<[Option<MacroCallId>]>)> =
     Key::new();
@@ -54,18 +55,16 @@ pub struct AstPtrPolicy<AST, ID> {
 }
 
 impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> {
-    type K = AST;
+    type K = AstPtr<AST>;
     type V = ID;
-    fn insert(map: &mut DynMap, key: AST, value: ID) {
-        let key = AstPtr::new(&key);
+    fn insert(map: &mut DynMap, key: AstPtr<AST>, value: ID) {
         map.map
             .entry::<FxHashMap<AstPtr<AST>, ID>>()
             .or_insert_with(Default::default)
             .insert(key, value);
     }
-    fn get<'a>(map: &'a DynMap, key: &AST) -> Option<&'a ID> {
-        let key = AstPtr::new(key);
-        map.map.get::<FxHashMap<AstPtr<AST>, ID>>()?.get(&key)
+    fn get<'a>(map: &'a DynMap, key: &AstPtr<AST>) -> Option<&'a ID> {
+        map.map.get::<FxHashMap<AstPtr<AST>, ID>>()?.get(key)
     }
     fn is_empty(map: &DynMap) -> bool {
         map.map.get::<FxHashMap<AstPtr<AST>, ID>>().map_or(true, |it| it.is_empty())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 73ce942c580..dbf8e6b225c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -56,7 +56,7 @@ impl Expander {
         &mut self,
         db: &dyn DefDatabase,
         macro_call: ast::MacroCall,
-        resolver: impl Fn(ModPath) -> Option<MacroId>,
+        resolver: impl Fn(&ModPath) -> Option<MacroId>,
     ) -> Result<ExpandResult<Option<(Mark, Parse<T>)>>, UnresolvedMacro> {
         // FIXME: within_limit should support this, instead of us having to extract the error
         let mut unresolved_macro_err = None;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index d9495d36c0d..58a1872ef25 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1,6 +1,6 @@
 //! An algorithm to find a path to refer to a certain item.
 
-use std::{cmp::Ordering, iter};
+use std::{cell::Cell, cmp::Ordering, iter};
 
 use hir_expand::{
     name::{known, AsName, Name},
@@ -23,15 +23,40 @@ pub fn find_path(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
-    prefix_kind: PrefixKind,
+    mut prefix_kind: PrefixKind,
     ignore_local_imports: bool,
-    cfg: ImportPathConfig,
+    mut cfg: ImportPathConfig,
 ) -> Option<ModPath> {
-    let _p = tracing::span!(tracing::Level::INFO, "find_path").entered();
-    find_path_inner(FindPathCtx { db, prefix: prefix_kind, cfg, ignore_local_imports }, item, from)
+    let _p = tracing::info_span!("find_path").entered();
+
+    // - if the item is a builtin, it's in scope
+    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
+        return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name())));
+    }
+
+    // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
+    // default to plain paths.
+    if item.module(db).is_some_and(ModuleId::is_within_block) {
+        prefix_kind = PrefixKind::Plain;
+    }
+    cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
+
+    find_path_inner(
+        &FindPathCtx {
+            db,
+            prefix: prefix_kind,
+            cfg,
+            ignore_local_imports,
+            from,
+            from_def_map: &from.def_map(db),
+            fuel: Cell::new(FIND_PATH_FUEL),
+        },
+        item,
+        MAX_PATH_LEN,
+    )
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum Stability {
     Unstable,
     Stable,
@@ -46,6 +71,7 @@ fn zip_stability(a: Stability, b: Stability) -> Stability {
 }
 
 const MAX_PATH_LEN: usize = 15;
+const FIND_PATH_FUEL: usize = 10000;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum PrefixKind {
@@ -63,79 +89,54 @@ impl PrefixKind {
     #[inline]
     fn path_kind(self) -> PathKind {
         match self {
-            PrefixKind::BySelf => PathKind::Super(0),
+            PrefixKind::BySelf => PathKind::SELF,
             PrefixKind::Plain => PathKind::Plain,
             PrefixKind::ByCrate => PathKind::Crate,
         }
     }
 }
 
-#[derive(Copy, Clone)]
 struct FindPathCtx<'db> {
     db: &'db dyn DefDatabase,
     prefix: PrefixKind,
     cfg: ImportPathConfig,
     ignore_local_imports: bool,
+    from: ModuleId,
+    from_def_map: &'db DefMap,
+    fuel: Cell<usize>,
 }
 
 /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
-fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
-    // - if the item is a builtin, it's in scope
-    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
-        return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name())));
-    }
-
-    let def_map = from.def_map(ctx.db);
-    let crate_root = from.derive_crate_root();
+fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
     // - if the item is a module, jump straight to module search
     if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
         let mut visited_modules = FxHashSet::default();
-        return find_path_for_module(
-            FindPathCtx {
-                cfg: ImportPathConfig {
-                    prefer_no_std: ctx.cfg.prefer_no_std
-                        || ctx.db.crate_supports_no_std(crate_root.krate),
-                    ..ctx.cfg
-                },
-                ..ctx
-            },
-            &def_map,
-            &mut visited_modules,
-            from,
-            module_id,
-            MAX_PATH_LEN,
-        )
-        .map(|(item, _)| item);
+        return find_path_for_module(ctx, &mut visited_modules, module_id, max_len)
+            .map(|(item, _)| item);
     }
 
-    let prefix = if item.module(ctx.db).is_some_and(|it| it.is_within_block()) {
-        PrefixKind::Plain
-    } else {
-        ctx.prefix
-    };
-    let may_be_in_scope = match prefix {
+    let may_be_in_scope = match ctx.prefix {
         PrefixKind::Plain | PrefixKind::BySelf => true,
-        PrefixKind::ByCrate => from.is_crate_root(),
+        PrefixKind::ByCrate => ctx.from.is_crate_root(),
     };
     if may_be_in_scope {
         // - if the item is already in scope, return the name under which it is
-        let scope_name = find_in_scope(ctx.db, &def_map, from, item, ctx.ignore_local_imports);
+        let scope_name =
+            find_in_scope(ctx.db, ctx.from_def_map, ctx.from, item, ctx.ignore_local_imports);
         if let Some(scope_name) = scope_name {
-            return Some(ModPath::from_segments(prefix.path_kind(), iter::once(scope_name)));
+            return Some(ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)));
         }
     }
 
     // - if the item is in the prelude, return the name from there
-    if let value @ Some(_) =
-        find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from)
-    {
-        return value;
+    if let Some(value) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
+        return Some(value);
     }
 
     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
         // - if the item is an enum variant, refer to it via the enum
         if let Some(mut path) =
-            find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), from)
+            find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len)
         {
             path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
             return Some(path);
@@ -147,53 +148,32 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti
 
     let mut visited_modules = FxHashSet::default();
 
-    calculate_best_path(
-        FindPathCtx {
-            cfg: ImportPathConfig {
-                prefer_no_std: ctx.cfg.prefer_no_std
-                    || ctx.db.crate_supports_no_std(crate_root.krate),
-                ..ctx.cfg
-            },
-            ..ctx
-        },
-        &def_map,
-        &mut visited_modules,
-        MAX_PATH_LEN,
-        item,
-        from,
-    )
-    .map(|(item, _)| item)
+    calculate_best_path(ctx, &mut visited_modules, item, max_len).map(|(item, _)| item)
 }
 
 #[tracing::instrument(skip_all)]
 fn find_path_for_module(
-    ctx: FindPathCtx<'_>,
-    def_map: &DefMap,
+    ctx: &FindPathCtx<'_>,
     visited_modules: &mut FxHashSet<ModuleId>,
-    from: ModuleId,
     module_id: ModuleId,
     max_len: usize,
 ) -> Option<(ModPath, Stability)> {
-    if max_len == 0 {
-        return None;
-    }
-
-    let is_crate_root = module_id.as_crate_root();
-    // - if the item is the crate root, return `crate`
-    if is_crate_root.is_some_and(|it| it == from.derive_crate_root()) {
-        return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
-    }
+    if let Some(crate_root) = module_id.as_crate_root() {
+        if crate_root == ctx.from.derive_crate_root() {
+            // - if the item is the crate root, return `crate`
+            return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
+        }
+        // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude
 
-    let root_def_map = from.derive_crate_root().def_map(ctx.db);
-    // - if the item is the crate root of a dependency crate, return the name from the extern prelude
-    if let Some(crate_root) = is_crate_root {
+        let root_def_map = ctx.from.derive_crate_root().def_map(ctx.db);
         // rev here so we prefer looking at renamed extern decls first
         for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude().rev() {
             if crate_root != def_id {
                 continue;
             }
-            let name_already_occupied_in_type_ns = def_map
-                .with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| {
+            let name_already_occupied_in_type_ns = ctx
+                .from_def_map
+                .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| {
                     def_map[local_id]
                         .scope
                         .type_(name)
@@ -209,30 +189,30 @@ fn find_path_for_module(
             return Some((ModPath::from_segments(kind, iter::once(name.clone())), Stable));
         }
     }
-    let prefix = if module_id.is_within_block() { PrefixKind::Plain } else { ctx.prefix };
-    let may_be_in_scope = match prefix {
+
+    let may_be_in_scope = match ctx.prefix {
         PrefixKind::Plain | PrefixKind::BySelf => true,
-        PrefixKind::ByCrate => from.is_crate_root(),
+        PrefixKind::ByCrate => ctx.from.is_crate_root(),
     };
     if may_be_in_scope {
         let scope_name = find_in_scope(
             ctx.db,
-            def_map,
-            from,
+            ctx.from_def_map,
+            ctx.from,
             ItemInNs::Types(module_id.into()),
             ctx.ignore_local_imports,
         );
         if let Some(scope_name) = scope_name {
             // - if the item is already in scope, return the name under which it is
             return Some((
-                ModPath::from_segments(prefix.path_kind(), iter::once(scope_name)),
+                ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)),
                 Stable,
             ));
         }
     }
 
     // - if the module can be referenced as self, super or crate, do that
-    if let Some(mod_path) = is_kw_kind_relative_to_from(def_map, module_id, from) {
+    if let Some(mod_path) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) {
         if ctx.prefix != PrefixKind::ByCrate || mod_path.kind == PathKind::Crate {
             return Some((mod_path, Stable));
         }
@@ -240,21 +220,13 @@ fn find_path_for_module(
 
     // - if the module is in the prelude, return it by that path
     if let Some(mod_path) =
-        find_in_prelude(ctx.db, &root_def_map, def_map, ItemInNs::Types(module_id.into()), from)
+        find_in_prelude(ctx.db, ctx.from_def_map, ItemInNs::Types(module_id.into()), ctx.from)
     {
         return Some((mod_path, Stable));
     }
-    calculate_best_path(
-        ctx,
-        def_map,
-        visited_modules,
-        max_len,
-        ItemInNs::Types(module_id.into()),
-        from,
-    )
+    calculate_best_path(ctx, visited_modules, ItemInNs::Types(module_id.into()), max_len)
 }
 
-// FIXME: Do we still need this now that we record import origins, and hence aliases?
 fn find_in_scope(
     db: &dyn DefDatabase,
     def_map: &DefMap,
@@ -274,13 +246,11 @@ fn find_in_scope(
 /// name doesn't clash in current scope.
 fn find_in_prelude(
     db: &dyn DefDatabase,
-    root_def_map: &DefMap,
     local_def_map: &DefMap,
     item: ItemInNs,
     from: ModuleId,
 ) -> Option<ModPath> {
-    let (prelude_module, _) = root_def_map.prelude()?;
-    // Preludes in block DefMaps are ignored, only the crate DefMap is searched
+    let (prelude_module, _) = local_def_map.prelude()?;
     let prelude_def_map = prelude_module.def_map(db);
     let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
     let (name, vis, _declared) = prelude_scope.name_of(item)?;
@@ -319,7 +289,7 @@ fn is_kw_kind_relative_to_from(
     let from = from.local_id;
     if item == from {
         // - if the item is the module we're in, use `self`
-        Some(ModPath::from_segments(PathKind::Super(0), None))
+        Some(ModPath::from_segments(PathKind::SELF, None))
     } else if let Some(parent_id) = def_map[from].parent {
         if item == parent_id {
             // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
@@ -337,60 +307,71 @@ fn is_kw_kind_relative_to_from(
 
 #[tracing::instrument(skip_all)]
 fn calculate_best_path(
-    ctx: FindPathCtx<'_>,
-    def_map: &DefMap,
+    ctx: &FindPathCtx<'_>,
     visited_modules: &mut FxHashSet<ModuleId>,
-    max_len: usize,
     item: ItemInNs,
-    from: ModuleId,
+    max_len: usize,
 ) -> Option<(ModPath, Stability)> {
     if max_len <= 1 {
+        // recursive base case, we can't find a path prefix of length 0, one segment is occupied by
+        // the item's name itself.
+        return None;
+    }
+    let fuel = ctx.fuel.get();
+    if fuel == 0 {
+        // we ran out of fuel, so we stop searching here
+        tracing::warn!(
+            "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}",
+            item.krate(ctx.db),
+            ctx.from.krate()
+        );
         return None;
     }
+    ctx.fuel.set(fuel - 1);
+
     let mut best_path = None;
-    let update_best_path =
-        |best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path {
+    let mut best_path_len = max_len;
+    let mut process = |mut path: (ModPath, Stability), name, best_path_len: &mut _| {
+        path.0.push_segment(name);
+        let new_path = match best_path.take() {
+            Some(best_path) => select_best_path(best_path, path, ctx.cfg),
+            None => path,
+        };
+        if new_path.1 == Stable {
+            *best_path_len = new_path.0.len();
+        }
+        match &mut best_path {
             Some((old_path, old_stability)) => {
                 *old_path = new_path.0;
                 *old_stability = zip_stability(*old_stability, new_path.1);
             }
-            None => *best_path = Some(new_path),
-        };
-    // Recursive case:
-    // - otherwise, look for modules containing (reexporting) it and import it from one of those
-    if item.krate(ctx.db) == Some(from.krate) {
-        let mut best_path_len = max_len;
+            None => best_path = Some(new_path),
+        }
+    };
+    let db = ctx.db;
+    if item.krate(db) == Some(ctx.from.krate) {
         // Item was defined in the same crate that wants to import it. It cannot be found in any
         // dependency in this case.
-        for (module_id, name) in find_local_import_locations(ctx.db, item, from) {
+        // FIXME: cache the `find_local_import_locations` output?
+        find_local_import_locations(db, item, ctx.from, ctx.from_def_map, |name, module_id| {
             if !visited_modules.insert(module_id) {
-                continue;
+                return;
             }
-            if let Some(mut path) = find_path_for_module(
-                ctx,
-                def_map,
-                visited_modules,
-                from,
-                module_id,
-                best_path_len - 1,
-            ) {
-                path.0.push_segment(name);
-
-                let new_path = match best_path.take() {
-                    Some(best_path) => select_best_path(best_path, path, ctx.cfg),
-                    None => path,
-                };
-                best_path_len = new_path.0.len();
-                update_best_path(&mut best_path, new_path);
+            // we are looking for paths of length up to best_path_len, any longer will make it be
+            // less optimal. The -1 is due to us pushing name onto it afterwards.
+            if let Some(path) =
+                find_path_for_module(ctx, visited_modules, module_id, best_path_len - 1)
+            {
+                process(path, name.clone(), &mut best_path_len);
             }
-        }
+        })
     } else {
         // Item was defined in some upstream crate. This means that it must be exported from one,
         // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
         // that wants to import it here, but we always prefer to use the external path here.
 
-        for dep in &ctx.db.crate_graph()[from.krate].dependencies {
-            let import_map = ctx.db.import_map(dep.crate_id);
+        for dep in &db.crate_graph()[ctx.from.krate].dependencies {
+            let import_map = db.import_map(dep.crate_id);
             let Some(import_info_for) = import_map.import_info_for(item) else { continue };
             for info in import_info_for {
                 if info.is_doc_hidden {
@@ -400,29 +381,18 @@ fn calculate_best_path(
 
                 // Determine best path for containing module and append last segment from `info`.
                 // FIXME: we should guide this to look up the path locally, or from the same crate again?
-                let Some((mut path, path_stability)) = find_path_for_module(
-                    ctx,
-                    def_map,
-                    visited_modules,
-                    from,
-                    info.container,
-                    max_len - 1,
-                ) else {
+                let path =
+                    find_path_for_module(ctx, visited_modules, info.container, best_path_len - 1);
+                let Some((path, path_stability)) = path else {
                     continue;
                 };
                 cov_mark::hit!(partially_imported);
-                path.push_segment(info.name.clone());
-
-                let path_with_stab = (
+                let path = (
                     path,
                     zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
                 );
 
-                let new_path_with_stab = match best_path.take() {
-                    Some(best_path) => select_best_path(best_path, path_with_stab, ctx.cfg),
-                    None => path_with_stab,
-                };
-                update_best_path(&mut best_path, new_path_with_stab);
+                process(path, info.name.clone(), &mut best_path_len);
             }
         }
     }
@@ -430,7 +400,7 @@ fn calculate_best_path(
 }
 
 /// Select the best (most relevant) path between two paths.
-/// This accounts for stability, path length whether std should be chosen over alloc/core paths as
+/// This accounts for stability, path length whether, std should be chosen over alloc/core paths as
 /// well as ignoring prelude like paths or not.
 fn select_best_path(
     old_path @ (_, old_stability): (ModPath, Stability),
@@ -496,36 +466,33 @@ fn select_best_path(
     }
 }
 
-// FIXME: Remove allocations
 /// Finds locations in `from.krate` from which `item` can be imported by `from`.
 fn find_local_import_locations(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
-) -> Vec<(ModuleId, Name)> {
-    let _p = tracing::span!(tracing::Level::INFO, "find_local_import_locations").entered();
+    def_map: &DefMap,
+    mut cb: impl FnMut(&Name, ModuleId),
+) {
+    let _p = tracing::info_span!("find_local_import_locations").entered();
 
     // `from` can import anything below `from` with visibility of at least `from`, and anything
     // above `from` with any visibility. That means we do not need to descend into private siblings
     // of `from` (and similar).
 
-    let def_map = from.def_map(db);
-
     // Compute the initial worklist. We start with all direct child modules of `from` as well as all
     // of its (recursive) parent modules.
-    let data = &def_map[from.local_id];
-    let mut worklist =
-        data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
-    // FIXME: do we need to traverse out of block expressions here?
-    for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
-        worklist.push(ancestor);
-    }
+    let mut worklist = def_map[from.local_id]
+        .children
+        .values()
+        .map(|child| def_map.module_id(*child))
+        // FIXME: do we need to traverse out of block expressions here?
+        .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db)))
+        .collect::<Vec<_>>();
+    let mut seen: FxHashSet<_> = FxHashSet::default();
 
     let def_map = def_map.crate_root().def_map(db);
 
-    let mut seen: FxHashSet<_> = FxHashSet::default();
-
-    let mut locations = Vec::new();
     while let Some(module) = worklist.pop() {
         if !seen.insert(module) {
             continue; // already processed this module
@@ -566,7 +533,7 @@ fn find_local_import_locations(
                 // the item and we're a submodule of it, so can we.
                 // Also this keeps the cached data smaller.
                 if declared || is_pub_or_explicit {
-                    locations.push((module, name.clone()));
+                    cb(name, module);
                 }
             }
         }
@@ -578,8 +545,6 @@ fn find_local_import_locations(
             }
         }
     }
-
-    locations
 }
 
 #[cfg(test)]
@@ -633,15 +598,13 @@ mod tests {
                 .into_iter()
                 .cartesian_product([false, true])
         {
-            let found_path = find_path_inner(
-                FindPathCtx {
-                    db: &db,
-                    prefix,
-                    cfg: ImportPathConfig { prefer_no_std: false, prefer_prelude },
-                    ignore_local_imports,
-                },
+            let found_path = find_path(
+                &db,
                 resolved,
                 module,
+                prefix,
+                ignore_local_imports,
+                ImportPathConfig { prefer_no_std: false, prefer_prelude },
             );
             format_to!(
                 res,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 10a1d65bb93..b9f8082391f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -11,7 +11,7 @@ use hir_expand::{
     ExpandResult,
 };
 use intern::Interned;
-use la_arena::Arena;
+use la_arena::{Arena, RawIdx};
 use once_cell::unsync::Lazy;
 use stdx::impl_from;
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
@@ -28,6 +28,9 @@ use crate::{
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
 
+const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
+    LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
+
 /// Data about a generic type parameter (to a function, struct, impl, ...).
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TypeParamData {
@@ -403,12 +406,12 @@ impl GenericParamsCollector {
                 let (def_map, expander) = &mut **exp;
 
                 let module = expander.module.local_id;
-                let resolver = |path| {
+                let resolver = |path: &_| {
                     def_map
                         .resolve_path(
                             db,
                             module,
-                            &path,
+                            path,
                             crate::item_scope::BuiltinShadowMode::Other,
                             Some(MacroSubNs::Bang),
                         )
@@ -441,15 +444,18 @@ impl GenericParamsCollector {
 
 impl GenericParams {
     /// Number of Generic parameters (type_or_consts + lifetimes)
+    #[inline]
     pub fn len(&self) -> usize {
         self.type_or_consts.len() + self.lifetimes.len()
     }
 
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
     /// Iterator of type_or_consts field
+    #[inline]
     pub fn iter_type_or_consts(
         &self,
     ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
@@ -457,6 +463,7 @@ impl GenericParams {
     }
 
     /// Iterator of lifetimes field
+    #[inline]
     pub fn iter_lt(
         &self,
     ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
@@ -467,7 +474,7 @@ impl GenericParams {
         db: &dyn DefDatabase,
         def: GenericDefId,
     ) -> Interned<GenericParams> {
-        let _p = tracing::span!(tracing::Level::INFO, "generic_params_query").entered();
+        let _p = tracing::info_span!("generic_params_query").entered();
 
         let krate = def.module(db).krate;
         let cfg_options = db.crate_graph();
@@ -605,17 +612,18 @@ impl GenericParams {
         })
     }
 
-    pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
-            matches!(
-                p,
-                TypeOrConstParamData::TypeParamData(TypeParamData {
-                    provenance: TypeParamProvenance::TraitSelf,
-                    ..
-                })
-            )
-            .then(|| id)
-        })
+    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
+        if self.type_or_consts.is_empty() {
+            return None;
+        }
+        matches!(
+            self.type_or_consts[SELF_PARAM_ID_IN_SELF],
+            TypeOrConstParamData::TypeParamData(TypeParamData {
+                provenance: TypeParamProvenance::TraitSelf,
+                ..
+            })
+        )
+        .then(|| SELF_PARAM_ID_IN_SELF)
     }
 
     pub fn find_lifetime_by_name(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 2f7ebbfec13..fd6f4a3d089 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -503,11 +503,11 @@ impl BindingAnnotation {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum BindingProblems {
-    /// https://doc.rust-lang.org/stable/error_codes/E0416.html
+    /// <https://doc.rust-lang.org/stable/error_codes/E0416.html>
     BoundMoreThanOnce,
-    /// https://doc.rust-lang.org/stable/error_codes/E0409.html
+    /// <https://doc.rust-lang.org/stable/error_codes/E0409.html>
     BoundInconsistently,
-    /// https://doc.rust-lang.org/stable/error_codes/E0408.html
+    /// <https://doc.rust-lang.org/stable/error_codes/E0408.html>
     NotBoundAcrossAll,
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 6e40293dbf8..2b2db21a9f4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -73,7 +73,7 @@ impl ImportMap {
     }
 
     pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_map_query").entered();
+        let _p = tracing::info_span!("import_map_query").entered();
 
         let map = Self::collect_import_map(db, krate);
 
@@ -124,7 +124,7 @@ impl ImportMap {
     }
 
     fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex {
-        let _p = tracing::span!(tracing::Level::INFO, "collect_import_map").entered();
+        let _p = tracing::info_span!("collect_import_map").entered();
 
         let def_map = db.crate_def_map(krate);
         let mut map = FxIndexMap::default();
@@ -214,7 +214,7 @@ impl ImportMap {
         is_type_in_ns: bool,
         trait_import_info: &ImportInfo,
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "collect_trait_assoc_items").entered();
+        let _p = tracing::info_span!("collect_trait_assoc_items").entered();
         for &(ref assoc_item_name, item) in &db.trait_data(tr).items {
             let module_def_id = match item {
                 AssocItemId::FunctionId(f) => ModuleDefId::from(f),
@@ -396,7 +396,7 @@ pub fn search_dependencies(
     krate: CrateId,
     query: &Query,
 ) -> FxHashSet<ItemInNs> {
-    let _p = tracing::span!(tracing::Level::INFO, "search_dependencies", ?query).entered();
+    let _p = tracing::info_span!("search_dependencies", ?query).entered();
 
     let graph = db.crate_graph();
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index acda64c41fb..c3b7a78301d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -99,7 +99,7 @@ pub struct ItemTree {
 
 impl ItemTree {
     pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
-        let _p = tracing::span!(tracing::Level::INFO, "file_item_tree_query", ?file_id).entered();
+        let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
 
         let syntax = db.parse_or_expand(file_id);
 
@@ -242,11 +242,11 @@ impl ItemVisibilities {
         match &vis {
             RawVisibility::Public => RawVisibilityId::PUB,
             RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
-                match (&path.kind, explicitiy) {
-                    (PathKind::Super(0), VisibilityExplicitness::Explicit) => {
+                match (path.kind, explicitiy) {
+                    (PathKind::SELF, VisibilityExplicitness::Explicit) => {
                         RawVisibilityId::PRIV_EXPLICIT
                     }
-                    (PathKind::Super(0), VisibilityExplicitness::Implicit) => {
+                    (PathKind::SELF, VisibilityExplicitness::Implicit) => {
                         RawVisibilityId::PRIV_IMPLICIT
                     }
                     (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
@@ -586,11 +586,11 @@ impl Index<RawVisibilityId> for ItemTree {
     fn index(&self, index: RawVisibilityId) -> &Self::Output {
         static VIS_PUB: RawVisibility = RawVisibility::Public;
         static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module(
-            ModPath::from_kind(PathKind::Super(0)),
+            ModPath::from_kind(PathKind::SELF),
             VisibilityExplicitness::Implicit,
         );
         static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module(
-            ModPath::from_kind(PathKind::Super(0)),
+            ModPath::from_kind(PathKind::SELF),
             VisibilityExplicitness::Explicit,
         );
         static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(
@@ -928,7 +928,7 @@ impl UseTree {
                         _ => None,
                     }
                 }
-                (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => {
+                (Some(prefix), PathKind::SELF) if path.segments().is_empty() => {
                     // `some::path::self` == `some::path`
                     Some((prefix, ImportKind::TypeOnly))
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 3a07c678428..6d7836d5ae8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -91,7 +91,7 @@ impl LangItems {
         db: &dyn DefDatabase,
         krate: CrateId,
     ) -> Option<Arc<LangItems>> {
-        let _p = tracing::span!(tracing::Level::INFO, "crate_lang_items_query").entered();
+        let _p = tracing::info_span!("crate_lang_items_query").entered();
 
         let mut lang_items = LangItems::default();
 
@@ -163,7 +163,7 @@ impl LangItems {
         start_crate: CrateId,
         item: LangItem,
     ) -> Option<LangItemTarget> {
-        let _p = tracing::span!(tracing::Level::INFO, "lang_item_query").entered();
+        let _p = tracing::info_span!("lang_item_query").entered();
         if let Some(target) =
             db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied())
         {
@@ -183,7 +183,7 @@ impl LangItems {
     ) where
         T: Into<AttrDefId> + Copy,
     {
-        let _p = tracing::span!(tracing::Level::INFO, "collect_lang_item").entered();
+        let _p = tracing::info_span!("collect_lang_item").entered();
         if let Some(lang_item) = lang_attr(db, item.into()) {
             self.items.entry(lang_item).or_insert_with(|| constructor(item));
         }
@@ -199,7 +199,7 @@ pub(crate) fn notable_traits_in_deps(
     db: &dyn DefDatabase,
     krate: CrateId,
 ) -> Arc<[Arc<[TraitId]>]> {
-    let _p = tracing::span!(tracing::Level::INFO, "notable_traits_in_deps", ?krate).entered();
+    let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered();
     let crate_graph = db.crate_graph();
 
     Arc::from_iter(
@@ -208,7 +208,7 @@ pub(crate) fn notable_traits_in_deps(
 }
 
 pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option<Arc<[TraitId]>> {
-    let _p = tracing::span!(tracing::Level::INFO, "crate_notable_traits", ?krate).entered();
+    let _p = tracing::info_span!("crate_notable_traits", ?krate).entered();
 
     let mut traits = Vec::new();
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 682d169adb1..f6fe0c618a2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -56,6 +56,7 @@ pub mod find_path;
 pub mod import_map;
 pub mod visibility;
 
+use intern::Interned;
 pub use rustc_abi as layout;
 use triomphe::Arc;
 
@@ -72,7 +73,7 @@ use std::{
 
 use base_db::{
     impl_intern_key,
-    salsa::{self, impl_intern_value_trivial},
+    salsa::{self, InternValueTrivial},
     CrateId,
 };
 use hir_expand::{
@@ -90,7 +91,7 @@ use hir_expand::{
 use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
-use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId};
+use span::{AstIdNode, Edition, FileAstId, SyntaxContextId};
 use stdx::impl_from;
 use syntax::{ast, AstNode};
 
@@ -186,7 +187,7 @@ pub trait ItemTreeLoc {
 macro_rules! impl_intern {
     ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
         impl_intern_key!($id);
-        impl_intern_value_trivial!($loc);
+        impl InternValueTrivial for $loc {}
         impl_intern_lookup!(DefDatabase, $id, $loc, $intern, $lookup);
     };
 }
@@ -396,6 +397,23 @@ impl PartialEq<ModuleId> for CrateRootModuleId {
         other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
     }
 }
+impl PartialEq<CrateRootModuleId> for ModuleId {
+    fn eq(&self, other: &CrateRootModuleId) -> bool {
+        other == self
+    }
+}
+
+impl From<CrateRootModuleId> for ModuleId {
+    fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
+        ModuleId { krate, block: None, local_id: DefMap::ROOT }
+    }
+}
+
+impl From<CrateRootModuleId> for ModuleDefId {
+    fn from(value: CrateRootModuleId) -> Self {
+        ModuleDefId::ModuleId(value.into())
+    }
+}
 
 impl From<CrateId> for CrateRootModuleId {
     fn from(krate: CrateId) -> Self {
@@ -472,6 +490,7 @@ impl ModuleId {
         self.block.is_some()
     }
 
+    /// Returns the [`CrateRootModuleId`] for this module if it is the crate root module.
     pub fn as_crate_root(&self) -> Option<CrateRootModuleId> {
         if self.local_id == DefMap::ROOT && self.block.is_none() {
             Some(CrateRootModuleId { krate: self.krate })
@@ -480,33 +499,17 @@ impl ModuleId {
         }
     }
 
+    /// Returns the [`CrateRootModuleId`] for this module.
     pub fn derive_crate_root(&self) -> CrateRootModuleId {
         CrateRootModuleId { krate: self.krate }
     }
 
+    /// Whether this module represents the crate root module
     fn is_crate_root(&self) -> bool {
         self.local_id == DefMap::ROOT && self.block.is_none()
     }
 }
 
-impl PartialEq<CrateRootModuleId> for ModuleId {
-    fn eq(&self, other: &CrateRootModuleId) -> bool {
-        other == self
-    }
-}
-
-impl From<CrateRootModuleId> for ModuleId {
-    fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
-        ModuleId { krate, block: None, local_id: DefMap::ROOT }
-    }
-}
-
-impl From<CrateRootModuleId> for ModuleDefId {
-    fn from(value: CrateRootModuleId) -> Self {
-        ModuleDefId::ModuleId(value.into())
-    }
-}
-
 /// An ID of a module, **local** to a `DefMap`.
 pub type LocalModuleId = Idx<nameres::ModuleData>;
 
@@ -532,7 +535,7 @@ pub struct TypeOrConstParamId {
     pub parent: GenericDefId,
     pub local_id: LocalTypeOrConstParamId,
 }
-impl_intern_value_trivial!(TypeOrConstParamId);
+impl InternValueTrivial for TypeOrConstParamId {}
 
 /// A TypeOrConstParamId with an invariant that it actually belongs to a type
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -594,7 +597,7 @@ pub struct LifetimeParamId {
     pub local_id: LocalLifetimeParamId,
 }
 pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
-impl_intern_value_trivial!(LifetimeParamId);
+impl InternValueTrivial for LifetimeParamId {}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ItemContainerId {
@@ -920,6 +923,7 @@ pub enum GenericDefId {
     ImplId(ImplId),
     // enum variants cannot have generics themselves, but their parent enums
     // can, and this makes some code easier to write
+    // FIXME: Try to remove this as that will reduce the amount of query slots generated per enum?
     EnumVariantId(EnumVariantId),
     // consts can have type parameters from their parents (i.e. associated consts of traits)
     ConstId(ConstId),
@@ -956,15 +960,14 @@ impl GenericDefId {
         match self {
             GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it),
-            GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None),
             GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
-            // We won't be using this ID anyway
-            GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None),
+            GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
+            GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None),
         }
     }
 
@@ -1368,7 +1371,7 @@ pub trait AsMacroCall {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
+        resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Option<MacroCallId> {
         self.as_call_id_with_errors(db, krate, resolver).ok()?.value
     }
@@ -1377,7 +1380,7 @@ pub trait AsMacroCall {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
+        resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
 }
 
@@ -1386,7 +1389,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
+        resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Result<ExpandResult<Option<MacroCallId>>, 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));
@@ -1406,7 +1409,8 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 
         macro_call_as_call_id_with_eager(
             db,
-            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
+            ast_id,
+            &path,
             call_site.ctx,
             expands_to,
             krate,
@@ -1420,11 +1424,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 #[derive(Clone, Debug, Eq, PartialEq)]
 struct AstIdWithPath<T: AstIdNode> {
     ast_id: AstId<T>,
-    path: path::ModPath,
+    path: Interned<path::ModPath>,
 }
 
 impl<T: AstIdNode> AstIdWithPath<T> {
-    fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
+    fn new(
+        file_id: HirFileId,
+        ast_id: FileAstId<T>,
+        path: Interned<path::ModPath>,
+    ) -> AstIdWithPath<T> {
         AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
     }
 }
@@ -1435,30 +1443,39 @@ fn macro_call_as_call_id(
     call_site: SyntaxContextId,
     expand_to: ExpandTo,
     krate: CrateId,
-    resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
+    resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
 ) -> Result<Option<MacroCallId>, UnresolvedMacro> {
-    macro_call_as_call_id_with_eager(db, call, call_site, expand_to, krate, resolver, resolver)
-        .map(|res| res.value)
+    macro_call_as_call_id_with_eager(
+        db,
+        call.ast_id,
+        &call.path,
+        call_site,
+        expand_to,
+        krate,
+        resolver,
+        resolver,
+    )
+    .map(|res| res.value)
 }
 
 fn macro_call_as_call_id_with_eager(
     db: &dyn ExpandDatabase,
-    call: &AstIdWithPath<ast::MacroCall>,
+    ast_id: AstId<ast::MacroCall>,
+    path: &path::ModPath,
     call_site: SyntaxContextId,
     expand_to: ExpandTo,
     krate: CrateId,
-    resolver: impl FnOnce(path::ModPath) -> Option<MacroDefId>,
-    eager_resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+    resolver: impl FnOnce(&path::ModPath) -> Option<MacroDefId>,
+    eager_resolver: impl Fn(&path::ModPath) -> Option<MacroDefId>,
 ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
-    let def =
-        resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
+    let def = resolver(path).ok_or_else(|| UnresolvedMacro { path: path.clone() })?;
 
     let res = match def.kind {
         MacroDefKind::BuiltInEager(..) => expand_eager_macro_input(
             db,
             krate,
-            &call.ast_id.to_node(db),
-            call.ast_id,
+            &ast_id.to_node(db),
+            ast_id,
             def,
             call_site,
             &|path| eager_resolver(path).filter(MacroDefId::is_fn_like),
@@ -1467,12 +1484,12 @@ fn macro_call_as_call_id_with_eager(
             value: Some(def.make_call(
                 db,
                 krate,
-                MacroCallKind::FnLike { ast_id: call.ast_id, expand_to, eager: None },
+                MacroCallKind::FnLike { ast_id, expand_to, eager: None },
                 call_site,
             )),
             err: None,
         },
-        _ => return Err(UnresolvedMacro { path: call.path.clone() }),
+        _ => return Err(UnresolvedMacro { path: path.clone() }),
     };
     Ok(res)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index c5c26e26bc0..4058159cefe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -1883,3 +1883,41 @@ fn test() {
 "#]],
     );
 }
+
+#[test]
+fn test_pat_fragment_eof_17441() {
+    check(
+        r#"
+macro_rules! matches {
+    ($expression:expr, $pattern:pat $(if $guard:expr)? ) => {
+        match $expression {
+            $pattern $(if $guard)? => true,
+            _ => false
+        }
+    };
+}
+fn f() {
+    matches!(0, 10..);
+    matches!(0, 10.. if true);
+}
+ "#,
+        expect![[r#"
+macro_rules! matches {
+    ($expression:expr, $pattern:pat $(if $guard:expr)? ) => {
+        match $expression {
+            $pattern $(if $guard)? => true,
+            _ => false
+        }
+    };
+}
+fn f() {
+    match 0 {
+        10.. =>true , _=>false
+    };
+    match 0 {
+        10..if true =>true , _=>false
+    };
+}
+ "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 8904aca9f28..dc964b3c9a8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -96,7 +96,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         let res = macro_call
             .as_call_id_with_errors(&db, krate, |path| {
                 resolver
-                    .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang))
+                    .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang))
                     .map(|(it, _)| db.macro_def(it))
             })
             .unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index a3eab22fc49..162b6429c34 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -16,8 +16,8 @@
 //!
 //! 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).
+//! phase. Macro calls are represented as a triple of `(Path, Option<Name>,
+//! TokenTree)`.
 //!
 //! ## Collecting Modules
 //!
@@ -333,7 +333,7 @@ impl DefMap {
         let crate_graph = db.crate_graph();
         let krate = &crate_graph[crate_id];
         let name = krate.display_name.as_deref().unwrap_or_default();
-        let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?name).entered();
+        let _p = tracing::info_span!("crate_def_map_query", ?name).entered();
 
         let module_data = ModuleData::new(
             ModuleOrigin::CrateRoot { definition: krate.root_file_id },
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
index 3cb0666edf9..f842027d642 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
@@ -3,6 +3,7 @@
 use base_db::CrateId;
 use hir_expand::{
     attrs::{Attr, AttrId, AttrInput},
+    inert_attr_macro::find_builtin_attr_idx,
     MacroCallId, MacroCallKind, MacroDefId,
 };
 use span::SyntaxContextId;
@@ -10,7 +11,6 @@ use syntax::{ast, SmolStr};
 use triomphe::Arc;
 
 use crate::{
-    attr::builtin::find_builtin_attr_idx,
     db::DefDatabase,
     item_scope::BuiltinShadowMode,
     nameres::path_resolution::ResolveMode,
@@ -59,7 +59,7 @@ impl DefMap {
                     return Ok(ResolvedAttr::Other);
                 }
             }
-            None => return Err(UnresolvedMacro { path: ast_id.path }),
+            None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }),
         };
 
         Ok(ResolvedAttr::Macro(attr_macro_as_call_id(
@@ -89,9 +89,12 @@ impl DefMap {
             }
 
             if segments.len() == 1 {
-                let mut registered = self.data.registered_attrs.iter().map(SmolStr::as_str);
-                let is_inert = find_builtin_attr_idx(&name).is_some() || registered.any(pred);
-                return is_inert;
+                if find_builtin_attr_idx(&name).is_some() {
+                    return true;
+                }
+                if self.data.registered_attrs.iter().map(SmolStr::as_str).any(pred) {
+                    return true;
+                }
             }
         }
         false
@@ -134,12 +137,12 @@ pub(super) fn derive_macro_as_call_id(
     derive_pos: u32,
     call_site: SyntaxContextId,
     krate: CrateId,
-    resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
+    resolver: impl Fn(&path::ModPath) -> Option<(MacroId, MacroDefId)>,
     derive_macro_id: MacroCallId,
 ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
-    let (macro_id, def_id) = resolver(item_attr.path.clone())
+    let (macro_id, def_id) = resolver(&item_attr.path)
         .filter(|(_, def_id)| def_id.is_derive())
-        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?;
     let call_id = def_id.make_call(
         db.upcast(),
         krate,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 587997c4736..6d2eb71549e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -10,18 +10,19 @@ use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
     attrs::{Attr, AttrId},
-    builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
+    builtin_attr_macro::find_builtin_attr,
     builtin_derive_macro::find_builtin_derive,
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
     proc_macro::CustomProcMacroExpander,
     ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
+use intern::Interned;
 use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
+use span::{Edition, ErasedFileAstId, FileAstId, SyntaxContextId};
 use syntax::ast;
 use triomphe::Arc;
 
@@ -75,36 +76,23 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
 
     let proc_macros = if krate.is_proc_macro {
         match db.proc_macros().get(&def_map.krate) {
-            Some(Ok(proc_macros)) => {
-                Ok(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(),
-                            span: Span {
-                                range: syntax::TextRange::empty(syntax::TextSize::new(0)),
-                                anchor: span::SpanAnchor {
-                                    file_id: FileId::BOGUS,
-                                    ast_id: span::ROOT_ERASED_FILE_AST_ID,
-                                },
-                                ctx: SyntaxContextId::ROOT,
-                            },
-                        };
-                        (
-                            name.as_name(),
-                            if it.disabled {
-                                CustomProcMacroExpander::disabled()
-                            } else {
-                                CustomProcMacroExpander::new(
-                                    hir_expand::proc_macro::ProcMacroId::new(idx as u32),
-                                )
-                            },
-                        )
-                    })
-                    .collect())
-            }
+            Some(Ok(proc_macros)) => Ok(proc_macros
+                .iter()
+                .enumerate()
+                .map(|(idx, it)| {
+                    let name = Name::new_text_dont_use(it.name.clone());
+                    (
+                        name,
+                        if it.disabled {
+                            CustomProcMacroExpander::disabled()
+                        } else {
+                            CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new(
+                                idx as u32,
+                            ))
+                        },
+                    )
+                })
+                .collect()),
             Some(Err(e)) => Err(e.clone().into_boxed_str()),
             None => Err("No proc-macros present for crate".to_owned().into_boxed_str()),
         }
@@ -270,12 +258,13 @@ struct DefCollector<'a> {
     ///
     /// This also stores the attributes to skip when we resolve derive helpers and non-macro
     /// non-builtin attributes in general.
+    // FIXME: There has to be a better way to do this
     skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
 }
 
 impl DefCollector<'_> {
     fn seed_with_top_level(&mut self) {
-        let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered();
+        let _p = tracing::info_span!("seed_with_top_level").entered();
 
         let crate_graph = self.db.crate_graph();
         let file_id = crate_graph[self.def_map.krate].root_file_id;
@@ -410,17 +399,17 @@ impl DefCollector<'_> {
     }
 
     fn resolution_loop(&mut self) {
-        let _p = tracing::span!(tracing::Level::INFO, "DefCollector::resolution_loop").entered();
+        let _p = tracing::info_span!("DefCollector::resolution_loop").entered();
 
         // main name resolution fixed-point loop.
         let mut i = 0;
         'resolve_attr: loop {
-            let _p = tracing::span!(tracing::Level::INFO, "resolve_macros loop").entered();
+            let _p = tracing::info_span!("resolve_macros loop").entered();
             'resolve_macros: loop {
                 self.db.unwind_if_cancelled();
 
                 {
-                    let _p = tracing::span!(tracing::Level::INFO, "resolve_imports loop").entered();
+                    let _p = tracing::info_span!("resolve_imports loop").entered();
 
                     'resolve_imports: loop {
                         if self.resolve_imports() == ReachedFixedPoint::Yes {
@@ -446,7 +435,7 @@ impl DefCollector<'_> {
     }
 
     fn collect(&mut self) {
-        let _p = tracing::span!(tracing::Level::INFO, "DefCollector::collect").entered();
+        let _p = tracing::info_span!("DefCollector::collect").entered();
 
         self.resolution_loop();
 
@@ -794,7 +783,7 @@ impl DefCollector<'_> {
     }
 
     fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
-        let _p = tracing::span!(tracing::Level::INFO, "resolve_import", import_path = %import.path.display(self.db.upcast()))
+        let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast()))
             .entered();
         tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
         match import.source {
@@ -856,7 +845,7 @@ impl DefCollector<'_> {
     }
 
     fn record_resolved_import(&mut self, directive: &ImportDirective) {
-        let _p = tracing::span!(tracing::Level::INFO, "record_resolved_import").entered();
+        let _p = tracing::info_span!("record_resolved_import").entered();
 
         let module_id = directive.module_id;
         let import = &directive.import;
@@ -1136,18 +1125,18 @@ impl DefCollector<'_> {
                     MacroSubNs::Attr
                 }
             };
-            let resolver = |path| {
+            let resolver = |path: &_| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
                     self.db,
                     ResolveMode::Other,
                     directive.module_id,
-                    &path,
+                    path,
                     BuiltinShadowMode::Module,
                     Some(subns),
                 );
                 resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it)))
             };
-            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
+            let resolver_def_id = |path: &_| resolver(path).map(|(_, it)| it);
 
             match &directive.kind {
                 MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => {
@@ -1250,22 +1239,28 @@ impl DefCollector<'_> {
                         }
                     }
 
-                    let def = match resolver_def_id(path.clone()) {
+                    let def = match resolver_def_id(path) {
                         Some(def) if def.is_attribute() => def,
                         _ => return Resolved::No,
                     };
 
-                    let call_id =
-                        attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
-                    if let MacroDefId {
-                        kind:
-                            MacroDefKind::BuiltInAttr(
-                                BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst,
-                                _,
-                            ),
-                        ..
-                    } = def
-                    {
+                    // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
+                    // due to duplicating functions into macro expansions
+                    if matches!(
+                        def.kind,
+                        MacroDefKind::BuiltInAttr(_, expander)
+                        if expander.is_test() || expander.is_bench()
+                    ) {
+                        return recollect_without(self);
+                    }
+
+                    let call_id = || {
+                        attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def)
+                    };
+                    if matches!(def,
+                        MacroDefId { kind: MacroDefKind::BuiltInAttr(_, exp), .. }
+                        if exp.is_derive()
+                    ) {
                         // Resolved to `#[derive]`, we don't actually expand this attribute like
                         // normal (as that would just be an identity expansion with extra output)
                         // Instead we treat derive attributes special and apply them separately.
@@ -1290,9 +1285,14 @@ impl DefCollector<'_> {
 
                         match attr.parse_path_comma_token_tree(self.db.upcast()) {
                             Some(derive_macros) => {
+                                let call_id = call_id();
                                 let mut len = 0;
                                 for (idx, (path, call_site)) in derive_macros.enumerate() {
-                                    let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
+                                    let ast_id = AstIdWithPath::new(
+                                        file_id,
+                                        ast_id.value,
+                                        Interned::new(path),
+                                    );
                                     self.unresolved_macros.push(MacroDirective {
                                         module_id: directive.module_id,
                                         depth: directive.depth + 1,
@@ -1312,13 +1312,6 @@ impl DefCollector<'_> {
                                 // This is just a trick to be able to resolve the input to derives
                                 // as proper paths in `Semantics`.
                                 // 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,
-                                );
                                 self.def_map.modules[directive.module_id]
                                     .scope
                                     .init_derive_attribute(ast_id, attr.id, call_id, len + 1);
@@ -1336,17 +1329,8 @@ impl DefCollector<'_> {
                         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!(
-                        def.kind,
-                        MacroDefKind::BuiltInAttr(expander, _)
-                        if expander.is_test() || expander.is_bench()
-                    ) {
-                        return recollect_without(self);
-                    }
-
-                    if let MacroDefKind::ProcMacro(exp, ..) = def.kind {
+                    let call_id = call_id();
+                    if let MacroDefKind::ProcMacro(_, exp, _) = def.kind {
                         // If proc attribute macro expansion is disabled, skip expanding it here
                         if !self.db.expand_proc_attr_macros() {
                             self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
@@ -1430,7 +1414,7 @@ impl DefCollector<'_> {
     fn finish(mut self) -> DefMap {
         // Emit diagnostics for all remaining unexpanded macros.
 
-        let _p = tracing::span!(tracing::Level::INFO, "DefCollector::finish").entered();
+        let _p = tracing::info_span!("DefCollector::finish").entered();
 
         for directive in &self.unresolved_macros {
             match &directive.kind {
@@ -1447,7 +1431,7 @@ impl DefCollector<'_> {
                                 self.db,
                                 ResolveMode::Other,
                                 directive.module_id,
-                                &path,
+                                path,
                                 BuiltinShadowMode::Module,
                                 Some(MacroSubNs::Bang),
                             );
@@ -1481,7 +1465,7 @@ impl DefCollector<'_> {
                             derive_index: *derive_pos as u32,
                             derive_macro_id: *derive_macro_id,
                         },
-                        ast_id.path.clone(),
+                        ast_id.path.as_ref().clone(),
                     ));
                 }
                 // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them
@@ -2116,7 +2100,7 @@ impl ModCollector<'_, '_> {
             let ast_id = AstIdWithPath::new(
                 self.file_id(),
                 mod_item.ast_id(self.item_tree),
-                attr.path.as_ref().clone(),
+                attr.path.clone(),
             );
             self.def_collector.unresolved_macros.push(MacroDirective {
                 module_id: self.module_id,
@@ -2162,19 +2146,7 @@ impl ModCollector<'_, '_> {
             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.into(),
-                        span: Span {
-                            range: syntax::TextRange::empty(syntax::TextSize::new(0)),
-                            anchor: span::SpanAnchor {
-                                file_id: FileId::BOGUS,
-                                ast_id: span::ROOT_ERASED_FILE_AST_ID,
-                            },
-                            ctx: SyntaxContextId::ROOT,
-                        },
-                    }
-                    .as_name();
+                    name = Name::new_text_dont_use(it.into());
                     &name
                 }
                 None => {
@@ -2310,7 +2282,7 @@ impl ModCollector<'_, '_> {
         &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
         container: ItemContainerId,
     ) {
-        let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path));
+        let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone());
         let db = self.def_collector.db;
 
         // FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define
@@ -2320,7 +2292,8 @@ impl ModCollector<'_, '_> {
         // Case 1: try to resolve macro calls with single-segment name and expand macro_rules
         if let Ok(res) = macro_call_as_call_id_with_eager(
             db.upcast(),
-            &ast_id,
+            ast_id.ast_id,
+            &ast_id.path,
             ctxt,
             expand_to,
             self.def_collector.def_map.krate,
@@ -2347,7 +2320,7 @@ impl ModCollector<'_, '_> {
                     db,
                     ResolveMode::Other,
                     self.module_id,
-                    &path,
+                    path,
                     BuiltinShadowMode::Module,
                     Some(MacroSubNs::Bang),
                 );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index d621f3a360a..e797d19223e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -283,7 +283,7 @@ impl DefMap {
                     // If we have a different `DefMap` from `self` (the original `DefMap` we started
                     // with), resolve the remaining path segments in that `DefMap`.
                     let path =
-                        ModPath::from_segments(PathKind::Super(0), path.segments().iter().cloned());
+                        ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned());
                     return def_map.resolve_path_fp_with_macro(
                         db,
                         mode,
@@ -333,7 +333,7 @@ impl DefMap {
                 ModuleDefId::ModuleId(module) => {
                     if module.krate != self.krate {
                         let path = ModPath::from_segments(
-                            PathKind::Super(0),
+                            PathKind::SELF,
                             path.segments()[i..].iter().cloned(),
                         );
                         tracing::debug!("resolving {:?} in other crate", path);
@@ -493,7 +493,12 @@ impl DefMap {
                 )
             })
         };
-        let prelude = || self.resolve_in_prelude(db, name);
+        let prelude = || {
+            if self.block.is_some() && module == DefMap::ROOT {
+                return PerNs::none();
+            }
+            self.resolve_in_prelude(db, name)
+        };
 
         from_legacy_macro
             .or(from_scope_or_builtin)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 6af52614111..2b555b3998a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -122,7 +122,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                 // don't break out if `self` is the last segment of a path, this mean we got a
                 // use tree like `foo::{self}` which we want to resolve as `foo`
                 if !segments.is_empty() {
-                    kind = PathKind::Super(0);
+                    kind = PathKind::SELF;
                     break;
                 }
             }
@@ -144,7 +144,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
 
     if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() {
         // plain empty paths don't exist, this means we got a single `self` segment as our path
-        kind = PathKind::Super(0);
+        kind = PathKind::SELF;
     }
 
     // handle local_inner_macros :
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
index 36ab62d0f7f..19485c476f7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
@@ -86,7 +86,7 @@ impl PerNs {
     }
 
     pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
-        let _p = tracing::span!(tracing::Level::INFO, "PerNs::filter_visibility").entered();
+        let _p = tracing::info_span!("PerNs::filter_visibility").entered();
         PerNs {
             types: self.types.filter(|&(_, v, _)| f(v)),
             values: self.values.filter(|&(_, v, _)| f(v)),
@@ -119,7 +119,7 @@ impl PerNs {
     }
 
     pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
-        let _p = tracing::span!(tracing::Level::INFO, "PerNs::iter_items").entered();
+        let _p = tracing::info_span!("PerNs::iter_items").entered();
         self.types
             .map(|it| (ItemInNs::Types(it.0), it.2))
             .into_iter()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index d3135bba965..d08e063976a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -57,7 +57,7 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write)
         }
         None => match path.kind() {
             PathKind::Plain => {}
-            PathKind::Super(0) => write!(buf, "self")?,
+            &PathKind::SELF => write!(buf, "self")?,
             PathKind::Super(n) => {
                 for i in 0..*n {
                     if i == 0 {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 1ef8fa772a1..e08718fc836 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -27,10 +27,7 @@ pub enum RawVisibility {
 
 impl RawVisibility {
     pub(crate) const fn private() -> RawVisibility {
-        RawVisibility::Module(
-            ModPath::from_kind(PathKind::Super(0)),
-            VisibilityExplicitness::Implicit,
-        )
+        RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit)
     }
 
     pub(crate) fn from_ast(
@@ -60,7 +57,7 @@ impl RawVisibility {
             }
             ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
             ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
-            ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)),
+            ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
             ast::VisibilityKind::Pub => return RawVisibility::Public,
         };
         RawVisibility::Module(path, VisibilityExplicitness::Explicit)
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 85ec02ae073..db0feb055e1 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -54,7 +54,7 @@ impl RawAttrs {
                     let span = span_map.span_for_range(comment.syntax().text_range());
                     Attr {
                         id,
-                        input: Some(Interned::new(AttrInput::Literal(tt::Literal {
+                        input: Some(Box::new(AttrInput::Literal(tt::Literal {
                             text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))),
                             span,
                         }))),
@@ -199,7 +199,7 @@ impl AttrId {
 pub struct Attr {
     pub id: AttrId,
     pub path: Interned<ModPath>,
-    pub input: Option<Interned<AttrInput>>,
+    pub input: Option<Box<AttrInput>>,
     pub ctxt: SyntaxContextId,
 }
 
@@ -234,7 +234,7 @@ impl Attr {
         })?);
         let span = span_map.span_for_range(range);
         let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
-            Some(Interned::new(AttrInput::Literal(tt::Literal {
+            Some(Box::new(AttrInput::Literal(tt::Literal {
                 text: lit.token().text().into(),
                 span,
             })))
@@ -245,7 +245,7 @@ impl Attr {
                 span,
                 DocCommentDesugarMode::ProcMacro,
             );
-            Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
+            Some(Box::new(AttrInput::TokenTree(Box::new(tree))))
         } else {
             None
         };
@@ -281,12 +281,12 @@ impl Attr {
 
         let input = match input.first() {
             Some(tt::TokenTree::Subtree(tree)) => {
-                Some(Interned::new(AttrInput::TokenTree(Box::new(tree.clone()))))
+                Some(Box::new(AttrInput::TokenTree(Box::new(tree.clone()))))
             }
             Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => {
                 let input = match input.get(1) {
                     Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => {
-                        Some(Interned::new(AttrInput::Literal(lit.clone())))
+                        Some(Box::new(AttrInput::Literal(lit.clone())))
                     }
                     _ => None,
                 };
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
index 9ff29b484d3..2e115f47932 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
@@ -52,8 +52,6 @@ impl BuiltinAttrExpander {
 
 register_builtin! {
     (bench, Bench) => dummy_attr_expand,
-    (cfg, Cfg) => dummy_attr_expand,
-    (cfg_attr, CfgAttr) => dummy_attr_expand,
     (cfg_accessible, CfgAccessible) => dummy_attr_expand,
     (cfg_eval, CfgEval) => dummy_attr_expand,
     (derive, Derive) => derive_expand,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index ba96ab6cc2f..02fd431e4e7 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -67,6 +67,10 @@ impl BuiltinFnLikeExpander {
         let span = span_with_def_site_ctxt(db, span, id);
         self.expander()(db, id, tt, span)
     }
+
+    pub fn is_asm(&self) -> bool {
+        matches!(self, Self::Asm | Self::GlobalAsm)
+    }
 }
 
 impl EagerExpander {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
index 9dd44262ba9..55ae19068f9 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
@@ -189,8 +189,8 @@ pub(crate) fn process_cfg_attrs(
     // FIXME: #[cfg_eval] is not implemented. But it is not stable yet
     let is_derive = match loc.def.kind {
         MacroDefKind::BuiltInDerive(..)
-        | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) => true,
-        MacroDefKind::BuiltInAttr(expander, _) => expander.is_derive(),
+        | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) => true,
+        MacroDefKind::BuiltInAttr(_, expander) => expander.is_derive(),
         _ => false,
     };
     if !is_derive {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 12421bbe702..ad25a1168c4 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -146,13 +146,11 @@ pub fn expand_speculative(
     token_to_map: SyntaxToken,
 ) -> Option<(SyntaxNode, SyntaxToken)> {
     let loc = db.lookup_intern_macro_call(actual_macro_call);
+    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
 
-    // FIXME: This BOGUS here is dangerous once the proc-macro server can call back into the database!
-    let span_map = RealSpanMap::absolute(FileId::BOGUS);
+    let span_map = RealSpanMap::absolute(span.anchor.file_id);
     let span_map = SpanMapRef::RealSpanMap(&span_map);
 
-    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
-
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
         MacroCallKind::FnLike { .. } => (
@@ -252,7 +250,7 @@ pub fn expand_speculative(
     // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
     let mut speculative_expansion =
         match loc.def.kind {
-            MacroDefKind::ProcMacro(expander, _, ast) => {
+            MacroDefKind::ProcMacro(ast, expander, _) => {
                 let span = db.proc_macro_span(ast);
                 tt.delimiter = tt::Delimiter::invisible_spanned(span);
                 expander.expand(
@@ -266,22 +264,22 @@ pub fn expand_speculative(
                     span_with_mixed_site_ctxt(db, span, actual_macro_call),
                 )
             }
-            MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
+            MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => {
                 pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span)
             }
             MacroDefKind::Declarative(it) => db
                 .decl_macro_expander(loc.krate, it)
                 .expand_unhygienic(db, tt, loc.def.krate, span, loc.def.edition),
-            MacroDefKind::BuiltIn(it, _) => {
+            MacroDefKind::BuiltIn(_, it) => {
                 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
             }
-            MacroDefKind::BuiltInDerive(it, ..) => {
+            MacroDefKind::BuiltInDerive(_, it) => {
                 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
             }
-            MacroDefKind::BuiltInEager(it, _) => {
+            MacroDefKind::BuiltInEager(_, it) => {
                 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
             }
-            MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt, span),
+            MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span),
         };
 
     let expand_to = loc.expand_to();
@@ -334,7 +332,7 @@ fn parse_macro_expansion(
     db: &dyn ExpandDatabase,
     macro_file: MacroFileId,
 ) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)> {
-    let _p = tracing::span!(tracing::Level::INFO, "parse_macro_expansion").entered();
+    let _p = tracing::info_span!("parse_macro_expansion").entered();
     let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
     let edition = loc.def.edition;
     let expand_to = loc.expand_to();
@@ -493,7 +491,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
                     .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
             );
             // If derive attribute we need to censor the derive input
-            if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
+            if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive())
                 && ast::Adt::can_cast(node.syntax().kind())
             {
                 let adt = ast::Adt::cast(node.syntax().clone()).unwrap();
@@ -569,11 +567,11 @@ impl TokenExpander {
             MacroDefKind::Declarative(ast_id) => {
                 TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
             }
-            MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander),
-            MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander),
-            MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander),
-            MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander),
-            MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander),
+            MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander),
+            MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander),
+            MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander),
+            MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander),
+            MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander),
         }
     }
 }
@@ -588,7 +586,7 @@ fn macro_expand(
     macro_call_id: MacroCallId,
     loc: MacroCallLoc,
 ) -> ExpandResult<(CowArc<tt::Subtree>, MatchedArmIndex)> {
-    let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered();
+    let _p = tracing::info_span!("macro_expand").entered();
 
     let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
         MacroDefKind::ProcMacro(..) => {
@@ -604,13 +602,13 @@ fn macro_expand(
                     MacroDefKind::Declarative(id) => db
                         .decl_macro_expander(loc.def.krate, id)
                         .expand(db, arg.clone(), macro_call_id, span),
-                    MacroDefKind::BuiltIn(it, _) => {
+                    MacroDefKind::BuiltIn(_, it) => {
                         it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
                     }
-                    MacroDefKind::BuiltInDerive(it, _) => {
+                    MacroDefKind::BuiltInDerive(_, it) => {
                         it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
                     }
-                    MacroDefKind::BuiltInEager(it, _) => {
+                    MacroDefKind::BuiltInEager(_, it) => {
                         // This might look a bit odd, but we do not expand the inputs to eager macros here.
                         // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
                         // That kind of expansion uses the ast id map of an eager macros input though which goes through
@@ -634,12 +632,12 @@ fn macro_expand(
                         }
                         res.zip_val(None)
                     }
-                    MacroDefKind::BuiltInAttr(it, _) => {
+                    MacroDefKind::BuiltInAttr(_, it) => {
                         let mut res = it.expand(db, macro_call_id, arg, span);
                         fixup::reverse_fixups(&mut res.value, &undo_info);
                         res.zip_val(None)
                     }
-                    _ => unreachable!(),
+                    MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
                 };
             (ExpandResult { value: res.value, err: res.err }, span)
         }
@@ -678,8 +676,8 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
     let loc = db.lookup_intern_macro_call(id);
     let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
 
-    let (expander, ast) = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),
+    let (ast, expander) = match loc.def.kind {
+        MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
         _ => unreachable!(),
     };
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index 64e04bc08f5..3e0d2dfa6c1 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -39,7 +39,7 @@ pub fn expand_eager_macro_input(
     ast_id: AstId<ast::MacroCall>,
     def: MacroDefId,
     call_site: SyntaxContextId,
-    resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
+    resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
 ) -> ExpandResult<Option<MacroCallId>> {
     let expand_to = ExpandTo::from_call_site(macro_call);
 
@@ -138,7 +138,7 @@ fn eager_macro_recur(
     curr: InFile<SyntaxNode>,
     krate: CrateId,
     call_site: SyntaxContextId,
-    macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
+    macro_resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
 ) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
     let original = curr.value.clone_for_update();
 
@@ -172,7 +172,7 @@ fn eager_macro_recur(
         let def = match call.path().and_then(|path| {
             ModPath::from_src(db, path, &mut |range| span_map.span_at(range.start()).ctx)
         }) {
-            Some(path) => match macro_resolver(path.clone()) {
+            Some(path) => match macro_resolver(&path) {
                 Some(def) => def,
                 None => {
                     error =
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index 1ba85c5c7ea..743fac50f4e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -1,6 +1,4 @@
 //! Things to wrap other things in file ids.
-use std::iter;
-
 use either::Either;
 use span::{
     AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr,
@@ -150,27 +148,16 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, N> {
     }
 }
 
+impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
+    // unfortunately `syntax` collides with the impl above, because `&_` is fundamental
+    pub fn syntax_ref(&self) -> InFileWrapper<FileId, &SyntaxNode> {
+        self.with_value(self.value.syntax())
+    }
+}
+
 // region:specific impls
 
 impl InFile<&SyntaxNode> {
-    /// Traverse up macro calls and skips the macro invocation node
-    pub fn ancestors_with_macros(
-        self,
-        db: &dyn db::ExpandDatabase,
-    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
-        let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
-            Some(parent) => Some(node.with_value(parent)),
-            None => db
-                .lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id)
-                .to_node_item(db)
-                .syntax()
-                .cloned()
-                .map(|node| node.parent())
-                .transpose(),
-        };
-        iter::successors(succ(&self.cloned()), succ)
-    }
-
     /// Falls back to the macro call range if the node cannot be mapped up fully.
     ///
     /// For attributes and derives, this will point back to the attribute only.
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index 9ec2a83162a..9fdf4aa4f7c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -4,7 +4,10 @@
 use mbe::DocCommentDesugarMode;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
-use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use span::{
+    ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, FIXUP_ERASED_FILE_AST_ID_MARKER,
+    ROOT_ERASED_FILE_AST_ID,
+};
 use stdx::never;
 use syntax::{
     ast::{self, AstNode, HasLoopBody},
@@ -88,7 +91,6 @@ pub(crate) fn fixup_syntax(
             preorder.skip_subtree();
             continue;
         }
-
         // In some other situations, we can fix things by just appending some tokens.
         match_ast! {
             match node {
@@ -273,6 +275,62 @@ pub(crate) fn fixup_syntax(
                         ]);
                     }
                 },
+                ast::RecordExprField(it) => {
+                    if let Some(colon) = it.colon_token() {
+                        if it.name_ref().is_some() && it.expr().is_none() {
+                            append.insert(colon.into(), vec![
+                                Leaf::Ident(Ident {
+                                    text: "__ra_fixup".into(),
+                                    span: fake_span(node_range)
+                                })
+                            ]);
+                        }
+                    }
+                },
+                ast::Path(it) => {
+                    if let Some(colon) = it.coloncolon_token() {
+                        if it.segment().is_none() {
+                            append.insert(colon.into(), vec![
+                                Leaf::Ident(Ident {
+                                    text: "__ra_fixup".into(),
+                                    span: fake_span(node_range)
+                                })
+                            ]);
+                        }
+                    }
+                },
+                ast::ArgList(it) => {
+                    if it.r_paren_token().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Punct(Punct {
+                                span: fake_span(node_range),
+                                char: ')',
+                                spacing: Spacing::Alone
+                            })
+                        ]);
+                    }
+                },
+                ast::ArgList(it) => {
+                    if it.r_paren_token().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Punct(Punct {
+                                span: fake_span(node_range),
+                                char: ')',
+                                spacing: Spacing::Alone
+                            })
+                        ]);
+                    }
+                },
+                ast::ClosureExpr(it) => {
+                    if it.body().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Ident(Ident {
+                                text: "__ra_fixup".into(),
+                                span: fake_span(node_range)
+                            })
+                        ]);
+                    }
+                },
                 _ => (),
             }
         }
@@ -307,8 +365,13 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo)
         tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID
             || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID
     ) {
-        tt.delimiter.close = Span::DUMMY;
-        tt.delimiter.open = Span::DUMMY;
+        let span = |file_id| Span {
+            range: TextRange::empty(TextSize::new(0)),
+            anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
+            ctx: SyntaxContextId::ROOT,
+        };
+        tt.delimiter.open = span(tt.delimiter.open.anchor.file_id);
+        tt.delimiter.close = span(tt.delimiter.close.anchor.file_id);
     }
     reverse_fixups_(tt, undo_info);
 }
@@ -751,4 +814,84 @@ fn foo () {loop { }}
 "#]],
         )
     }
+
+    #[test]
+    fn fixup_path() {
+        check(
+            r#"
+fn foo() {
+    path::
+}
+"#,
+            expect![[r#"
+fn foo () {path :: __ra_fixup}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_record_ctor_field() {
+        check(
+            r#"
+fn foo() {
+    R { f: }
+}
+"#,
+            expect![[r#"
+fn foo () {R {f : __ra_fixup}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn no_fixup_record_ctor_field() {
+        check(
+            r#"
+fn foo() {
+    R { f: a }
+}
+"#,
+            expect![[r#"
+fn foo () {R {f : a}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_arg_list() {
+        check(
+            r#"
+fn foo() {
+    foo(a
+}
+"#,
+            expect![[r#"
+fn foo () { foo ( a ) }
+"#]],
+        );
+        check(
+            r#"
+fn foo() {
+    bar.foo(a
+}
+"#,
+            expect![[r#"
+fn foo () { bar . foo ( a ) }
+"#]],
+        );
+    }
+
+    #[test]
+    fn fixup_closure() {
+        check(
+            r#"
+fn foo() {
+    ||
+}
+"#,
+            expect![[r#"
+fn foo () {|| __ra_fixup}
+"#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index 097e760c70a..cc02332207d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -4,7 +4,7 @@
 //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
 //! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
 //!
-//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
+//! Also see <https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies>
 //!
 //! # The Expansion Order Hierarchy
 //!
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
index f4564c94bb5..35fd85bf451 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
@@ -36,11 +36,6 @@ pub fn find_builtin_attr_idx(name: &str) -> Option<usize> {
         .copied()
 }
 
-// impl AttributeTemplate {
-//     const DEFAULT: AttributeTemplate =
-//         AttributeTemplate { word: false, list: None, name_value_str: None };
-// }
-
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
@@ -628,6 +623,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
     ),
+    rustc_attr!(
+        rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing,
+        "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024",
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 83e92565f4d..a7150cf3087 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -16,6 +16,7 @@ pub mod declarative;
 pub mod eager;
 pub mod files;
 pub mod hygiene;
+pub mod inert_attr_macro;
 pub mod mod_path;
 pub mod name;
 pub mod proc_macro;
@@ -30,7 +31,7 @@ use triomphe::Arc;
 
 use std::{fmt, hash::Hash};
 
-use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId};
+use base_db::{salsa::InternValueTrivial, CrateId, FileId};
 use either::Either;
 use span::{
     Edition, ErasedFileAstId, FileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor,
@@ -46,7 +47,7 @@ use crate::{
     builtin_attr_macro::BuiltinAttrExpander,
     builtin_derive_macro::BuiltinDeriveExpander,
     builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
-    db::{ExpandDatabase, TokenExpander},
+    db::ExpandDatabase,
     mod_path::ModPath,
     proc_macro::{CustomProcMacroExpander, ProcMacroKind},
     span_map::{ExpansionSpanMap, SpanMap},
@@ -172,7 +173,7 @@ pub struct MacroCallLoc {
     pub kind: MacroCallKind,
     pub ctxt: SyntaxContextId,
 }
-impl_intern_value_trivial!(MacroCallLoc);
+impl InternValueTrivial for MacroCallLoc {}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroDefId {
@@ -186,11 +187,11 @@ pub struct MacroDefId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum MacroDefKind {
     Declarative(AstId<ast::Macro>),
-    BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
-    BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
-    BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
-    BuiltInEager(EagerExpander, AstId<ast::Macro>),
-    ProcMacro(CustomProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
+    BuiltIn(AstId<ast::Macro>, BuiltinFnLikeExpander),
+    BuiltInAttr(AstId<ast::Macro>, BuiltinAttrExpander),
+    BuiltInDerive(AstId<ast::Macro>, BuiltinDeriveExpander),
+    BuiltInEager(AstId<ast::Macro>, EagerExpander),
+    ProcMacro(AstId<ast::Fn>, CustomProcMacroExpander, ProcMacroKind),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -252,9 +253,6 @@ pub trait HirFileIdExt {
     /// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
     fn original_call_node(self, db: &dyn ExpandDatabase) -> Option<InRealFile<SyntaxNode>>;
 
-    /// Return expansion information if it is a macro-expansion file
-    fn expansion_info(self, db: &dyn ExpandDatabase) -> Option<ExpansionInfo>;
-
     fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option<InFile<ast::Attr>>;
 }
 
@@ -308,11 +306,6 @@ impl HirFileIdExt for HirFileId {
         }
     }
 
-    /// Return expansion information if it is a macro-expansion file
-    fn expansion_info(self, db: &dyn ExpandDatabase) -> Option<ExpansionInfo> {
-        Some(ExpansionInfo::new(db, self.macro_file()?))
-    }
-
     fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option<InFile<ast::Attr>> {
         let macro_file = self.macro_file()?;
         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
@@ -379,7 +372,7 @@ impl MacroFileIdExt for MacroFileId {
     fn is_custom_derive(&self, db: &dyn ExpandDatabase) -> bool {
         matches!(
             db.lookup_intern_macro_call(self.macro_call_id).def.kind,
-            MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)
+            MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive)
         )
     }
 
@@ -416,8 +409,10 @@ impl MacroFileIdExt for MacroFileId {
     }
 
     fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool {
-        let loc = db.lookup_intern_macro_call(self.macro_call_id);
-        matches!(loc.kind, MacroCallKind::Attr { .. })
+        matches!(
+            db.lookup_intern_macro_call(self.macro_call_id).def.kind,
+            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr)
+        )
     }
 
     fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool {
@@ -440,13 +435,13 @@ impl MacroDefId {
     pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile<TextRange> {
         match self.kind {
             MacroDefKind::Declarative(id)
-            | MacroDefKind::BuiltIn(_, id)
-            | MacroDefKind::BuiltInAttr(_, id)
-            | MacroDefKind::BuiltInDerive(_, id)
-            | MacroDefKind::BuiltInEager(_, id) => {
+            | MacroDefKind::BuiltIn(id, _)
+            | MacroDefKind::BuiltInAttr(id, _)
+            | MacroDefKind::BuiltInDerive(id, _)
+            | MacroDefKind::BuiltInEager(id, _) => {
                 id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range())
             }
-            MacroDefKind::ProcMacro(_, _, id) => {
+            MacroDefKind::ProcMacro(id, _, _) => {
                 id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range())
             }
         }
@@ -454,12 +449,12 @@ impl MacroDefId {
 
     pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
         match self.kind {
-            MacroDefKind::ProcMacro(.., id) => Either::Right(id),
+            MacroDefKind::ProcMacro(id, ..) => Either::Right(id),
             MacroDefKind::Declarative(id)
-            | MacroDefKind::BuiltIn(_, id)
-            | MacroDefKind::BuiltInAttr(_, id)
-            | MacroDefKind::BuiltInDerive(_, id)
-            | MacroDefKind::BuiltInEager(_, id) => Either::Left(id),
+            | MacroDefKind::BuiltIn(id, _)
+            | MacroDefKind::BuiltInAttr(id, _)
+            | MacroDefKind::BuiltInDerive(id, _)
+            | MacroDefKind::BuiltInEager(id, _) => Either::Left(id),
         }
     }
 
@@ -470,7 +465,7 @@ impl MacroDefId {
     pub fn is_attribute(&self) -> bool {
         matches!(
             self.kind,
-            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _)
+            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr)
         )
     }
 
@@ -478,7 +473,7 @@ impl MacroDefId {
         matches!(
             self.kind,
             MacroDefKind::BuiltInDerive(..)
-                | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)
+                | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive)
         )
     }
 
@@ -486,26 +481,26 @@ impl MacroDefId {
         matches!(
             self.kind,
             MacroDefKind::BuiltIn(..)
-                | MacroDefKind::ProcMacro(_, ProcMacroKind::Bang, _)
+                | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Bang)
                 | MacroDefKind::BuiltInEager(..)
                 | MacroDefKind::Declarative(..)
         )
     }
 
     pub fn is_attribute_derive(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
+        matches!(self.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive())
     }
 
     pub fn is_include(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include())
+        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include())
     }
 
     pub fn is_include_like(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include_like())
+        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include_like())
     }
 
     pub fn is_env_or_option_env(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_env_or_option_env())
+        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_env_or_option_env())
     }
 }
 
@@ -702,16 +697,12 @@ impl MacroCallKind {
 // simpler function calls if the map is only used once
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ExpansionInfo {
-    pub expanded: InMacroFile<SyntaxNode>,
+    expanded: InMacroFile<SyntaxNode>,
     /// The argument TokenTree or item for attributes
     arg: InFile<Option<SyntaxNode>>,
-    /// The `macro_rules!` or attribute input.
-    attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
-
-    macro_def: TokenExpander,
-    macro_arg: Arc<tt::Subtree>,
-    pub exp_map: Arc<ExpansionSpanMap>,
+    exp_map: Arc<ExpansionSpanMap>,
     arg_map: SpanMap,
+    loc: MacroCallLoc,
 }
 
 impl ExpansionInfo {
@@ -719,14 +710,21 @@ impl ExpansionInfo {
         self.expanded.clone()
     }
 
-    pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
-        Some(self.arg.with_value(self.arg.value.as_ref()?.parent()?))
+    pub fn arg(&self) -> InFile<Option<&SyntaxNode>> {
+        self.arg.as_ref().map(|it| it.as_ref())
     }
 
     pub fn call_file(&self) -> HirFileId {
         self.arg.file_id
     }
 
+    pub fn is_attr(&self) -> bool {
+        matches!(
+            self.loc.def.kind,
+            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr)
+        )
+    }
+
     /// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
     ///
     /// Note this does a linear search through the entire backing vector of the spanmap.
@@ -811,49 +809,16 @@ impl ExpansionInfo {
     }
 
     pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo {
-        let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
+        let _p = tracing::info_span!("ExpansionInfo::new").entered();
+        let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 
         let arg_tt = loc.kind.arg(db);
         let arg_map = db.span_map(arg_tt.file_id);
 
-        let macro_def = db.macro_expander(loc.def);
         let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
         let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
 
-        let (macro_arg, _, _) =
-            db.macro_arg_considering_derives(macro_file.macro_call_id, &loc.kind);
-
-        let def = loc.def.ast_id().left().and_then(|id| {
-            let def_tt = match id.to_node(db) {
-                ast::Macro::MacroRules(mac) => mac.token_tree()?,
-                ast::Macro::MacroDef(_) if matches!(macro_def, TokenExpander::BuiltInAttr(_)) => {
-                    return None
-                }
-                ast::Macro::MacroDef(mac) => mac.body()?,
-            };
-            Some(InFile::new(id.file_id, def_tt))
-        });
-        let attr_input_or_mac_def = def.or_else(|| match loc.kind {
-            MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
-                // FIXME: handle `cfg_attr`
-                let tt = collect_attrs(&ast_id.to_node(db))
-                    .nth(invoc_attr_index.ast_index())
-                    .and_then(|x| Either::left(x.1))?
-                    .token_tree()?;
-                Some(InFile::new(ast_id.file_id, tt))
-            }
-            _ => None,
-        });
-
-        ExpansionInfo {
-            expanded,
-            arg: arg_tt,
-            attr_input_or_mac_def,
-            macro_arg,
-            macro_def,
-            exp_map,
-            arg_map,
-        }
+        ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index 46f8c2b9d8c..12fdf88a2a8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -44,6 +44,10 @@ pub enum PathKind {
     DollarCrate(CrateId),
 }
 
+impl PathKind {
+    pub const SELF: PathKind = PathKind::Super(0);
+}
+
 impl ModPath {
     pub fn from_src(
         db: &dyn ExpandDatabase,
@@ -96,7 +100,7 @@ impl ModPath {
     pub fn textual_len(&self) -> usize {
         let base = match self.kind {
             PathKind::Plain => 0,
-            PathKind::Super(0) => "self".len(),
+            PathKind::SELF => "self".len(),
             PathKind::Super(i) => "super".len() * i as usize,
             PathKind::Crate => "crate".len(),
             PathKind::Abs => 0,
@@ -113,7 +117,7 @@ impl ModPath {
     }
 
     pub fn is_self(&self) -> bool {
-        self.kind == PathKind::Super(0) && self.segments.is_empty()
+        self.kind == PathKind::SELF && self.segments.is_empty()
     }
 
     #[allow(non_snake_case)]
@@ -193,7 +197,7 @@ fn display_fmt_path(
     };
     match path.kind {
         PathKind::Plain => {}
-        PathKind::Super(0) => add_segment("self")?,
+        PathKind::SELF => add_segment("self")?,
         PathKind::Super(n) => {
             for _ in 0..n {
                 add_segment("super")?;
@@ -316,7 +320,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
         tt::Leaf::Ident(tt::Ident { text, span }) if text == "$crate" => {
             resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate)
         }
-        tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::Super(0),
+        tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF,
         tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
             let mut deg = 1;
             while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
index a31a111c911..8f1e32321e1 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
@@ -231,7 +231,7 @@ mod tests {
 
     const DUMMY: tt::Span = tt::Span {
         range: TextRange::empty(TextSize::new(0)),
-        anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID },
+        anchor: SpanAnchor { file_id: FileId::from_raw(0xe4e4e), ast_id: ROOT_ERASED_FILE_AST_ID },
         ctx: SyntaxContextId::ROOT,
     };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index e2446c34254..b706cef0b3a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -143,7 +143,7 @@ pub(crate) fn deref_by_trait(
     table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
     ty: Ty,
 ) -> Option<Ty> {
-    let _p = tracing::span!(tracing::Level::INFO, "deref_by_trait").entered();
+    let _p = tracing::info_span!("deref_by_trait").entered();
     if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
         // don't try to deref unknown variables
         return None;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index 41acd3555eb..52411f94ad0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -14,10 +14,10 @@ use hir_def::{
 use smallvec::SmallVec;
 
 use crate::{
-    consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime,
-    infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics,
-    Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
-    Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
+    consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, generics::generics,
+    infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, Binders,
+    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
+    TraitRef, Ty, TyDefId, TyExt, TyKind,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -246,6 +246,7 @@ impl TyBuilder<()> {
     /// - yield type of coroutine ([`Coroutine::Yield`](std::ops::Coroutine::Yield))
     /// - return type of coroutine ([`Coroutine::Return`](std::ops::Coroutine::Return))
     /// - generic parameters in scope on `parent`
+    ///
     /// in this order.
     ///
     /// This method prepopulates the builder with placeholder substitution of `parent`, so you
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 84ac8740ecd..debae1fe123 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -20,13 +20,14 @@ use hir_expand::name::name;
 use crate::{
     db::{HirDatabase, InternedCoroutine},
     display::HirDisplay,
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
-    make_single_type_binders,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
+    generics::generics,
+    make_binders, make_single_type_binders,
     mapping::{from_chalk, ToChalk, TypeAliasAsValue},
     method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
     to_assoc_type_id, to_chalk_trait_id,
     traits::ChalkContext,
-    utils::{generics, ClosureSubst},
+    utils::ClosureSubst,
     wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
     Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
     TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
@@ -603,7 +604,6 @@ pub(crate) fn associated_ty_data_query(
     // Lower bounds -- we could/should maybe move this to a separate query in `lower`
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
-    // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
         .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
@@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query(
     krate: CrateId,
     impl_id: ImplId,
 ) -> Arc<ImplDatum> {
-    let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered();
+    let _p = tracing::info_span!("impl_datum_query").entered();
     debug!("impl_datum {:?}", impl_id);
     let impl_: hir_def::ImplId = from_chalk(db, impl_id);
     impl_def_datum(db, krate, impl_id, impl_)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index d99ef6679e5..4279c756519 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -12,12 +12,10 @@ use hir_def::{
 };
 
 use crate::{
-    db::HirDatabase,
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
-    to_chalk_trait_id,
-    utils::{generics, ClosureSubst},
-    AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
-    ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
+    db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
+    from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, AdtId,
+    AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId,
+    DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
 };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index f09277a92e6..8b6cde975f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -15,10 +15,9 @@ use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
-    mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
-    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
-    TyBuilder,
+    db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode,
+    mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue,
+    GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder,
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -72,12 +71,12 @@ impl From<MirEvalError> for ConstEvalError {
     }
 }
 
-pub(crate) fn path_to_const(
+pub(crate) fn path_to_const<'g>(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
     mode: ParamLoweringMode,
-    args: impl FnOnce() -> Option<Generics>,
+    args: impl FnOnce() -> Option<&'g Generics>,
     debruijn: DebruijnIndex,
     expected_ty: Ty,
 ) -> Option<Const> {
@@ -90,7 +89,7 @@ pub(crate) fn path_to_const(
                 }
                 ParamLoweringMode::Variable => {
                     let args = args();
-                    match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) {
+                    match args.and_then(|args| args.type_or_const_param_idx(p.into())) {
                         Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
                         None => {
                             never!(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index d1ffd5046c3..1b4584a18d7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -73,7 +73,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
         Ok(t) => t,
         Err(e) => {
             let err = pretty_print_err(e, db);
-            panic!("Error in evaluating goal: {}", err);
+            panic!("Error in evaluating goal: {err}");
         }
     };
     match &r.data(Interner).value {
@@ -81,7 +81,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
             ConstScalar::Bytes(b, mm) => {
                 check(b, mm);
             }
-            x => panic!("Expected number but found {:?}", x),
+            x => panic!("Expected number but found {x:?}"),
         },
         _ => panic!("result of const eval wasn't a concrete const"),
     }
@@ -89,7 +89,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
 
 fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
     let mut err = String::new();
-    let span_formatter = |file, range| format!("{:?} {:?}", file, range);
+    let span_formatter = |file, range| format!("{file:?} {range:?}");
     match e {
         ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter),
         ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 90bf46b5056..e951048021d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -5,7 +5,7 @@ use std::sync;
 
 use base_db::{
     impl_intern_key,
-    salsa::{self, impl_intern_value_trivial},
+    salsa::{self, InternValueTrivial},
     CrateId, Upcast,
 };
 use hir_def::{
@@ -21,11 +21,12 @@ use crate::{
     chalk_db,
     consteval::ConstEvalError,
     layout::{Layout, LayoutError},
+    lower::{GenericDefaults, GenericPredicates},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
-    Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits,
-    InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment,
-    TraitRef, Ty, TyDefId, ValueTyDefId,
+    Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult,
+    Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty,
+    TyDefId, ValueTyDefId,
 };
 use hir_expand::name::Name;
 
@@ -147,7 +148,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     ) -> Arc<[Binders<QuantifiedWhereClause>]>;
 
     #[salsa::invoke(crate::lower::generic_predicates_query)]
-    fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<QuantifiedWhereClause>]>;
+    fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
 
     #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
     #[salsa::transparent]
@@ -158,7 +159,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
 
     #[salsa::invoke(crate::lower::generic_defaults_query)]
     #[salsa::cycle(crate::lower::generic_defaults_recover)]
-    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
+    fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
 
     #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
     fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
@@ -298,7 +299,8 @@ impl_intern_key!(InternedClosureId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedClosure(pub DefWithBodyId, pub ExprId);
-impl_intern_value_trivial!(InternedClosure);
+
+impl InternValueTrivial for InternedClosure {}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedCoroutineId(salsa::InternId);
@@ -306,7 +308,7 @@ impl_intern_key!(InternedCoroutineId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
-impl_intern_value_trivial!(InternedCoroutine);
+impl InternValueTrivial for InternedCoroutine {}
 
 /// This exists just for Chalk, because Chalk just has a single `FnDefId` where
 /// we have different IDs for struct and enum variant constructors.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index ecbb1d4c60e..15ecf9aafcf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -43,7 +43,7 @@ mod allow {
 }
 
 pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
-    let _p = tracing::span!(tracing::Level::INFO, "incorrect_case").entered();
+    let _p = tracing::info_span!("incorrect_case").entered();
     let mut validator = DeclValidator::new(db);
     validator.validate_item(owner);
     validator.sink
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index a5a42c52af0..ce3fa53f7ad 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -65,8 +65,7 @@ impl BodyValidationDiagnostic {
         owner: DefWithBodyId,
         validate_lints: bool,
     ) -> Vec<BodyValidationDiagnostic> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered();
+        let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered();
         let infer = db.infer(owner);
         let body = db.body(owner);
         let mut validator =
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 081b4d83a86..22aa5c69bb0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -13,7 +13,7 @@ use crate::{
 };
 
 pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
-    let _p = tracing::span!(tracing::Level::INFO, "missing_unsafe").entered();
+    let _p = tracing::info_span!("missing_unsafe").entered();
 
     let mut res = Vec::new();
     let is_unsafe = match def {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 241690d0089..66b5398b88e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -4,7 +4,7 @@
 
 use std::{
     fmt::{self, Debug},
-    mem::size_of,
+    mem::{self, size_of},
 };
 
 use base_db::CrateId;
@@ -36,12 +36,13 @@ use crate::{
     consteval::try_const_usize,
     db::{HirDatabase, InternedClosure},
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
+    generics::generics,
     layout::Layout,
     lt_from_placeholder_idx,
     mapping::from_chalk,
     mir::pad16,
     primitive, to_assoc_type_id,
-    utils::{self, detect_variant_from_bytes, generics, ClosureSubst},
+    utils::{self, detect_variant_from_bytes, ClosureSubst},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const,
     ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime,
     LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
@@ -74,6 +75,8 @@ pub struct HirFormatter<'a> {
     /// When rendering something that has a concept of "children" (like fields in a struct), this limits
     /// how many should be rendered.
     pub entity_limit: Option<usize>,
+    /// When rendering functions, whether to show the constraint from the container
+    show_container_bounds: bool,
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
@@ -101,6 +104,7 @@ pub trait HirDisplay {
         omit_verbose_types: bool,
         display_target: DisplayTarget,
         closure_style: ClosureStyle,
+        show_container_bounds: bool,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -117,6 +121,7 @@ pub trait HirDisplay {
             omit_verbose_types,
             display_target,
             closure_style,
+            show_container_bounds,
         }
     }
 
@@ -134,6 +139,7 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
+            show_container_bounds: false,
         }
     }
 
@@ -155,6 +161,7 @@ pub trait HirDisplay {
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
+            show_container_bounds: false,
         }
     }
 
@@ -176,6 +183,7 @@ pub trait HirDisplay {
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
+            show_container_bounds: false,
         }
     }
 
@@ -198,6 +206,7 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
+            show_container_bounds: false,
         }) {
             Ok(()) => {}
             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -219,6 +228,29 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Test,
+            show_container_bounds: false,
+        }
+    }
+
+    /// Returns a String representation of `self` that shows the constraint from
+    /// the container for functions
+    fn display_with_container_bounds<'a>(
+        &'a self,
+        db: &'a dyn HirDatabase,
+        show_container_bounds: bool,
+    ) -> HirDisplayWrapper<'a, Self>
+    where
+        Self: Sized,
+    {
+        HirDisplayWrapper {
+            db,
+            t: self,
+            max_size: None,
+            limited_size: None,
+            omit_verbose_types: false,
+            closure_style: ClosureStyle::ImplFn,
+            display_target: DisplayTarget::Diagnostics,
+            show_container_bounds,
         }
     }
 }
@@ -277,6 +309,10 @@ impl HirFormatter<'_> {
     pub fn omit_verbose_types(&self) -> bool {
         self.omit_verbose_types
     }
+
+    pub fn show_container_bounds(&self) -> bool {
+        self.show_container_bounds
+    }
 }
 
 #[derive(Clone, Copy)]
@@ -336,6 +372,7 @@ pub struct HirDisplayWrapper<'a, T> {
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
+    show_container_bounds: bool,
 }
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -365,6 +402,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
             omit_verbose_types: self.omit_verbose_types,
             display_target: self.display_target,
             closure_style: self.closure_style,
+            show_container_bounds: self.show_container_bounds,
         })
     }
 
@@ -423,7 +461,7 @@ impl HirDisplay for ProjectionTy {
         let proj_params_count =
             self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
         let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
-        hir_fmt_generics(f, proj_params, None)
+        hir_fmt_generics(f, proj_params, None, None)
     }
 }
 
@@ -456,7 +494,7 @@ impl HirDisplay for Const {
             ConstValue::Placeholder(idx) => {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params[id.local_id];
+                let param_data = &generics[id.local_id];
                 write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?;
                 Ok(())
             }
@@ -468,6 +506,7 @@ impl HirDisplay for Const {
                         f,
                         parameters.as_slice(Interner),
                         c.generic_def(f.db.upcast()),
+                        None,
                     )?;
                     Ok(())
                 }
@@ -670,7 +709,7 @@ fn render_const_scalar(
         TyKind::FnDef(..) => ty.hir_fmt(f),
         TyKind::Function(_) | TyKind::Raw(_, _) => {
             let it = u128::from_le_bytes(pad16(b, false));
-            write!(f, "{:#X} as ", it)?;
+            write!(f, "{it:#X} as ")?;
             ty.hir_fmt(f)
         }
         TyKind::Array(ty, len) => {
@@ -950,7 +989,7 @@ impl HirDisplay for Ty {
 
                 if parameters.len(Interner) > 0 {
                     let generics = generics(db.upcast(), def.into());
-                    let (parent_len, self_, type_, const_, impl_, lifetime) =
+                    let (parent_len, self_param, type_, const_, impl_, lifetime) =
                         generics.provenance_split();
                     let parameters = parameters.as_slice(Interner);
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
@@ -958,7 +997,7 @@ impl HirDisplay for Ty {
                         // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
                         // parent's params (those from enclosing impl or trait, if any).
                         let (fn_params, other) =
-                            parameters.split_at(self_ + type_ + const_ + lifetime);
+                            parameters.split_at(self_param as usize + type_ + const_ + lifetime);
                         let (_impl, parent_params) = other.split_at(impl_);
                         debug_assert_eq!(parent_params.len(), parent_len);
 
@@ -967,11 +1006,11 @@ impl HirDisplay for Ty {
                         let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params);
 
                         write!(f, "<")?;
-                        hir_fmt_generic_arguments(f, parent_params)?;
+                        hir_fmt_generic_arguments(f, parent_params, None)?;
                         if !parent_params.is_empty() && !fn_params.is_empty() {
                             write!(f, ", ")?;
                         }
-                        hir_fmt_generic_arguments(f, fn_params)?;
+                        hir_fmt_generic_arguments(f, fn_params, None)?;
                         write!(f, ">")?;
                     }
                 }
@@ -1016,7 +1055,7 @@ impl HirDisplay for Ty {
 
                 let generic_def = self.as_generic_def(db);
 
-                hir_fmt_generics(f, parameters.as_slice(Interner), generic_def)?;
+                hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?;
             }
             TyKind::AssociatedType(assoc_type_id, parameters) => {
                 let type_alias = from_assoc_type_id(*assoc_type_id);
@@ -1039,7 +1078,7 @@ impl HirDisplay for Ty {
                     f.end_location_link();
                     // Note that the generic args for the associated type come before those for the
                     // trait (including the self type).
-                    hir_fmt_generics(f, parameters.as_slice(Interner), None)
+                    hir_fmt_generics(f, parameters.as_slice(Interner), None, None)
                 } else {
                     let projection_ty = ProjectionTy {
                         associated_ty_id: to_assoc_type_id(type_alias),
@@ -1141,7 +1180,7 @@ impl HirDisplay for Ty {
                     }
                     ClosureStyle::ClosureWithSubst => {
                         write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
-                        return hir_fmt_generics(f, substs.as_slice(Interner), None);
+                        return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
                     }
                     _ => (),
                 }
@@ -1177,7 +1216,7 @@ impl HirDisplay for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(db, *idx);
                 let generics = generics(db.upcast(), id.parent);
-                let param_data = &generics.params[id.local_id];
+                let param_data = &generics[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
@@ -1329,6 +1368,7 @@ fn hir_fmt_generics(
     f: &mut HirFormatter<'_>,
     parameters: &[GenericArg],
     generic_def: Option<hir_def::GenericDefId>,
+    self_: Option<&Ty>,
 ) -> Result<(), HirDisplayError> {
     if parameters.is_empty() {
         return Ok(());
@@ -1348,7 +1388,7 @@ fn hir_fmt_generics(
         });
     if !parameters_to_write.is_empty() && !only_err_lifetimes {
         write!(f, "<")?;
-        hir_fmt_generic_arguments(f, parameters_to_write)?;
+        hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
         write!(f, ">")?;
     }
 
@@ -1411,6 +1451,7 @@ fn generic_args_sans_defaults<'ga>(
 fn hir_fmt_generic_arguments(
     f: &mut HirFormatter<'_>,
     parameters: &[GenericArg],
+    self_: Option<&Ty>,
 ) -> Result<(), HirDisplayError> {
     let mut first = true;
     let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
@@ -1432,11 +1473,13 @@ fn hir_fmt_generic_arguments(
             continue;
         }
 
-        if !first {
+        if !mem::take(&mut first) {
             write!(f, ", ")?;
         }
-        first = false;
-        generic_arg.hir_fmt(f)?;
+        match self_ {
+            self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
+            _ => generic_arg.hir_fmt(f)?,
+        }
     }
     Ok(())
 }
@@ -1559,12 +1602,16 @@ fn write_bounds_like_dyn_trait(
                 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
                 f.end_location_link();
                 if is_fn_trait {
-                    if let [_self, params @ ..] = trait_ref.substitution.as_slice(Interner) {
+                    if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
                         if let Some(args) =
                             params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
                         {
                             write!(f, "(")?;
-                            hir_fmt_generic_arguments(f, args.as_slice(Interner))?;
+                            hir_fmt_generic_arguments(
+                                f,
+                                args.as_slice(Interner),
+                                self_.ty(Interner),
+                            )?;
                             write!(f, ")")?;
                         }
                     }
@@ -1574,10 +1621,10 @@ fn write_bounds_like_dyn_trait(
                         Some(trait_.into()),
                         trait_ref.substitution.as_slice(Interner),
                     );
-                    if let [_self, params @ ..] = params {
+                    if let [self_, params @ ..] = params {
                         if !params.is_empty() {
                             write!(f, "<")?;
-                            hir_fmt_generic_arguments(f, params)?;
+                            hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
                             // there might be assoc type bindings, so we leave the angle brackets open
                             angle_open = true;
                         }
@@ -1635,6 +1682,7 @@ fn write_bounds_like_dyn_trait(
                         hir_fmt_generic_arguments(
                             f,
                             &proj.substitution.as_slice(Interner)[..proj_arg_count],
+                            None,
                         )?;
                         write!(f, ">")?;
                     }
@@ -1691,7 +1739,8 @@ fn fmt_trait_ref(
     f.start_location_link(trait_.into());
     write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
     f.end_location_link();
-    hir_fmt_generics(f, &tr.substitution.as_slice(Interner)[1..], None)
+    let substs = tr.substitution.as_slice(Interner);
+    hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
 }
 
 impl HirDisplay for TraitRef {
@@ -1749,7 +1798,7 @@ impl HirDisplay for LifetimeData {
             LifetimeData::Placeholder(idx) => {
                 let id = lt_from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params[id.local_id];
+                let param_data = &generics[id.local_id];
                 write!(f, "{}", param_data.name.display(f.db.upcast()))?;
                 Ok(())
             }
@@ -1943,7 +1992,7 @@ impl HirDisplay for Path {
             (_, PathKind::Plain) => {}
             (_, PathKind::Abs) => {}
             (_, PathKind::Crate) => write!(f, "crate")?,
-            (_, PathKind::Super(0)) => write!(f, "self")?,
+            (_, &PathKind::SELF) => write!(f, "self")?,
             (_, PathKind::Super(n)) => {
                 for i in 0..*n {
                     if i > 0 {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
new file mode 100644
index 00000000000..ea10e6881e7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -0,0 +1,263 @@
+//! Utilities for working with generics.
+//!
+//! The layout for generics as expected by chalk are as follows:
+//! - Optional Self parameter
+//! - Type or Const parameters
+//! - Lifetime parameters
+//! - Parent parameters
+//!
+//! where parent follows the same scheme.
+use std::ops;
+
+use chalk_ir::{cast::Cast as _, BoundVar, DebruijnIndex};
+use hir_def::{
+    db::DefDatabase,
+    generics::{
+        GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
+        TypeParamProvenance,
+    },
+    ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
+    LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
+};
+use intern::Interned;
+
+use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
+
+pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
+    let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
+    Generics { def, params: db.generic_params(def), parent_generics }
+}
+#[derive(Clone, Debug)]
+pub(crate) struct Generics {
+    def: GenericDefId,
+    params: Interned<GenericParams>,
+    parent_generics: Option<Box<Generics>>,
+}
+
+impl<T> ops::Index<T> for Generics
+where
+    GenericParams: ops::Index<T>,
+{
+    type Output = <GenericParams as ops::Index<T>>::Output;
+    fn index(&self, index: T) -> &Self::Output {
+        &self.params[index]
+    }
+}
+
+impl Generics {
+    pub(crate) fn def(&self) -> GenericDefId {
+        self.def
+    }
+
+    pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
+        self.iter_self_id().chain(self.iter_parent_id())
+    }
+
+    pub(crate) fn iter_self_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
+        self.iter_self().map(|(id, _)| id)
+    }
+
+    fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
+        self.iter_parent().map(|(id, _)| id)
+    }
+
+    pub(crate) fn iter_self_type_or_consts(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
+        self.params.iter_type_or_consts()
+    }
+
+    /// Iterate over the params followed by the parent params.
+    pub(crate) fn iter(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
+        self.iter_self().chain(self.iter_parent())
+    }
+
+    /// Iterate over the params without parent params.
+    pub(crate) fn iter_self(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
+        self.params
+            .iter_type_or_consts()
+            .map(from_toc_id(self))
+            .chain(self.params.iter_lt().map(from_lt_id(self)))
+    }
+
+    /// Iterator over types and const params of parent.
+    fn iter_parent(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
+        self.parent_generics().into_iter().flat_map(|it| {
+            let lt_iter = it.params.iter_lt().map(from_lt_id(it));
+            it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter)
+        })
+    }
+
+    /// Returns total number of generic parameters in scope, including those from parent.
+    pub(crate) fn len(&self) -> usize {
+        let parent = self.parent_generics().map_or(0, Generics::len);
+        let child = self.params.len();
+        parent + child
+    }
+
+    /// Returns numbers of generic parameters excluding those from parent.
+    pub(crate) fn len_self(&self) -> usize {
+        self.params.len()
+    }
+
+    /// (parent total, self param, type params, const params, impl trait list, lifetimes)
+    pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) {
+        let mut self_param = false;
+        let mut type_params = 0;
+        let mut impl_trait_params = 0;
+        let mut const_params = 0;
+        self.params.iter_type_or_consts().for_each(|(_, data)| match data {
+            TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+                TypeParamProvenance::TypeParamList => type_params += 1,
+                TypeParamProvenance::TraitSelf => self_param |= true,
+                TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
+            },
+            TypeOrConstParamData::ConstParamData(_) => const_params += 1,
+        });
+
+        let lifetime_params = self.params.iter_lt().count();
+
+        let parent_len = self.parent_generics().map_or(0, Generics::len);
+        (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params)
+    }
+
+    pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
+        self.find_type_or_const_param(param)
+    }
+
+    fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> {
+        if param.parent == self.def {
+            let idx = param.local_id.into_raw().into_u32() as usize;
+            debug_assert!(idx <= self.params.type_or_consts.len());
+            Some(idx)
+        } else {
+            debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent));
+            self.parent_generics()
+                .and_then(|g| g.find_type_or_const_param(param))
+                // Remember that parent parameters come after parameters for self.
+                .map(|idx| self.len_self() + idx)
+        }
+    }
+
+    pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
+        self.find_lifetime(lifetime)
+    }
+
+    fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> {
+        if lifetime.parent == self.def {
+            let idx = lifetime.local_id.into_raw().into_u32() as usize;
+            debug_assert!(idx <= self.params.lifetimes.len());
+            Some(self.params.type_or_consts.len() + idx)
+        } else {
+            debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent));
+            self.parent_generics()
+                .and_then(|g| g.find_lifetime(lifetime))
+                .map(|idx| self.len_self() + idx)
+        }
+    }
+
+    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
+        self.parent_generics.as_deref()
+    }
+
+    pub(crate) fn parent_or_self(&self) -> &Generics {
+        self.parent_generics.as_deref().unwrap_or(self)
+    }
+
+    /// Returns a Substitution that replaces each parameter by a bound variable.
+    pub(crate) fn bound_vars_subst(
+        &self,
+        db: &dyn HirDatabase,
+        debruijn: DebruijnIndex,
+    ) -> Substitution {
+        Substitution::from_iter(
+            Interner,
+            self.iter_id().enumerate().map(|(idx, id)| match id {
+                GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
+                GenericParamId::TypeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
+                }
+                GenericParamId::LifetimeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
+                }
+            }),
+        )
+    }
+
+    /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
+    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
+        Substitution::from_iter(
+            Interner,
+            self.iter_id().map(|id| match id {
+                GenericParamId::TypeParamId(id) => {
+                    to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
+                }
+                GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into())
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
+                GenericParamId::LifetimeParamId(id) => {
+                    lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
+                }
+            }),
+        )
+    }
+}
+
+fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
+    let container = match def {
+        GenericDefId::FunctionId(it) => it.lookup(db).container,
+        GenericDefId::TypeAliasId(it) => it.lookup(db).container,
+        GenericDefId::ConstId(it) => it.lookup(db).container,
+        GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()),
+        GenericDefId::AdtId(_)
+        | GenericDefId::TraitId(_)
+        | GenericDefId::ImplId(_)
+        | GenericDefId::TraitAliasId(_) => return None,
+    };
+
+    match container {
+        ItemContainerId::ImplId(it) => Some(it.into()),
+        ItemContainerId::TraitId(it) => Some(it.into()),
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+    }
+}
+
+fn from_toc_id<'a>(
+    it: &'a Generics,
+) -> impl Fn(
+    (LocalTypeOrConstParamId, &'a TypeOrConstParamData),
+) -> (GenericParamId, GenericParamDataRef<'a>) {
+    move |(local_id, p): (_, _)| {
+        let id = TypeOrConstParamId { parent: it.def, local_id };
+        match p {
+            TypeOrConstParamData::TypeParamData(p) => (
+                GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                GenericParamDataRef::TypeParamData(p),
+            ),
+            TypeOrConstParamData::ConstParamData(p) => (
+                GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                GenericParamDataRef::ConstParamData(p),
+            ),
+        }
+    }
+}
+
+fn from_lt_id<'a>(
+    it: &'a Generics,
+) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>)
+{
+    move |(local_id, p): (_, _)| {
+        (
+            GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+            GenericParamDataRef::LifetimeParamData(p),
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 6f2f70dd40a..96431ba4ce9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -49,6 +49,7 @@ use hir_def::{
 use hir_expand::name::{name, Name};
 use indexmap::IndexSet;
 use la_arena::{ArenaMap, Entry};
+use once_cell::unsync::OnceCell;
 use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::{always, never};
 use triomphe::Arc;
@@ -56,14 +57,15 @@ use triomphe::Arc;
 use crate::{
     db::HirDatabase,
     error_lifetime, fold_tys,
+    generics::Generics,
     infer::{coerce::CoerceMany, unify::InferenceTable},
     lower::ImplTraitLoweringMode,
     to_assoc_type_id,
     traits::FnTrait,
-    utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
+    utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
-    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution,
-    TraitEnvironment, Ty, TyBuilder, TyExt,
+    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy,
+    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -79,7 +81,7 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
 
 /// The entry point of type inference.
 pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
-    let _p = tracing::span!(tracing::Level::INFO, "infer_query").entered();
+    let _p = tracing::info_span!("infer_query").entered();
     let resolver = def.resolver(db.upcast());
     let body = db.body(def);
     let mut ctx = InferenceContext::new(db, def, &body, resolver);
@@ -526,6 +528,7 @@ pub(crate) struct InferenceContext<'a> {
     pub(crate) owner: DefWithBodyId,
     pub(crate) body: &'a Body,
     pub(crate) resolver: Resolver,
+    generics: OnceCell<Option<Generics>>,
     table: unify::InferenceTable<'a>,
     /// The traits in scope, disregarding block modules. This is used for caching purposes.
     traits_in_scope: FxHashSet<TraitId>,
@@ -611,6 +614,7 @@ impl<'a> InferenceContext<'a> {
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
         InferenceContext {
+            generics: OnceCell::new(),
             result: InferenceResult::default(),
             table: unify::InferenceTable::new(db, trait_env),
             tuple_field_accesses_rev: Default::default(),
@@ -632,8 +636,14 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    pub(crate) fn generics(&self) -> Option<Generics> {
-        Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?))
+    pub(crate) fn generics(&self) -> Option<&Generics> {
+        self.generics
+            .get_or_init(|| {
+                self.resolver
+                    .generic_def()
+                    .map(|def| crate::generics::generics(self.db.upcast(), def))
+            })
+            .as_ref()
     }
 
     // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
@@ -781,7 +791,8 @@ impl<'a> InferenceContext<'a> {
 
     fn collect_fn(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into())
+        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
+            .with_type_param_mode(ParamLoweringMode::Placeholder)
             .with_impl_trait_mode(ImplTraitLoweringMode::Param);
         let mut param_tys =
             data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
@@ -816,6 +827,7 @@ impl<'a> InferenceContext<'a> {
         let return_ty = &*data.ret_type;
 
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
+            .with_type_param_mode(ParamLoweringMode::Placeholder)
             .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
         let return_ty = ctx.lower_ty(return_ty);
         let return_ty = self.insert_type_vars(return_ty);
@@ -1263,7 +1275,7 @@ impl<'a> InferenceContext<'a> {
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
             }
             TypeNs::SelfType(impl_id) => {
-                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
+                let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
                 let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index a25498eff33..b7c7b665453 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -22,11 +22,13 @@ use stdx::never;
 
 use crate::{
     db::{HirDatabase, InternedClosure},
-    error_lifetime, from_chalk_trait_id, from_placeholder_idx, make_binders,
+    error_lifetime, from_chalk_trait_id, from_placeholder_idx,
+    generics::Generics,
+    make_binders,
     mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
     to_chalk_trait_id,
     traits::FnTrait,
-    utils::{self, elaborate_clause_supertraits, Generics},
+    utils::{self, elaborate_clause_supertraits},
     Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy,
     DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty,
     TyExt, WhereClause,
@@ -337,7 +339,7 @@ impl CapturedItemWithoutTy {
         fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders<Ty> {
             struct Filler<'a> {
                 db: &'a dyn HirDatabase,
-                generics: Generics,
+                generics: &'a Generics,
             }
             impl FallibleTypeFolder<Interner> for Filler<'_> {
                 type Error = ();
@@ -380,7 +382,7 @@ impl CapturedItemWithoutTy {
             };
             let filler = &mut Filler { db: ctx.db, generics };
             let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
-            make_binders(ctx.db, &filler.generics, result)
+            make_binders(ctx.db, filler.generics, result)
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 4c12786362f..95f28531acf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -24,6 +24,7 @@ use crate::{
     consteval,
     db::{InternedClosure, InternedCoroutine},
     error_lifetime,
+    generics::{generics, Generics},
     infer::{
         coerce::{CoerceMany, CoercionCause},
         find_continuable,
@@ -39,7 +40,6 @@ use crate::{
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     traits::FnTrait,
-    utils::{generics, Generics},
     Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig,
     FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder,
     TyExt, TyKind,
@@ -1830,13 +1830,13 @@ impl InferenceContext<'_> {
     ) -> Substitution {
         let (
             parent_params,
-            self_params,
+            has_self_param,
             type_params,
             const_params,
             impl_trait_params,
             lifetime_params,
         ) = def_generics.provenance_split();
-        assert_eq!(self_params, 0); // method shouldn't have another Self param
+        assert!(!has_self_param); // method shouldn't have another Self param
         let total_len =
             parent_params + type_params + const_params + impl_trait_params + lifetime_params;
         let mut substs = Vec::with_capacity(total_len);
@@ -1844,13 +1844,11 @@ impl InferenceContext<'_> {
         // 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()
-                .take(type_params + const_params + lifetime_params)
-                .zip(def_generics.iter_id())
+            let self_params = type_params + const_params + lifetime_params;
+            for (arg, kind_id) in
+                generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params)
             {
-                if let Some(g) = generic_arg_to_chalk(
+                let arg = generic_arg_to_chalk(
                     self.db,
                     kind_id,
                     arg,
@@ -1869,9 +1867,8 @@ impl InferenceContext<'_> {
                         )
                     },
                     |this, lt_ref| this.make_lifetime(lt_ref),
-                ) {
-                    substs.push(g);
-                }
+                );
+                substs.push(arg);
             }
         };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 9a1835b625b..d876008cd58 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -12,11 +12,10 @@ use stdx::never;
 use crate::{
     builder::ParamKind,
     consteval, error_lifetime,
+    generics::generics,
     method_resolution::{self, VisibleFromModule},
-    to_chalk_trait_id,
-    utils::generics,
-    InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
-    TyKind, ValueTyDefId,
+    to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty,
+    TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext};
@@ -64,7 +63,7 @@ impl InferenceContext<'_> {
                 it.into()
             }
             ValueNs::ImplSelf(impl_id) => {
-                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
+                let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
                 let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
                 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 36e3a458898..ed4d55d2037 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -613,8 +613,7 @@ impl<'a> InferenceTable<'a> {
     }
 
     pub(crate) fn resolve_obligations_as_possible(&mut self) {
-        let _span =
-            tracing::span!(tracing::Level::INFO, "resolve_obligations_as_possible").entered();
+        let _span = tracing::info_span!("resolve_obligations_as_possible").entered();
         let mut changed = true;
         let mut obligations = mem::take(&mut self.resolve_obligations_buffer);
         while mem::take(&mut changed) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index 7546369d8d4..f5fb2ffd781 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -15,7 +15,7 @@ use crate::{
 // FIXME: Turn this into a query, it can be quite slow
 /// Checks whether a type is visibly uninhabited from a particular module.
 pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool {
-    let _p = tracing::span!(tracing::Level::INFO, "is_ty_uninhabited_from", ?ty).entered();
+    let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
     let mut uninhabited_from =
         UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
     let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
@@ -30,7 +30,7 @@ pub(crate) fn is_enum_variant_uninhabited_from(
     subst: &Substitution,
     target_mod: ModuleId,
 ) -> bool {
-    let _p = tracing::span!(tracing::Level::INFO, "is_enum_variant_uninhabited_from").entered();
+    let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
 
     let mut uninhabited_from =
         UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 26a839f0e9f..5e33e1285ee 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -22,6 +22,7 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 mod builder;
 mod chalk_db;
 mod chalk_ext;
+mod generics;
 mod infer;
 mod inhabitedness;
 mod interner;
@@ -52,7 +53,7 @@ use std::{
     hash::{BuildHasherDefault, Hash},
 };
 
-use base_db::salsa::impl_intern_value_trivial;
+use base_db::salsa::InternValueTrivial;
 use chalk_ir::{
     fold::{Shift, TypeFoldable},
     interner::HasInterner,
@@ -67,11 +68,10 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast::{make, ConstArg};
 use traits::FnTrait;
 use triomphe::Arc;
-use utils::Generics;
 
 use crate::{
-    consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable,
-    utils::generics,
+    consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics,
+    infer::unify::InferenceTable,
 };
 
 pub use autoderef::autoderef;
@@ -289,7 +289,7 @@ impl Hash for ConstScalar {
 
 /// Return an index of a parameter in the generic type parameter list by it's id.
 pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
-    generics(db.upcast(), id.parent).type_or_const_param_idx(id)
+    generics::generics(db.upcast(), id.parent).type_or_const_param_idx(id)
 }
 
 pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
@@ -330,18 +330,15 @@ pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
     )
 }
 
-pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
+pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
     db: &dyn HirDatabase,
-    count: usize,
     generics: &Generics,
     value: T,
 ) -> Binders<T> {
-    let it = generics.iter_id().take(count);
-
     Binders::new(
         VariableKinds::from_iter(
             Interner,
-            it.map(|x| match x {
+            generics.iter_id().map(|x| match x {
                 hir_def::GenericParamId::ConstParamId(id) => {
                     chalk_ir::VariableKind::Const(db.const_param_ty(id))
                 }
@@ -355,14 +352,6 @@ pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
     )
 }
 
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
-    db: &dyn HirDatabase,
-    generics: &Generics,
-    value: T,
-) -> Binders<T> {
-    make_binders_with_count(db, usize::MAX, generics, value)
-}
-
 // FIXME: get rid of this, just replace it by FnPointer
 /// A function signature as seen by type inference: Several parameter types and
 /// one return type.
@@ -524,14 +513,16 @@ pub type PolyFnSig = Binders<CallableSig>;
 
 impl CallableSig {
     pub fn from_params_and_return(
-        mut params: Vec<Ty>,
+        params: impl ExactSizeIterator<Item = Ty>,
         ret: Ty,
         is_varargs: bool,
         safety: Safety,
         abi: FnAbi,
     ) -> CallableSig {
-        params.push(ret);
-        CallableSig { params_and_return: params.into(), is_varargs, safety, abi }
+        let mut params_and_return = Vec::with_capacity(params.len() + 1);
+        params_and_return.extend(params);
+        params_and_return.push(ret);
+        CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
     }
 
     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
@@ -606,7 +597,7 @@ pub enum ImplTraitId {
     AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
     AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 }
-impl_intern_value_trivial!(ImplTraitId);
+impl InternValueTrivial for ImplTraitId {}
 
 #[derive(PartialEq, Eq, Debug, Hash)]
 pub struct ImplTraits {
@@ -946,8 +937,7 @@ pub fn callable_sig_from_fn_trait(
                     .as_tuple()?
                     .iter(Interner)
                     .map(|it| it.assert_ty_ref(Interner))
-                    .cloned()
-                    .collect();
+                    .cloned();
 
                 return Some((
                     fn_x,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 04ace382021..96f545415e2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -8,10 +8,11 @@
 use std::{
     cell::{Cell, RefCell, RefMut},
     iter,
+    ops::{self, Not as _},
 };
 
 use base_db::{
-    salsa::{impl_intern_value_trivial, Cycle},
+    salsa::{Cycle, InternValueTrivial},
     CrateId,
 };
 use chalk_ir::{
@@ -45,7 +46,9 @@ use hir_def::{
 use hir_expand::{name::Name, ExpandResult};
 use intern::Interned;
 use la_arena::{Arena, ArenaMap};
+use once_cell::unsync::OnceCell;
 use rustc_hash::FxHashSet;
+use rustc_pattern_analysis::Captures;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::ast;
@@ -58,12 +61,13 @@ use crate::{
         unknown_const_as_generic,
     },
     db::HirDatabase,
-    error_lifetime, make_binders,
+    error_lifetime,
+    generics::{generics, Generics},
+    make_binders,
     mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::{
-        self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
-        Generics, InTypeConstIdMetadata,
+        all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata,
     },
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
     FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
@@ -121,6 +125,7 @@ impl ImplTraitLoweringState {
 pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
     resolver: &'a Resolver,
+    generics: OnceCell<Option<Generics>>,
     in_binders: DebruijnIndex,
     // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
     // where expected
@@ -152,6 +157,7 @@ impl<'a> TyLoweringContext<'a> {
         Self {
             db,
             resolver,
+            generics: OnceCell::new(),
             owner,
             in_binders,
             impl_trait_mode,
@@ -174,6 +180,7 @@ impl<'a> TyLoweringContext<'a> {
             impl_trait_mode,
             expander: RefCell::new(expander),
             unsized_types: RefCell::new(unsized_types),
+            generics: self.generics.clone(),
             ..*self
         };
         let result = f(&new_ctx);
@@ -245,8 +252,10 @@ impl<'a> TyLoweringContext<'a> {
         )
     }
 
-    fn generics(&self) -> Option<Generics> {
-        Some(generics(self.db.upcast(), self.resolver.generic_def()?))
+    fn generics(&self) -> Option<&Generics> {
+        self.generics
+            .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def)))
+            .as_ref()
     }
 
     pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
@@ -374,7 +383,7 @@ impl<'a> TyLoweringContext<'a> {
                         counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
                             _parent_params,
-                            self_params,
+                            self_param,
                             type_params,
                             const_params,
                             _impl_trait_params,
@@ -385,7 +394,7 @@ impl<'a> TyLoweringContext<'a> {
                             .provenance_split();
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_params + type_params + const_params,
+                            idx as usize + self_param as usize + type_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -416,9 +425,9 @@ impl<'a> TyLoweringContext<'a> {
                 };
                 let ty = {
                     let macro_call = macro_call.to_node(self.db.upcast());
-                    let resolver = |path| {
+                    let resolver = |path: &_| {
                         self.resolver
-                            .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
+                            .resolve_path_as_macro(self.db.upcast(), path, Some(MacroSubNs::Bang))
                             .map(|(it, _)| it)
                     };
                     match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
@@ -705,7 +714,8 @@ impl<'a> TyLoweringContext<'a> {
                     None,
                 );
 
-                let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self();
+                let len_self =
+                    crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self();
 
                 let substs = Substitution::from_iter(
                     Interner,
@@ -815,14 +825,14 @@ impl<'a> TyLoweringContext<'a> {
         let def_generics = generics(self.db.upcast(), def);
         let (
             parent_params,
-            self_params,
+            self_param,
             type_params,
             const_params,
             impl_trait_params,
             lifetime_params,
         ) = def_generics.provenance_split();
         let item_len =
-            self_params + type_params + const_params + impl_trait_params + lifetime_params;
+            self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
         let total_len = parent_params + item_len;
 
         let ty_error = TyKind::Error.intern(Interner).cast(Interner);
@@ -830,18 +840,16 @@ impl<'a> TyLoweringContext<'a> {
         let mut def_generic_iter = def_generics.iter_id();
 
         let fill_self_params = || {
-            for x in explicit_self_ty
-                .into_iter()
-                .map(|x| x.cast(Interner))
-                .chain(iter::repeat(ty_error.clone()))
-                .take(self_params)
-            {
+            if self_param {
+                let self_ty =
+                    explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone());
+
                 if let Some(id) = def_generic_iter.next() {
                     assert!(matches!(
                         id,
                         GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
                     ));
-                    substs.push(x);
+                    substs.push(self_ty);
                 }
             }
         };
@@ -852,11 +860,11 @@ impl<'a> TyLoweringContext<'a> {
                 fill_self_params();
             }
             let expected_num = if generic_args.has_self_type {
-                self_params + type_params + const_params
+                self_param as usize + type_params + const_params
             } else {
                 type_params + const_params
             };
-            let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
+            let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 };
             // if args are provided, it should be all of them, but we can't rely on that
             for arg in generic_args
                 .args
@@ -866,7 +874,7 @@ impl<'a> TyLoweringContext<'a> {
                 .take(expected_num)
             {
                 if let Some(id) = def_generic_iter.next() {
-                    if let Some(x) = generic_arg_to_chalk(
+                    let arg = generic_arg_to_chalk(
                         self.db,
                         id,
                         arg,
@@ -874,13 +882,9 @@ impl<'a> TyLoweringContext<'a> {
                         |_, type_ref| self.lower_ty(type_ref),
                         |_, const_ref, ty| self.lower_const(const_ref, ty),
                         |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    ) {
-                        had_explicit_args = true;
-                        substs.push(x);
-                    } else {
-                        // we just filtered them out
-                        never!("Unexpected lifetime argument");
-                    }
+                    );
+                    had_explicit_args = true;
+                    substs.push(arg);
                 }
             }
 
@@ -893,7 +897,7 @@ impl<'a> TyLoweringContext<'a> {
                 // Taking into the fact that def_generic_iter will always have lifetimes at the end
                 // Should have some test cases tho to test this behaviour more properly
                 if let Some(id) = def_generic_iter.next() {
-                    if let Some(x) = generic_arg_to_chalk(
+                    let arg = generic_arg_to_chalk(
                         self.db,
                         id,
                         arg,
@@ -901,13 +905,9 @@ impl<'a> TyLoweringContext<'a> {
                         |_, type_ref| self.lower_ty(type_ref),
                         |_, const_ref, ty| self.lower_const(const_ref, ty),
                         |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    ) {
-                        had_explicit_args = true;
-                        substs.push(x);
-                    } else {
-                        // Never return a None explicitly
-                        never!("Unexpected None by generic_arg_to_chalk");
-                    }
+                    );
+                    had_explicit_args = true;
+                    substs.push(arg);
                 }
             }
         } else {
@@ -1176,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> {
                             let ty = if let Some(target_param_idx) = target_param_idx {
                                 let mut counter = 0;
                                 let generics = self.generics().expect("generics in scope");
-                                for (idx, data) in generics.params.type_or_consts.iter() {
+                                for (idx, data) in generics.iter_self_type_or_consts() {
                                     // Count the number of `impl Trait` things that appear before
                                     // the target of our `bound`.
                                     // Our counter within `impl_trait_mode` should be that number
@@ -1478,7 +1478,7 @@ fn named_associated_type_shorthand_candidates<R>(
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
                 let trait_generics = generics(db.upcast(), trait_id.into());
-                if trait_generics.params[param_id.local_id()].is_trait_self() {
+                if trait_generics[param_id.local_id()].is_trait_self() {
                     let def_generics = generics(db.upcast(), def);
                     let starting_idx = match def {
                         GenericDefId::TraitId(_) => 0,
@@ -1596,14 +1596,20 @@ pub(crate) fn generic_predicates_for_param_query(
         .collect();
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-    if let Some(implicitly_sized_predicates) =
-        implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
-    {
-        predicates.extend(
-            implicitly_sized_predicates
-                .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
-        );
+    if !subst.is_empty(Interner) {
+        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+        if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(
+            db,
+            param_id.parent,
+            &explicitly_unsized_tys,
+            &subst,
+            &resolver,
+        ) {
+            predicates.extend(
+                implicitly_sized_predicates
+                    .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
+            );
+        };
     }
     predicates.into()
 }
@@ -1666,14 +1672,17 @@ pub(crate) fn trait_environment_query(
     }
 
     let subst = generics(db.upcast(), def).placeholder_subst(db);
-    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-    if let Some(implicitly_sized_clauses) =
-        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-    {
-        clauses.extend(
-            implicitly_sized_clauses
-                .map(|pred| pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)),
-        );
+    if !subst.is_empty(Interner) {
+        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+        if let Some(implicitly_sized_clauses) =
+            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+        {
+            clauses.extend(
+                implicitly_sized_clauses.map(|pred| {
+                    pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)
+                }),
+            );
+        };
     }
 
     let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
@@ -1681,20 +1690,32 @@ pub(crate) fn trait_environment_query(
     TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
+
+impl ops::Deref for GenericPredicates {
+    type Target = [Binders<crate::QuantifiedWhereClause>];
+
+    fn deref(&self) -> &Self::Target {
+        self.0.as_deref().unwrap_or(&[])
+    }
+}
+
 /// Resolve the where clause(s) of an item with generics.
 pub(crate) fn generic_predicates_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
-) -> Arc<[Binders<QuantifiedWhereClause>]> {
+) -> GenericPredicates {
     let resolver = def.resolver(db.upcast());
-    let ctx = if let GenericDefId::FunctionId(_) = def {
-        TyLoweringContext::new(db, &resolver, def.into())
-            .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
-            .with_type_param_mode(ParamLoweringMode::Variable)
-    } else {
-        TyLoweringContext::new(db, &resolver, def.into())
-            .with_type_param_mode(ParamLoweringMode::Variable)
+    let (impl_trait_lowering, param_lowering) = match def {
+        GenericDefId::FunctionId(_) => {
+            (ImplTraitLoweringMode::Variable, ParamLoweringMode::Variable)
+        }
+        _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
     };
+    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+        .with_impl_trait_mode(impl_trait_lowering)
+        .with_type_param_mode(param_lowering);
     let generics = generics(db.upcast(), def);
 
     let mut predicates = resolver
@@ -1705,27 +1726,29 @@ pub(crate) fn generic_predicates_query(
         .collect::<Vec<_>>();
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-    if let Some(implicitly_sized_predicates) =
-        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-    {
-        predicates.extend(
-            implicitly_sized_predicates
-                .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
-        );
+    if !subst.is_empty(Interner) {
+        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+        if let Some(implicitly_sized_predicates) =
+            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+        {
+            predicates.extend(
+                implicitly_sized_predicates
+                    .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
+            );
+        };
     }
-    predicates.into()
+    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
 }
 
 /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
 /// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'a>(
+fn implicitly_sized_clauses<'a, 'subst: 'a>(
     db: &dyn HirDatabase,
     def: GenericDefId,
     explicitly_unsized_tys: &'a FxHashSet<Ty>,
-    substitution: &'a Substitution,
+    substitution: &'subst Substitution,
     resolver: &Resolver,
-) -> Option<impl Iterator<Item = WhereClause> + 'a> {
+) -> Option<impl Iterator<Item = WhereClause> + Captures<'a> + Captures<'subst>> {
     let is_trait_def = matches!(def, GenericDefId::TraitId(..));
     let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
     let sized_trait = db
@@ -1746,71 +1769,84 @@ fn implicitly_sized_clauses<'a>(
     })
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericDefaults(Option<Arc<[Binders<crate::GenericArg>]>>);
+
+impl ops::Deref for GenericDefaults {
+    type Target = [Binders<crate::GenericArg>];
+
+    fn deref(&self) -> &Self::Target {
+        self.0.as_deref().unwrap_or(&[])
+    }
+}
+
 /// Resolve the default type params from generics
-pub(crate) fn generic_defaults_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> Arc<[Binders<crate::GenericArg>]> {
-    let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
-        .with_type_param_mode(ParamLoweringMode::Variable);
+pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
     let generic_params = generics(db.upcast(), def);
+    if generic_params.len() == 0 {
+        return GenericDefaults(None);
+    }
+    let resolver = def.resolver(db.upcast());
     let parent_start_idx = generic_params.len_self();
 
-    let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| {
-        match p {
-            GenericParamDataRef::TypeParamData(p) => {
-                let mut ty =
-                    p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
-                // Each default can only refer to previous parameters.
-                // Type variable default referring to parameter coming
-                // after it is forbidden (FIXME: report diagnostic)
-                ty = fallback_bound_vars(ty, idx, parent_start_idx);
-                crate::make_binders(db, &generic_params, ty.cast(Interner))
-            }
-            GenericParamDataRef::ConstParamData(p) => {
-                let GenericParamId::ConstParamId(id) = id else {
-                    unreachable!("Unexpected lifetime or type argument")
-                };
+    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+        .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
+        .with_type_param_mode(ParamLoweringMode::Variable);
+    GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
+        |(idx, (id, p))| {
+            match p {
+                GenericParamDataRef::TypeParamData(p) => {
+                    let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
+                        // Each default can only refer to previous parameters.
+                        // Type variable default referring to parameter coming
+                        // after it is forbidden (FIXME: report diagnostic)
+                        fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx)
+                    });
+                    crate::make_binders(db, &generic_params, ty.cast(Interner))
+                }
+                GenericParamDataRef::ConstParamData(p) => {
+                    let GenericParamId::ConstParamId(id) = id else {
+                        unreachable!("Unexpected lifetime or type argument")
+                    };
 
-                let mut val = p.default.as_ref().map_or_else(
-                    || unknown_const_as_generic(db.const_param_ty(id)),
-                    |c| {
-                        let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
-                        c.cast(Interner)
-                    },
-                );
-                // Each default can only refer to previous parameters, see above.
-                val = fallback_bound_vars(val, idx, parent_start_idx);
-                make_binders(db, &generic_params, val)
-            }
-            GenericParamDataRef::LifetimeParamData(_) => {
-                make_binders(db, &generic_params, error_lifetime().cast(Interner))
+                    let mut val = p.default.as_ref().map_or_else(
+                        || unknown_const_as_generic(db.const_param_ty(id)),
+                        |c| {
+                            let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+                            c.cast(Interner)
+                        },
+                    );
+                    // Each default can only refer to previous parameters, see above.
+                    val = fallback_bound_vars(val, idx, parent_start_idx);
+                    make_binders(db, &generic_params, val)
+                }
+                GenericParamDataRef::LifetimeParamData(_) => {
+                    make_binders(db, &generic_params, error_lifetime().cast(Interner))
+                }
             }
-        }
-    }));
-
-    defaults
+        },
+    ))))
 }
 
 pub(crate) fn generic_defaults_recover(
     db: &dyn HirDatabase,
     _cycle: &Cycle,
     def: &GenericDefId,
-) -> Arc<[Binders<crate::GenericArg>]> {
+) -> GenericDefaults {
     let generic_params = generics(db.upcast(), *def);
+    if generic_params.len() == 0 {
+        return GenericDefaults(None);
+    }
     // FIXME: this code is not covered in tests.
     // we still need one default per parameter
-    let defaults = Arc::from_iter(generic_params.iter_id().map(|id| {
+    GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
         let val = match id {
             GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
             GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
             GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
         };
         crate::make_binders(db, &generic_params, val)
-    }));
-
-    defaults
+    }))))
 }
 
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
@@ -1819,7 +1855,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
+    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
     let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
@@ -1873,7 +1909,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
     let resolver = def.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
     Binders::new(
         binders,
@@ -1905,7 +1941,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let resolver = def.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
     let (ret, binders) =
         type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
     Binders::new(
@@ -1965,7 +2001,9 @@ pub enum CallableDefId {
     StructId(StructId),
     EnumVariantId(EnumVariantId),
 }
-impl_intern_value_trivial!(CallableDefId);
+
+impl InternValueTrivial for CallableDefId {}
+
 impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
 impl From<CallableDefId> for ModuleDefId {
     fn from(def: CallableDefId) -> ModuleDefId {
@@ -2166,7 +2204,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
 /// Checks if the provided generic arg matches its expected kind, then lower them via
 /// provided closures. Use unknown if there was kind mismatch.
 ///
-/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
 pub(crate) fn generic_arg_to_chalk<'a, T>(
     db: &dyn HirDatabase,
     kind_id: GenericParamId,
@@ -2175,7 +2212,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
     for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
     for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
     for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
-) -> Option<crate::GenericArg> {
+) -> crate::GenericArg {
     let kind = match kind_id {
         GenericParamId::TypeParamId(_) => ParamKind::Type,
         GenericParamId::ConstParamId(id) => {
@@ -2184,7 +2221,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         }
         GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
     };
-    Some(match (arg, kind) {
+    match (arg, kind) {
         (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
         (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
         (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
@@ -2197,11 +2234,12 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             // as types. Maybe here is not the best place to do it, but
             // it works.
             if let TypeRef::Path(p) = t {
-                let p = p.mod_path()?;
-                if p.kind == PathKind::Plain {
-                    if let [n] = p.segments() {
-                        let c = ConstRef::Path(n.clone());
-                        return Some(for_const(this, &c, c_ty).cast(Interner));
+                if let Some(p) = p.mod_path() {
+                    if p.kind == PathKind::Plain {
+                        if let [n] = p.segments() {
+                            let c = ConstRef::Path(n.clone());
+                            return for_const(this, &c, c_ty).cast(Interner);
+                        }
                     }
                 }
             }
@@ -2210,17 +2248,17 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
         (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
         (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
-    })
+    }
 }
 
-pub(crate) fn const_or_path_to_chalk(
+pub(crate) fn const_or_path_to_chalk<'g>(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     owner: TypeOwnerId,
     expected_ty: Ty,
     value: &ConstRef,
     mode: ParamLoweringMode,
-    args: impl FnOnce() -> Option<Generics>,
+    args: impl FnOnce() -> Option<&'g Generics>,
     debruijn: DebruijnIndex,
 ) -> Const {
     match value {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index cb56a6f0bfe..5ce124d6d27 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -144,8 +144,7 @@ pub struct TraitImpls {
 
 impl TraitImpls {
     pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "trait_impls_in_crate_query", ?krate).entered();
+        let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered();
         let mut impls = FxHashMap::default();
 
         Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
@@ -157,7 +156,7 @@ impl TraitImpls {
         db: &dyn HirDatabase,
         block: BlockId,
     ) -> Option<Arc<Self>> {
-        let _p = tracing::span!(tracing::Level::INFO, "trait_impls_in_block_query").entered();
+        let _p = tracing::info_span!("trait_impls_in_block_query").entered();
         let mut impls = FxHashMap::default();
 
         Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
@@ -173,8 +172,7 @@ impl TraitImpls {
         db: &dyn HirDatabase,
         krate: CrateId,
     ) -> Arc<[Arc<Self>]> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "trait_impls_in_deps_query", ?krate).entered();
+        let _p = tracing::info_span!("trait_impls_in_deps_query", ?krate).entered();
         let crate_graph = db.crate_graph();
 
         Arc::from_iter(
@@ -280,8 +278,7 @@ pub struct InherentImpls {
 
 impl InherentImpls {
     pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "inherent_impls_in_crate_query", ?krate).entered();
+        let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
         let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
 
         let crate_def_map = db.crate_def_map(krate);
@@ -295,7 +292,7 @@ impl InherentImpls {
         db: &dyn HirDatabase,
         block: BlockId,
     ) -> Option<Arc<Self>> {
-        let _p = tracing::span!(tracing::Level::INFO, "inherent_impls_in_block_query").entered();
+        let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
         let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
 
         let block_def_map = db.block_def_map(block);
@@ -368,7 +365,7 @@ pub(crate) fn incoherent_inherent_impl_crates(
     krate: CrateId,
     fp: TyFingerprint,
 ) -> SmallVec<[CrateId; 2]> {
-    let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered();
+    let _p = tracing::info_span!("incoherent_inherent_impl_crates").entered();
     let mut res = SmallVec::new();
     let crate_graph = db.crate_graph();
 
@@ -937,8 +934,7 @@ pub fn iterate_method_candidates_dyn(
     mode: LookupMode,
     callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let _p = tracing::span!(
-        tracing::Level::INFO,
+    let _p = tracing::info_span!(
         "iterate_method_candidates_dyn",
         ?mode,
         ?name,
@@ -1504,7 +1500,7 @@ fn is_valid_impl_fn_candidate(
         }
     }
     table.run_in_snapshot(|table| {
-        let _p = tracing::span!(tracing::Level::INFO, "subst_for_def").entered();
+        let _p = tracing::info_span!("subst_for_def").entered();
         let impl_subst =
             TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build();
         let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst);
@@ -1512,7 +1508,7 @@ fn is_valid_impl_fn_candidate(
         check_that!(table.unify(&expect_self_ty, self_ty));
 
         if let Some(receiver_ty) = receiver_ty {
-            let _p = tracing::span!(tracing::Level::INFO, "check_receiver_ty").entered();
+            let _p = tracing::info_span!("check_receiver_ty").entered();
             check_that!(data.has_self_param());
 
             let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index d5133550377..2e106877cbc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -898,20 +898,19 @@ pub enum Rvalue {
     Cast(CastKind, Operand, Ty),
 
     // FIXME link to `pointer::offset` when it hits stable.
-    /// * `Offset` has the same semantics as `pointer::offset`, except that the second
-    ///   parameter may be a `usize` as well.
-    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
-    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
-    ///   matching, up to the usual caveat of the lifetimes in function pointers.
-    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
-    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
-    ///   truncated as needed.
-    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
-    ///   types and return a value of that type.
-    /// * The remaining operations accept signed integers, unsigned integers, or floats with
-    ///   matching types and return a value of that type.
+    // /// * `Offset` has the same semantics as `pointer::offset`, except that the second
+    // ///   parameter may be a `usize` as well.
+    // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+    // ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
+    // ///   matching, up to the usual caveat of the lifetimes in function pointers.
+    // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+    // ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+    // ///   truncated as needed.
+    // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+    // ///   types and return a value of that type.
+    // /// * The remaining operations accept signed integers, unsigned integers, or floats with
+    // ///   matching types and return a value of that type.
     //BinaryOp(BinOp, Box<(Operand, Operand)>),
-
     /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
     ///
     /// When overflow checking is disabled and we are generating run-time code, the error condition
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 8b6936f8bc0..878d584a4ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -91,7 +91,7 @@ pub fn borrowck_query(
     db: &dyn HirDatabase,
     def: DefWithBodyId,
 ) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
-    let _p = tracing::span!(tracing::Level::INFO, "borrowck_query").entered();
+    let _p = tracing::info_span!("borrowck_query").entered();
     let mut res = vec![];
     all_mir_bodies(db, def, |body| {
         res.push(BorrowckResult {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 2de1aa30c96..4ee96a66a39 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -363,7 +363,7 @@ impl MirEvalError {
                         )?;
                     }
                     Either::Right(closure) => {
-                        writeln!(f, "In {:?}", closure)?;
+                        writeln!(f, "In {closure:?}")?;
                     }
                 }
                 let source_map = db.body_with_source_map(*def).1;
@@ -424,7 +424,7 @@ impl MirEvalError {
             | MirEvalError::StackOverflow
             | MirEvalError::CoerceUnsizedError(_)
             | MirEvalError::InternalError(_)
-            | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
+            | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?,
         }
         Ok(())
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 4abbda56cbb..c3b35cd553d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -77,7 +77,7 @@ fn check_panic(ra_fixture: &str, expected_panic: &str) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
     let file_id = *file_ids.last().unwrap();
     let e = eval_main(&db, file_id).unwrap_err();
-    assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic);
+    assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic);
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 151f65cfbb8..09302846f1b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -28,6 +28,7 @@ use crate::{
     db::{HirDatabase, InternedClosure},
     display::HirDisplay,
     error_lifetime,
+    generics::generics,
     infer::{CaptureKind, CapturedItem, TypeMismatch},
     inhabitedness::is_ty_uninhabited_from,
     layout::LayoutError,
@@ -42,7 +43,7 @@ use crate::{
     },
     static_lifetime,
     traits::FnTrait,
-    utils::{generics, ClosureSubst},
+    utils::ClosureSubst,
     Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
 };
 
@@ -213,7 +214,7 @@ impl MirLowerError {
             | MirLowerError::LangItemNotFound(_)
             | MirLowerError::MutatingRvalue
             | MirLowerError::UnresolvedLabel
-            | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{:?}", self)?,
+            | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?,
         }
         Ok(())
     }
@@ -2133,7 +2134,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
         }
         DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
     };
-    let _p = tracing::span!(tracing::Level::INFO, "mir_body_query", ?detail).entered();
+    let _p = tracing::info_span!("mir_body_query", ?detail).entered();
     let body = db.body(def);
     let infer = db.infer(def);
     let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index a384c9306ee..43afa615048 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -21,8 +21,8 @@ use crate::{
     consteval::{intern_const_scalar, unknown_const},
     db::{HirDatabase, InternedClosure},
     from_placeholder_idx,
+    generics::{generics, Generics},
     infer::normalize,
-    utils::{generics, Generics},
     ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind,
 };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 02f2cd76159..4283a94657b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -108,7 +108,7 @@ pub(crate) fn trait_solve_query(
         GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
         _ => "??".to_owned(),
     };
-    let _p = tracing::span!(tracing::Level::INFO, "trait_solve_query", ?detail).entered();
+    let _p = tracing::info_span!("trait_solve_query", ?detail).entered();
     tracing::info!("trait_solve_query({:?})", goal.value.goal);
 
     if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
@@ -140,7 +140,7 @@ fn solve(
     block: Option<BlockId>,
     goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
 ) -> Option<chalk_solve::Solution<Interner>> {
-    let _p = tracing::span!(tracing::Level::INFO, "solve", ?krate, ?block).entered();
+    let _p = tracing::info_span!("solve", ?krate, ?block).entered();
     let context = ChalkContext { db, krate, block };
     tracing::debug!("solve goal: {:?}", goal);
     let mut solver = create_chalk_solver();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 42c7a840328..969999cdb84 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -5,25 +5,19 @@ use std::{hash::Hash, iter};
 
 use base_db::CrateId;
 use chalk_ir::{
-    cast::Cast,
     fold::{FallibleTypeFolder, Shift},
-    BoundVar, DebruijnIndex,
+    DebruijnIndex,
 };
 use hir_def::{
     db::DefDatabase,
-    generics::{
-        GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
-        TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
-    },
+    generics::{WherePredicate, WherePredicateTypeTarget},
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId,
-    LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
-    TypeParamId,
+    EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
+    TypeOrConstParamId,
 };
 use hir_expand::name::Name;
-use intern::Interned;
 use rustc_abi::TargetDataLayout;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -161,7 +155,7 @@ impl Iterator for ClauseElaborator<'_> {
 fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
     let resolver = trait_.resolver(db);
     let generic_params = db.generic_params(trait_.into());
-    let trait_self = generic_params.find_trait_self_param();
+    let trait_self = generic_params.trait_self_param();
     generic_params
         .where_predicates
         .iter()
@@ -194,7 +188,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
 
 fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
     let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
-    let trait_self = match generic_params.find_trait_self_param() {
+    let trait_self = match generic_params.trait_self_param() {
         Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
         None => return,
     };
@@ -226,11 +220,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
     })
 }
 
-pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
-    let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
-    Generics { def, params: db.generic_params(def), parent_generics }
-}
-
 /// It is a bit different from the rustc equivalent. Currently it stores:
 /// - 0: the function signature, encoded as a function pointer type
 /// - 1..n: generics of the parent
@@ -262,278 +251,14 @@ impl<'a> ClosureSubst<'a> {
     }
 }
 
-#[derive(Clone, Debug)]
-pub(crate) struct Generics {
-    def: GenericDefId,
-    pub(crate) params: Interned<GenericParams>,
-    parent_generics: Option<Box<Generics>>,
-}
-
-impl Generics {
-    pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
-        self.iter().map(|(id, _)| id)
-    }
-
-    pub(crate) fn def(&self) -> GenericDefId {
-        self.def
-    }
-
-    /// Iterator over types and const params of self, then parent.
-    pub(crate) fn iter<'a>(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
-        let from_toc_id = |it: &'a Generics| {
-            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
-                let id = TypeOrConstParamId { parent: it.def, local_id };
-                match p {
-                    TypeOrConstParamData::TypeParamData(p) => (
-                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
-                        GenericParamDataRef::TypeParamData(p),
-                    ),
-                    TypeOrConstParamData::ConstParamData(p) => (
-                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
-                        GenericParamDataRef::ConstParamData(p),
-                    ),
-                }
-            }
-        };
-
-        let from_lt_id = |it: &'a Generics| {
-            move |(local_id, p): (_, &'a LifetimeParamData)| {
-                (
-                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
-                    GenericParamDataRef::LifetimeParamData(p),
-                )
-            }
-        };
-
-        let lt_iter = self.params.iter_lt().map(from_lt_id(self));
-        self.params
-            .iter_type_or_consts()
-            .map(from_toc_id(self))
-            .chain(lt_iter)
-            .chain(self.iter_parent())
-    }
-
-    /// Iterate over types and const params without parent params.
-    pub(crate) fn iter_self<'a>(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
-        let from_toc_id = |it: &'a Generics| {
-            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
-                let id = TypeOrConstParamId { parent: it.def, local_id };
-                match p {
-                    TypeOrConstParamData::TypeParamData(p) => (
-                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
-                        GenericParamDataRef::TypeParamData(p),
-                    ),
-                    TypeOrConstParamData::ConstParamData(p) => (
-                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
-                        GenericParamDataRef::ConstParamData(p),
-                    ),
-                }
-            }
-        };
-
-        let from_lt_id = |it: &'a Generics| {
-            move |(local_id, p): (_, &'a LifetimeParamData)| {
-                (
-                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
-                    GenericParamDataRef::LifetimeParamData(p),
-                )
-            }
-        };
-
-        self.params
-            .iter_type_or_consts()
-            .map(from_toc_id(self))
-            .chain(self.params.iter_lt().map(from_lt_id(self)))
-    }
-
-    /// Iterator over types and const params of parent.
-    pub(crate) fn iter_parent(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
-        self.parent_generics().into_iter().flat_map(|it| {
-            let from_toc_id = move |(local_id, p)| {
-                let p: &_ = p;
-                let id = TypeOrConstParamId { parent: it.def, local_id };
-                match p {
-                    TypeOrConstParamData::TypeParamData(p) => (
-                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
-                        GenericParamDataRef::TypeParamData(p),
-                    ),
-                    TypeOrConstParamData::ConstParamData(p) => (
-                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
-                        GenericParamDataRef::ConstParamData(p),
-                    ),
-                }
-            };
-
-            let from_lt_id = move |(local_id, p): (_, _)| {
-                (
-                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
-                    GenericParamDataRef::LifetimeParamData(p),
-                )
-            };
-            let lt_iter = it.params.iter_lt().map(from_lt_id);
-            it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter)
-        })
-    }
-
-    /// Returns total number of generic parameters in scope, including those from parent.
-    pub(crate) fn len(&self) -> usize {
-        let parent = self.parent_generics().map_or(0, Generics::len);
-        let child = self.params.len();
-        parent + child
-    }
-
-    /// Returns numbers of generic parameters and lifetimes excluding those from parent.
-    pub(crate) fn len_self(&self) -> usize {
-        self.params.len()
-    }
-
-    /// Returns number of generic parameter excluding those from parent
-    fn len_type_and_const_params(&self) -> usize {
-        self.params.type_or_consts.len()
-    }
-
-    /// (parent total, self param, type params, const params, impl trait list, lifetimes)
-    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) {
-        let mut self_params = 0;
-        let mut type_params = 0;
-        let mut impl_trait_params = 0;
-        let mut const_params = 0;
-        let mut lifetime_params = 0;
-        self.params.iter_type_or_consts().for_each(|(_, data)| match data {
-            TypeOrConstParamData::TypeParamData(p) => match p.provenance {
-                TypeParamProvenance::TypeParamList => type_params += 1,
-                TypeParamProvenance::TraitSelf => self_params += 1,
-                TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
-            },
-            TypeOrConstParamData::ConstParamData(_) => const_params += 1,
-        });
-
-        self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1);
-
-        let parent_len = self.parent_generics().map_or(0, Generics::len);
-        (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params)
-    }
-
-    pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
-        Some(self.find_type_or_const_param(param)?.0)
-    }
-
-    fn find_type_or_const_param(
-        &self,
-        param: TypeOrConstParamId,
-    ) -> Option<(usize, &TypeOrConstParamData)> {
-        if param.parent == self.def {
-            let idx = param.local_id.into_raw().into_u32() as usize;
-            if idx >= self.params.type_or_consts.len() {
-                return None;
-            }
-            Some((idx, &self.params.type_or_consts[param.local_id]))
-        } else {
-            self.parent_generics()
-                .and_then(|g| g.find_type_or_const_param(param))
-                // Remember that parent parameters come after parameters for self.
-                .map(|(idx, data)| (self.len_self() + idx, data))
-        }
-    }
-
-    pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
-        Some(self.find_lifetime(lifetime)?.0)
-    }
-
-    fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> {
-        if lifetime.parent == self.def {
-            let idx = lifetime.local_id.into_raw().into_u32() as usize;
-            if idx >= self.params.lifetimes.len() {
-                return None;
-            }
-            Some((
-                self.len_type_and_const_params() + idx,
-                &self.params.lifetimes[lifetime.local_id],
-            ))
-        } else {
-            self.parent_generics()
-                .and_then(|g| g.find_lifetime(lifetime))
-                .map(|(idx, data)| (self.len_self() + idx, data))
-        }
-    }
-
-    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
-        self.parent_generics.as_deref()
-    }
-
-    pub(crate) fn parent_or_self(&self) -> &Generics {
-        self.parent_generics.as_deref().unwrap_or(self)
-    }
-
-    /// Returns a Substitution that replaces each parameter by a bound variable.
-    pub(crate) fn bound_vars_subst(
-        &self,
-        db: &dyn HirDatabase,
-        debruijn: DebruijnIndex,
-    ) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.iter_id().enumerate().map(|(idx, id)| match id {
-                GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
-                GenericParamId::TypeParamId(_) => {
-                    BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
-                }
-                GenericParamId::LifetimeParamId(_) => {
-                    BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
-                }
-            }),
-        )
-    }
-
-    /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
-    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.iter_id().map(|id| match id {
-                GenericParamId::TypeParamId(id) => {
-                    crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
-                }
-                GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into())
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
-                GenericParamId::LifetimeParamId(id) => {
-                    crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
-                }
-            }),
-        )
-    }
-}
-
-fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
-    let container = match def {
-        GenericDefId::FunctionId(it) => it.lookup(db).container,
-        GenericDefId::TypeAliasId(it) => it.lookup(db).container,
-        GenericDefId::ConstId(it) => it.lookup(db).container,
-        GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()),
-        GenericDefId::AdtId(_)
-        | GenericDefId::TraitId(_)
-        | GenericDefId::ImplId(_)
-        | GenericDefId::TraitAliasId(_) => return None,
-    };
-
-    match container {
-        ItemContainerId::ImplId(it) => Some(it.into()),
-        ItemContainerId::TraitId(it) => Some(it.into()),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
-    }
-}
-
 pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
     let data = db.function_data(func);
     if data.has_unsafe_kw() {
+        // Functions that are `#[rustc_deprecated_safe_2024]` are safe to call before 2024.
+        if db.attrs(func.into()).by_key("rustc_deprecated_safe_2024").exists() {
+            // FIXME: Properly check the caller span and mark it as unsafe after 2024.
+            return false;
+        }
         return true;
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 6d7ecd1e50b..edf26a07a74 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -27,6 +27,7 @@ cfg.workspace = true
 hir-def.workspace = true
 hir-expand.workspace = true
 hir-ty.workspace = true
+intern.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 tt.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index c7502890ef4..7b3ff7b0645 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -307,7 +307,7 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
         let kind = match parts.next()? {
             "" => PathKind::Abs,
             "crate" => PathKind::Crate,
-            "self" => PathKind::Super(0),
+            "self" => PathKind::SELF,
             "super" => {
                 let mut deg = 1;
                 for segment in parts.by_ref() {
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index c276e87786d..79069ed66bf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -3,7 +3,8 @@ use either::Either;
 use hir_def::{
     data::adt::{StructKind, VariantData},
     generics::{
-        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+        GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
+        WherePredicateTypeTarget,
     },
     lang_item::LangItem,
     type_ref::{TypeBound, TypeRef},
@@ -16,10 +17,12 @@ use hir_ty::{
     },
     AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
 };
+use intern::Interned;
+use itertools::Itertools;
 
 use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl,
-    Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module,
+    Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module,
     SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias,
     TypeOrConstParam, TypeParam, Union, Variant,
 };
@@ -30,12 +33,42 @@ impl HirDisplay for Function {
         let data = db.function_data(self.id);
         let container = self.as_assoc_item(db).map(|it| it.container(db));
         let mut module = self.module(db);
+
+        // Write container (trait or impl)
+        let container_params = match container {
+            Some(AssocItemContainer::Trait(trait_)) => {
+                let params = f.db.generic_params(trait_.id.into());
+                if f.show_container_bounds() && !params.is_empty() {
+                    write_trait_header(&trait_, f)?;
+                    f.write_char('\n')?;
+                    has_disaplayable_predicates(&params).then_some(params)
+                } else {
+                    None
+                }
+            }
+            Some(AssocItemContainer::Impl(impl_)) => {
+                let params = f.db.generic_params(impl_.id.into());
+                if f.show_container_bounds() && !params.is_empty() {
+                    write_impl_header(&impl_, f)?;
+                    f.write_char('\n')?;
+                    has_disaplayable_predicates(&params).then_some(params)
+                } else {
+                    None
+                }
+            }
+            None => None,
+        };
+
+        // Write signature of the function
+
+        // Block-local impls are "hoisted" to the nearest (non-block) module.
         if let Some(AssocItemContainer::Impl(_)) = container {
-            // Block-local impls are "hoisted" to the nearest (non-block) module.
             module = module.nearest_non_block_module(db);
         }
         let module_id = module.id;
+
         write_visibility(module_id, self.visibility(db), f)?;
+
         if data.has_default_kw() {
             f.write_str("default ")?;
         }
@@ -116,12 +149,41 @@ impl HirDisplay for Function {
             }
         }
 
-        write_where_clause(GenericDefId::FunctionId(self.id), f)?;
-
+        // Write where clauses
+        let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?;
+        if let Some(container_params) = container_params {
+            if !has_written_where {
+                f.write_str("\nwhere")?;
+            }
+            let container_name = match container.unwrap() {
+                AssocItemContainer::Trait(_) => "trait",
+                AssocItemContainer::Impl(_) => "impl",
+            };
+            write!(f, "\n    // Bounds from {container_name}:",)?;
+            write_where_predicates(&container_params, f)?;
+        }
         Ok(())
     }
 }
 
+fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+    let db = f.db;
+
+    f.write_str("impl")?;
+    let def_id = GenericDefId::ImplId(impl_.id);
+    write_generic_params(def_id, f)?;
+
+    if let Some(trait_) = impl_.trait_(db) {
+        let trait_data = db.trait_data(trait_.id);
+        write!(f, " {} for", trait_data.name.display(db.upcast()))?;
+    }
+
+    f.write_char(' ')?;
+    impl_.self_ty(db).hir_fmt(f)?;
+
+    Ok(())
+}
+
 impl HirDisplay for SelfParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         let data = f.db.function_data(self.func);
@@ -188,7 +250,7 @@ impl HirDisplay for Struct {
             StructKind::Record => {
                 let has_where_clause = write_where_clause(def_id, f)?;
                 if let Some(limit) = f.entity_limit {
-                    display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
+                    write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
                 }
             }
             StructKind::Unit => _ = write_where_clause(def_id, f)?,
@@ -208,7 +270,7 @@ impl HirDisplay for Enum {
 
         let has_where_clause = write_where_clause(def_id, f)?;
         if let Some(limit) = f.entity_limit {
-            display_variants(&self.variants(f.db), has_where_clause, limit, f)?;
+            write_variants(&self.variants(f.db), has_where_clause, limit, f)?;
         }
 
         Ok(())
@@ -225,13 +287,13 @@ impl HirDisplay for Union {
 
         let has_where_clause = write_where_clause(def_id, f)?;
         if let Some(limit) = f.entity_limit {
-            display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
+            write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
         }
         Ok(())
     }
 }
 
-fn display_fields(
+fn write_fields(
     fields: &[Field],
     has_where_clause: bool,
     limit: usize,
@@ -242,11 +304,7 @@ fn display_fields(
     let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
     f.write_char(if !has_where_clause { ' ' } else { separator })?;
     if count == 0 {
-        if fields.is_empty() {
-            f.write_str("{}")?;
-        } else {
-            f.write_str("{ /* … */ }")?;
-        }
+        f.write_str(if fields.is_empty() { "{}" } else { "{ /* … */ }" })?;
     } else {
         f.write_char('{')?;
 
@@ -255,14 +313,11 @@ fn display_fields(
             for field in &fields[..count] {
                 f.write_str(indent)?;
                 field.hir_fmt(f)?;
-                f.write_char(',')?;
-                f.write_char(separator)?;
+                write!(f, ",{separator}")?;
             }
 
             if fields.len() > count {
-                f.write_str(indent)?;
-                f.write_str("/* … */")?;
-                f.write_char(separator)?;
+                write!(f, "{indent}/* … */{separator}")?;
             }
         }
 
@@ -272,7 +327,7 @@ fn display_fields(
     Ok(())
 }
 
-fn display_variants(
+fn write_variants(
     variants: &[Variant],
     has_where_clause: bool,
     limit: usize,
@@ -281,30 +336,22 @@ fn display_variants(
     let count = variants.len().min(limit);
     f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
     if count == 0 {
-        if variants.is_empty() {
-            f.write_str("{}")?;
-        } else {
-            f.write_str("{ /* … */ }")?;
-        }
+        let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" };
+        f.write_str(variants)?;
     } else {
         f.write_str("{\n")?;
         for variant in &variants[..count] {
-            f.write_str("    ")?;
-            write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?;
+            write!(f, "    {}", variant.name(f.db).display(f.db.upcast()))?;
             match variant.kind(f.db) {
                 StructKind::Tuple => {
-                    if variant.fields(f.db).is_empty() {
-                        f.write_str("()")?;
-                    } else {
-                        f.write_str("( /* … */ )")?;
-                    }
+                    let fields_str =
+                        if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" };
+                    f.write_str(fields_str)?;
                 }
                 StructKind::Record => {
-                    if variant.fields(f.db).is_empty() {
-                        f.write_str(" {}")?;
-                    } else {
-                        f.write_str(" { /* … */ }")?;
-                    }
+                    let fields_str =
+                        if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" };
+                    f.write_str(fields_str)?;
                 }
                 StructKind::Unit => {}
             }
@@ -357,7 +404,7 @@ impl HirDisplay for Variant {
             }
             VariantData::Record(_) => {
                 if let Some(limit) = f.entity_limit {
-                    display_fields(&self.fields(f.db), false, limit, true, f)?;
+                    write_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
             }
         }
@@ -554,102 +601,96 @@ fn write_where_clause(
     f: &mut HirFormatter<'_>,
 ) -> Result<bool, HirDisplayError> {
     let params = f.db.generic_params(def);
+    if !has_disaplayable_predicates(&params) {
+        return Ok(false);
+    }
 
-    // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
-    let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
-        WherePredicateTypeTarget::TypeRef(_) => false,
-        WherePredicateTypeTarget::TypeOrConstParam(id) => {
-            params.type_or_consts[*id].name().is_none()
-        }
-    };
+    f.write_str("\nwhere")?;
+    write_where_predicates(&params, f)?;
 
-    let has_displayable_predicate = params
-        .where_predicates
-        .iter()
-        .any(|pred| {
-            !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target))
-        });
+    Ok(true)
+}
 
-    if !has_displayable_predicate {
-        return Ok(false);
-    }
+fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
+    params.where_predicates.iter().any(|pred| {
+        !matches!(
+            pred,
+            WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. }
+            if params.type_or_consts[*id].name().is_none()
+        )
+    })
+}
+
+fn write_where_predicates(
+    params: &Interned<GenericParams>,
+    f: &mut HirFormatter<'_>,
+) -> Result<(), HirDisplayError> {
+    use WherePredicate::*;
+
+    // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
+    let is_unnamed_type_target =
+        |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
+            matches!(target,
+                WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none()
+            )
+        };
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
         WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
-        WherePredicateTypeTarget::TypeOrConstParam(id) => {
-            match &params.type_or_consts[*id].name() {
-                Some(name) => write!(f, "{}", name.display(f.db.upcast())),
-                None => f.write_str("{unnamed}"),
-            }
-        }
+        WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() {
+            Some(name) => write!(f, "{}", name.display(f.db.upcast())),
+            None => f.write_str("{unnamed}"),
+        },
     };
 
-    f.write_str("\nwhere")?;
-
-    for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
-        let prev_pred =
-            if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
+    let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) {
+        (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2,
+        (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2,
+        (
+            ForLifetime { lifetimes: l1, target: t1, .. },
+            ForLifetime { lifetimes: l2, target: t2, .. },
+        ) => l1 == l2 && t1 == t2,
+        _ => false,
+    };
 
-        let new_predicate = |f: &mut HirFormatter<'_>| {
-            f.write_str(if pred_idx == 0 { "\n    " } else { ",\n    " })
-        };
+    let mut iter = params.where_predicates.iter().peekable();
+    while let Some(pred) = iter.next() {
+        if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) {
+            continue;
+        }
 
+        f.write_str("\n    ")?;
         match pred {
-            WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {}
-            WherePredicate::TypeBound { target, bound } => {
-                if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
-                {
-                    f.write_str(" + ")?;
-                } else {
-                    new_predicate(f)?;
-                    write_target(target, f)?;
-                    f.write_str(": ")?;
-                }
+            TypeBound { target, bound } => {
+                write_target(target, f)?;
+                f.write_str(": ")?;
                 bound.hir_fmt(f)?;
             }
-            WherePredicate::Lifetime { target, bound } => {
-                if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
-                {
-                    write!(f, " + {}", bound.name.display(f.db.upcast()))?;
-                } else {
-                    new_predicate(f)?;
-                    write!(
-                        f,
-                        "{}: {}",
-                        target.name.display(f.db.upcast()),
-                        bound.name.display(f.db.upcast())
-                    )?;
-                }
+            Lifetime { target, bound } => {
+                let target = target.name.display(f.db.upcast());
+                let bound = bound.name.display(f.db.upcast());
+                write!(f, "{target}: {bound}")?;
             }
-            WherePredicate::ForLifetime { lifetimes, target, bound } => {
-                if matches!(
-                    prev_pred,
-                    Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
-                    if lifetimes_ == lifetimes && target_ == target,
-                ) {
-                    f.write_str(" + ")?;
-                } else {
-                    new_predicate(f)?;
-                    f.write_str("for<")?;
-                    for (idx, lifetime) in lifetimes.iter().enumerate() {
-                        if idx != 0 {
-                            f.write_str(", ")?;
-                        }
-                        write!(f, "{}", lifetime.display(f.db.upcast()))?;
-                    }
-                    f.write_str("> ")?;
-                    write_target(target, f)?;
-                    f.write_str(": ")?;
-                }
+            ForLifetime { lifetimes, target, bound } => {
+                let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", ");
+                write!(f, "for<{lifetimes}> ")?;
+                write_target(target, f)?;
+                f.write_str(": ")?;
                 bound.hir_fmt(f)?;
             }
         }
-    }
 
-    // End of final predicate. There must be at least one predicate here.
-    f.write_char(',')?;
+        while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
+            f.write_str(" + ")?;
+            match nxt {
+                TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
+                Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?,
+            }
+        }
+        f.write_str(",")?;
+    }
 
-    Ok(true)
+    Ok(())
 }
 
 impl HirDisplay for Const {
@@ -689,17 +730,8 @@ impl HirDisplay for Static {
 
 impl HirDisplay for Trait {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
-        let data = f.db.trait_data(self.id);
-        if data.is_unsafe {
-            f.write_str("unsafe ")?;
-        }
-        if data.is_auto {
-            f.write_str("auto ")?;
-        }
-        write!(f, "trait {}", data.name.display(f.db.upcast()))?;
+        write_trait_header(self, f)?;
         let def_id = GenericDefId::TraitId(self.id);
-        write_generic_params(def_id, f)?;
         let has_where_clause = write_where_clause(def_id, f)?;
 
         if let Some(limit) = f.entity_limit {
@@ -735,6 +767,20 @@ impl HirDisplay for Trait {
     }
 }
 
+fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+    write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
+    let data = f.db.trait_data(trait_.id);
+    if data.is_unsafe {
+        f.write_str("unsafe ")?;
+    }
+    if data.is_auto {
+        f.write_str("auto ")?;
+    }
+    write!(f, "trait {}", data.name.display(f.db.upcast()))?;
+    write_generic_params(GenericDefId::TraitId(trait_.id), f)?;
+    Ok(())
+}
+
 impl HirDisplay for TraitAlias {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
index 7cdcdd76d18..929c8b3c09e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -8,13 +8,14 @@ use hir_def::{
     Lookup, MacroId, VariantId,
 };
 use hir_expand::{HirFileId, InFile};
+use hir_ty::{db::InternedClosure, CallableDefId};
 use syntax::ast;
 use tt::TextRange;
 
 use crate::{
-    db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
-    LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias,
-    TypeOrConstParam, Union, Variant,
+    db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
+    Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait,
+    TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant,
 };
 
 pub trait HasSource {
@@ -25,7 +26,7 @@ pub trait HasSource {
     ///
     /// The current some implementations can return `InFile` instead of `Option<InFile>`.
     /// But we made this method `Option` to support rlib in the future
-    /// by https://github.com/rust-lang/rust-analyzer/issues/6913
+    /// by <https://github.com/rust-lang/rust-analyzer/issues/6913>
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
 }
 
@@ -202,7 +203,7 @@ impl HasSource for TypeOrConstParam {
     type Ast = Either<ast::TypeOrConstParam, ast::TraitOrAlias>;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
-        Some(child_source.map(|it| it[self.id.local_id].clone()))
+        child_source.map(|it| it.get(self.id.local_id).cloned()).transpose()
     }
 }
 
@@ -210,7 +211,7 @@ impl HasSource for LifetimeParam {
     type Ast = ast::LifetimeParam;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
-        Some(child_source.map(|it| it[self.id.local_id].clone()))
+        child_source.map(|it| it.get(self.id.local_id).cloned()).transpose()
     }
 }
 
@@ -222,6 +223,68 @@ impl HasSource for LocalSource {
     }
 }
 
+impl HasSource for Param {
+    type Ast = Either<ast::SelfParam, ast::Param>;
+
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        match self.func {
+            Callee::Def(CallableDefId::FunctionId(func)) => {
+                let InFile { file_id, value } = Function { id: func }.source(db)?;
+                let params = value.param_list()?;
+                if let Some(self_param) = params.self_param() {
+                    if let Some(idx) = self.idx.checked_sub(1) {
+                        params.params().nth(idx).map(Either::Right)
+                    } else {
+                        Some(Either::Left(self_param))
+                    }
+                } else {
+                    params.params().nth(self.idx).map(Either::Right)
+                }
+                .map(|value| InFile { file_id, value })
+            }
+            Callee::Closure(closure, _) => {
+                let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
+                let (_, source_map) = db.body_with_source_map(owner);
+                let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
+                let root = db.parse_or_expand(file_id);
+                match value.to_node(&root) {
+                    ast::Expr::ClosureExpr(it) => it
+                        .param_list()?
+                        .params()
+                        .nth(self.idx)
+                        .map(Either::Right)
+                        .map(|value| InFile { file_id: ast.file_id, value }),
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
+}
+
+impl HasSource for SelfParam {
+    type Ast = ast::SelfParam;
+
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        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 })
+    }
+}
+
+impl HasSource for Label {
+    type Ast = ast::Label;
+
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        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());
+        Some(src.map(|ast| ast.to_node(&root)))
+    }
+}
+
 impl HasSource for ExternCrateDecl {
     type Ast = ast::ExternCrate;
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 777be711a5e..c1fe8a8b316 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -64,7 +64,6 @@ use hir_expand::{
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
-    db::InternedClosure,
     diagnostics::BodyValidationDiagnostic,
     error_lifetime, known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
@@ -113,7 +112,7 @@ pub use hir_ty::method_resolution::TyFingerprint;
 pub use {
     cfg::{CfgAtom, CfgExpr, CfgOptions},
     hir_def::{
-        attr::{builtin::AttributeTemplate, AttrSourceMap, Attrs, AttrsWithOwner},
+        attr::{AttrSourceMap, Attrs, AttrsWithOwner},
         data::adt::StructKind,
         find_path::PrefixKind,
         import_map,
@@ -132,6 +131,7 @@ pub use {
         attrs::{Attr, AttrId},
         change::ChangeWithProcMacros,
         hygiene::{marks_rev, SyntaxContextExt},
+        inert_attr_macro::AttributeTemplate,
         name::{known, Name},
         proc_macro::ProcMacros,
         tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId,
@@ -242,7 +242,7 @@ impl Crate {
         db: &dyn DefDatabase,
         query: import_map::Query,
     ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
-        let _p = tracing::span!(tracing::Level::INFO, "query_external_importables").entered();
+        let _p = tracing::info_span!("query_external_importables").entered();
         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),
@@ -551,8 +551,7 @@ impl Module {
         acc: &mut Vec<AnyDiagnostic>,
         style_lints: bool,
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", name = ?self.name(db))
-            .entered();
+        let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered();
         let def_map = self.id.def_map(db.upcast());
         for diag in def_map.diagnostics() {
             if diag.in_module != self.id.local_id {
@@ -1099,6 +1098,35 @@ pub enum FieldSource {
     Pos(ast::TupleField),
 }
 
+impl AstNode for FieldSource {
+    fn can_cast(kind: syntax::SyntaxKind) -> bool
+    where
+        Self: Sized,
+    {
+        ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind)
+    }
+
+    fn cast(syntax: SyntaxNode) -> Option<Self>
+    where
+        Self: Sized,
+    {
+        if ast::RecordField::can_cast(syntax.kind()) {
+            <ast::RecordField as AstNode>::cast(syntax).map(FieldSource::Named)
+        } else if ast::TupleField::can_cast(syntax.kind()) {
+            <ast::TupleField as AstNode>::cast(syntax).map(FieldSource::Pos)
+        } else {
+            None
+        }
+    }
+
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            FieldSource::Named(it) => it.syntax(),
+            FieldSource::Pos(it) => it.syntax(),
+        }
+    }
+}
+
 impl Field {
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
         self.parent.variant_data(db).fields()[self.id].name.clone()
@@ -1884,6 +1912,14 @@ impl Function {
         Type::from_value_def(db, self.id)
     }
 
+    pub fn fn_ptr_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 = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner);
+        Type::new_with_resolver_inner(db, &resolver, ty)
+    }
+
     /// Get this function's return type
     pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
         let resolver = self.id.resolver(db.upcast());
@@ -2208,47 +2244,9 @@ impl Param {
         }
     }
 
-    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
+    pub fn pattern_source(self, db: &dyn HirDatabase) -> Option<ast::Pat> {
         self.source(db).and_then(|p| p.value.right()?.pat())
     }
-
-    pub fn source(
-        &self,
-        db: &dyn HirDatabase,
-    ) -> Option<InFile<Either<ast::SelfParam, ast::Param>>> {
-        match self.func {
-            Callee::Def(CallableDefId::FunctionId(func)) => {
-                let InFile { file_id, value } = Function { id: func }.source(db)?;
-                let params = value.param_list()?;
-                if let Some(self_param) = params.self_param() {
-                    if let Some(idx) = self.idx.checked_sub(1) {
-                        params.params().nth(idx).map(Either::Right)
-                    } else {
-                        Some(Either::Left(self_param))
-                    }
-                } else {
-                    params.params().nth(self.idx).map(Either::Right)
-                }
-                .map(|value| InFile { file_id, value })
-            }
-            Callee::Closure(closure, _) => {
-                let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
-                let (_, source_map) = db.body_with_source_map(owner);
-                let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
-                let root = db.parse_or_expand(file_id);
-                match value.to_node(&root) {
-                    ast::Expr::ClosureExpr(it) => it
-                        .param_list()?
-                        .params()
-                        .nth(self.idx)
-                        .map(Either::Right)
-                        .map(|value| InFile { file_id: ast.file_id, value }),
-                    _ => None,
-                }
-            }
-            _ => None,
-        }
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2272,14 +2270,6 @@ impl SelfParam {
             .unwrap_or(Access::Owned)
     }
 
-    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 parent_fn(&self) -> Function {
         Function::from(self.func)
     }
@@ -2414,9 +2404,9 @@ impl Const {
                         let value_signed =
                             i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_))));
                         if value >= 10 {
-                            return Ok(format!("{} ({:#X})", value_signed, value));
+                            return Ok(format!("{value_signed} ({value:#X})"));
                         } else {
-                            return Ok(format!("{}", value_signed));
+                            return Ok(format!("{value_signed}"));
                         }
                     }
                 }
@@ -2746,6 +2736,12 @@ impl Macro {
         }
     }
 
+    pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool {
+        matches!(self.id, MacroId::Macro2Id(it) if {
+            matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm())
+        })
+    }
+
     pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
         matches!(self.kind(db), MacroKind::Attr)
     }
@@ -2788,6 +2784,7 @@ impl From<ModuleDef> for ItemInNs {
             ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
                 ItemInNs::Values(module_def)
             }
+            ModuleDef::Macro(it) => ItemInNs::Macros(it),
             _ => ItemInNs::Types(module_def),
         }
     }
@@ -3381,7 +3378,7 @@ impl BuiltinAttr {
     }
 
     fn builtin(name: &str) -> Option<Self> {
-        hir_def::attr::builtin::find_builtin_attr_idx(name)
+        hir_expand::inert_attr_macro::find_builtin_attr_idx(name)
             .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 })
     }
 
@@ -3389,14 +3386,18 @@ impl BuiltinAttr {
         // FIXME: Return a `Name` here
         match self.krate {
             Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
-            None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name),
+            None => {
+                SmolStr::new(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name)
+            }
         }
     }
 
     pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
         match self.krate {
             Some(_) => None,
-            None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template),
+            None => {
+                Some(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].template)
+            }
         }
     }
 }
@@ -3440,13 +3441,6 @@ impl Label {
         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)]
@@ -4612,8 +4606,7 @@ impl Type {
         name: Option<&Name>,
         mut callback: impl FnMut(Function) -> Option<T>,
     ) -> Option<T> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered();
+        let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
         let mut slot = None;
 
         self.iterate_method_candidates_dyn(
@@ -4662,8 +4655,7 @@ impl Type {
         name: Option<&Name>,
         callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
     ) {
-        let _p = tracing::span!(
-            tracing::Level::INFO,
+        let _p = tracing::info_span!(
             "iterate_method_candidates_dyn",
             with_local_impls = traits_in_scope.len(),
             traits_in_scope = traits_in_scope.len(),
@@ -4701,7 +4693,7 @@ impl Type {
         name: Option<&Name>,
         mut callback: impl FnMut(AssocItem) -> Option<T>,
     ) -> Option<T> {
-        let _p = tracing::span!(tracing::Level::INFO, "iterate_path_candidates").entered();
+        let _p = tracing::info_span!("iterate_path_candidates").entered();
         let mut slot = None;
         self.iterate_path_candidates_dyn(
             db,
@@ -4768,7 +4760,7 @@ impl Type {
         &'a self,
         db: &'a dyn HirDatabase,
     ) -> impl Iterator<Item = Trait> + 'a {
-        let _p = tracing::span!(tracing::Level::INFO, "applicable_inherent_traits").entered();
+        let _p = tracing::info_span!("applicable_inherent_traits").entered();
         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))
@@ -4776,7 +4768,7 @@ impl Type {
     }
 
     pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
-        let _p = tracing::span!(tracing::Level::INFO, "env_traits").entered();
+        let _p = tracing::info_span!("env_traits").entered();
         self.autoderef_(db)
             .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
             .flat_map(|ty| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 43de2a6ee7d..f6c88edbff7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -19,7 +19,11 @@ use hir_def::{
     AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
 };
 use hir_expand::{
-    attrs::collect_attrs, db::ExpandDatabase, files::InRealFile, name::AsName, ExpansionInfo,
+    attrs::collect_attrs,
+    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
+    db::ExpandDatabase,
+    files::InRealFile,
+    name::AsName,
     InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
 };
 use itertools::Itertools;
@@ -132,9 +136,6 @@ pub struct SemanticsImpl<'db> {
     s2d_cache: RefCell<SourceToDefCache>,
     /// Rootnode to HirFileId cache
     root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
-    // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens
-    // So we might wanna move them out into something specific for semantic highlighting
-    expansion_info_cache: RefCell<FxHashMap<MacroFileId, ExpansionInfo>>,
     /// MacroCall to its expansion's MacroFileId cache
     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>,
 }
@@ -295,7 +296,6 @@ impl<'db> SemanticsImpl<'db> {
             db,
             s2d_cache: Default::default(),
             root_to_file_cache: Default::default(),
-            expansion_info_cache: Default::default(),
             macro_call_cache: Default::default(),
         }
     }
@@ -314,7 +314,58 @@ impl<'db> SemanticsImpl<'db> {
 
     pub 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 macro_call = InFile::new(sa.file_id, macro_call);
+        let file_id = if let Some(call) =
+            <ast::MacroCall as crate::semantics::ToDef>::to_def(self, macro_call)
+        {
+            call.as_macro_file()
+        } else {
+            sa.expand(self.db, macro_call)?
+        };
+
+        let node = self.parse_or_expand(file_id.into());
+        Some(node)
+    }
+
+    /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy
+    /// expansions.
+    pub fn expand_allowed_builtins(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
+        let sa = self.analyze_no_infer(macro_call.syntax())?;
+
+        let macro_call = InFile::new(sa.file_id, macro_call);
+        let file_id = if let Some(call) =
+            <ast::MacroCall as crate::semantics::ToDef>::to_def(self, macro_call)
+        {
+            call.as_macro_file()
+        } else {
+            sa.expand(self.db, macro_call)?
+        };
+        let macro_call = self.db.lookup_intern_macro_call(file_id.macro_call_id);
+
+        let skip = matches!(
+            macro_call.def.kind,
+            hir_expand::MacroDefKind::BuiltIn(
+                _,
+                BuiltinFnLikeExpander::Column
+                    | BuiltinFnLikeExpander::File
+                    | BuiltinFnLikeExpander::ModulePath
+                    | BuiltinFnLikeExpander::Asm
+                    | BuiltinFnLikeExpander::LlvmAsm
+                    | BuiltinFnLikeExpander::GlobalAsm
+                    | BuiltinFnLikeExpander::LogSyntax
+                    | BuiltinFnLikeExpander::TraceMacros
+                    | BuiltinFnLikeExpander::FormatArgs
+                    | BuiltinFnLikeExpander::FormatArgsNl
+                    | BuiltinFnLikeExpander::ConstFormatArgs,
+            ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError)
+        );
+        if skip {
+            // these macros expand to custom builtin syntax and/or dummy things, no point in
+            // showing these to the user
+            return None;
+        }
+
         let node = self.parse_or_expand(file_id.into());
         Some(node)
     }
@@ -322,7 +373,7 @@ impl<'db> SemanticsImpl<'db> {
     /// If `item` has an attribute macro attached to it, expands it.
     pub 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))?;
+        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?;
         Some(self.parse_or_expand(macro_call_id.as_file()))
     }
 
@@ -341,9 +392,7 @@ impl<'db> SemanticsImpl<'db> {
             Some(
                 calls
                     .into_iter()
-                    .map(|call| {
-                        macro_call_to_macro_id(ctx, self.db.upcast(), call?).map(|id| Macro { id })
-                    })
+                    .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id }))
                     .collect(),
             )
         })
@@ -403,7 +452,7 @@ impl<'db> SemanticsImpl<'db> {
 
     pub 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());
+        let src = InFile::new(file_id, item);
         self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
     }
 
@@ -420,7 +469,7 @@ impl<'db> SemanticsImpl<'db> {
         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_def(self.db.upcast(), &path, Some(MacroSubNs::Bang))
+            resolver.resolve_path_as_macro_def(self.db.upcast(), path, Some(MacroSubNs::Bang))
         })?;
         hir_expand::db::expand_speculative(
             self.db.upcast(),
@@ -453,7 +502,7 @@ impl<'db> SemanticsImpl<'db> {
         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))?;
+        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?;
         hir_expand::db::expand_speculative(
             self.db.upcast(),
             macro_call_id,
@@ -705,8 +754,6 @@ impl<'db> SemanticsImpl<'db> {
         let parent = token.parent()?;
         let file_id = self.find_file(&parent).file_id.file_id()?;
 
-        let mut cache = self.expansion_info_cache.borrow_mut();
-
         // iterate related crates and find all include! invocations that include_file_id matches
         for (invoc, _) in self
             .db
@@ -716,18 +763,32 @@ impl<'db> SemanticsImpl<'db> {
             .filter(|&(_, include_file_id)| include_file_id == file_id)
         {
             let macro_file = invoc.as_macro_file();
-            let expansion_info = cache.entry(macro_file).or_insert_with(|| {
-                let exp_info = macro_file.expansion_info(self.db.upcast());
-
-                let InMacroFile { file_id, value } = exp_info.expanded();
-                self.cache(value, file_id.into());
+            let expansion_info = {
+                self.with_ctx(|ctx| {
+                    ctx.cache
+                        .expansion_info_cache
+                        .entry(macro_file)
+                        .or_insert_with(|| {
+                            let exp_info = macro_file.expansion_info(self.db.upcast());
+
+                            let InMacroFile { file_id, value } = exp_info.expanded();
+                            if let InFile { file_id, value: Some(value) } = exp_info.arg() {
+                                self.cache(value.ancestors().last().unwrap(), file_id);
+                            }
+                            self.cache(value, file_id.into());
 
-                exp_info
-            });
+                            exp_info
+                        })
+                        .clone()
+                })
+            };
 
             // FIXME: uncached parse
             // Create the source analyzer for the macro call scope
-            let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file()))
+            let Some(sa) = expansion_info
+                .arg()
+                .value
+                .and_then(|it| self.analyze_no_infer(&it.ancestors().last().unwrap()))
             else {
                 continue;
             };
@@ -758,7 +819,7 @@ impl<'db> SemanticsImpl<'db> {
         mut token: SyntaxToken,
         f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered();
+        let _p = tracing::info_span!("descend_into_macros_impl").entered();
         let (sa, span, file_id) =
             match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) {
                 Some(sa) => match sa.file_id.file_id() {
@@ -785,23 +846,28 @@ impl<'db> SemanticsImpl<'db> {
                 }
             };
 
-        let mut cache = self.expansion_info_cache.borrow_mut();
-        let mut mcache = self.macro_call_cache.borrow_mut();
+        let mut m_cache = self.macro_call_cache.borrow_mut();
         let def_map = sa.resolver.def_map();
 
         let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])];
-        let mut process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
-            let exp_info = cache.entry(macro_file).or_insert_with(|| {
-                let exp_info = macro_file.expansion_info(self.db.upcast());
-
-                let InMacroFile { file_id, value } = exp_info.expanded();
-                self.cache(value, file_id.into());
-
-                exp_info
-            });
-
-            let InMacroFile { file_id, value: mapped_tokens } = exp_info.map_range_down(span)?;
-            let mapped_tokens: SmallVec<[_; 2]> = mapped_tokens.collect();
+        let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
+            let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| {
+                Some(
+                    ctx.cache
+                        .expansion_info_cache
+                        .entry(macro_file)
+                        .or_insert_with(|| {
+                            let exp_info = macro_file.expansion_info(self.db.upcast());
+
+                            let InMacroFile { file_id, value } = exp_info.expanded();
+                            self.cache(value, file_id.into());
+
+                            exp_info
+                        })
+                        .map_range_down(span)?
+                        .map(SmallVec::<[_; 2]>::from_iter),
+                )
+            })?;
 
             // we have found a mapping for the token if the vec is non-empty
             let res = mapped_tokens.is_empty().not().then_some(());
@@ -818,10 +884,7 @@ impl<'db> SemanticsImpl<'db> {
                         token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
                             // Don't force populate the dyn cache for items that don't have an attribute anyways
                             item.attrs().next()?;
-                            Some((
-                                ctx.item_to_macro_call(InFile::new(file_id, item.clone()))?,
-                                item,
-                            ))
+                            Some((ctx.item_to_macro_call(InFile::new(file_id, &item))?, item))
                         })
                     });
                     if let Some((call_id, item)) = containing_attribute_macro_call {
@@ -874,13 +937,20 @@ impl<'db> SemanticsImpl<'db> {
                                 return None;
                             }
                             let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
-                            let mcall: hir_expand::files::InFileWrapper<HirFileId, ast::MacroCall> =
-                                InFile::new(file_id, macro_call);
-                            let file_id = match mcache.get(&mcall) {
+                            let mcall = InFile::new(file_id, macro_call);
+                            let file_id = match m_cache.get(&mcall) {
                                 Some(&it) => it,
                                 None => {
-                                    let it = sa.expand(self.db, mcall.as_ref())?;
-                                    mcache.insert(mcall, it);
+                                    let it = if let Some(call) =
+                                        <ast::MacroCall as crate::semantics::ToDef>::to_def(
+                                            self,
+                                            mcall.as_ref(),
+                                        ) {
+                                        call.as_macro_file()
+                                    } else {
+                                        sa.expand(self.db, mcall.as_ref())?
+                                    };
+                                    m_cache.insert(mcall, it);
                                     it
                                 }
                             };
@@ -953,6 +1023,13 @@ impl<'db> SemanticsImpl<'db> {
                             let helpers =
                                 def_map.derive_helpers_in_scope(InFile::new(file_id, id))?;
 
+                            if !helpers.is_empty() {
+                                let text_range = attr.syntax().text_range();
+                                // remove any other token in this macro input, all their mappings are the
+                                // same as this
+                                tokens.retain(|t| !text_range.contains_range(t.text_range()));
+                            }
+
                             let mut res = None;
                             for (.., derive) in
                                 helpers.iter().filter(|(helper, ..)| *helper == attr_name)
@@ -1056,16 +1133,20 @@ impl<'db> SemanticsImpl<'db> {
         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 => {
-                    let call_node = file_id.macro_file()?.call_node(db);
-                    // cache the node
-                    // FIXME: uncached parse
-                    self.parse_or_expand(call_node.file_id);
-                    Some(call_node)
+                    let macro_file = file_id.macro_file()?;
+
+                    self.with_ctx(|ctx| {
+                        let expansion_info = ctx
+                            .cache
+                            .expansion_info_cache
+                            .entry(macro_file)
+                            .or_insert_with(|| macro_file.expansion_info(self.db.upcast()));
+                        expansion_info.arg().map(|node| node?.parent()).transpose()
+                    })
                 }
             }
         })
@@ -1090,7 +1171,7 @@ impl<'db> SemanticsImpl<'db> {
                 .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)
+        ToDef::to_def(self, src.as_ref())
     }
 
     pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
@@ -1112,7 +1193,7 @@ impl<'db> SemanticsImpl<'db> {
             })
         })?;
         let src = self.wrap_node_infile(label);
-        ToDef::to_def(self, src)
+        ToDef::to_def(self, src.as_ref())
     }
 
     pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
@@ -1275,9 +1356,15 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub 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)
+        self.with_ctx(|ctx| {
+            ctx.macro_call_to_macro_call(macro_call)
+                .and_then(|call| macro_call_to_macro_id(ctx, call))
+                .map(Into::into)
+        })
+        .or_else(|| {
+            self.analyze(macro_call.value.syntax())?.resolve_macro_call(self.db, macro_call)
+        })
     }
 
     pub fn is_proc_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
@@ -1297,19 +1384,24 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub 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 Some(mac) = self.resolve_macro_call(macro_call) else { return false };
+        if mac.is_asm_or_global_asm(self.db) {
+            return true;
+        }
+
+        let Some(sa) = self.analyze(macro_call.syntax()) else { return false };
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
-        sa.is_unsafe_macro_call(self.db, macro_call)
+        match macro_call.map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast)).transpose() {
+            Some(it) => sa.is_unsafe_macro_call_expr(self.db, it.as_ref()),
+            None => false,
+        }
     }
 
     pub 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)
+            let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?;
+            macro_call_to_macro_id(ctx, macro_call_id)
         })?;
         Some(Macro { id })
     }
@@ -1339,18 +1431,17 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     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, dynmap_cache: &mut cache };
+        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() };
         f(&mut ctx)
     }
 
     pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
-        let src = self.find_file(src.syntax()).with_value(src).cloned();
+        let src = self.find_file(src.syntax()).with_value(src);
         T::to_def(self, src)
     }
 
     fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
-        self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
+        self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from)
     }
 
     pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
@@ -1380,6 +1471,7 @@ impl<'db> SemanticsImpl<'db> {
     where
         Def::Ast: AstNode,
     {
+        // FIXME: source call should go through the parse cache
         let res = def.source(self.db)?;
         self.cache(find_root(res.value.syntax()), res.file_id);
         Some(res)
@@ -1409,7 +1501,7 @@ impl<'db> SemanticsImpl<'db> {
         offset: Option<TextSize>,
         infer_body: bool,
     ) -> Option<SourceAnalyzer> {
-        let _p = tracing::span!(tracing::Level::INFO, "SemanticsImpl::analyze_impl").entered();
+        let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
         let node = self.find_file(node);
 
         let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@@ -1438,7 +1530,7 @@ impl<'db> SemanticsImpl<'db> {
         assert!(root_node.parent().is_none());
         let mut cache = self.root_to_file_cache.borrow_mut();
         let prev = cache.insert(root_node, file_id);
-        assert!(prev.is_none() || prev == Some(file_id))
+        assert!(prev.is_none() || prev == Some(file_id));
     }
 
     pub fn assert_contains_node(&self, node: &SyntaxNode) {
@@ -1613,35 +1705,59 @@ impl<'db> SemanticsImpl<'db> {
 
 fn macro_call_to_macro_id(
     ctx: &mut SourceToDefCtx<'_, '_>,
-    db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
 ) -> Option<MacroId> {
+    use span::HirFileIdRepr;
+
+    let db: &dyn ExpandDatabase = ctx.db.upcast();
     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)))
+
+    match loc.def.ast_id() {
+        Either::Left(it) => {
+            let node = match it.file_id.repr() {
+                HirFileIdRepr::FileId(file_id) => {
+                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                }
+                HirFileIdRepr::MacroFile(macro_file) => {
+                    let expansion_info = ctx
+                        .cache
+                        .expansion_info_cache
+                        .entry(macro_file)
+                        .or_insert_with(|| macro_file.expansion_info(ctx.db.upcast()));
+                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
+                }
+            };
+            ctx.macro_to_def(InFile::new(it.file_id, &node))
         }
-        hir_expand::MacroDefKind::ProcMacro(_, _, it) => {
-            ctx.proc_macro_to_def(InFile::new(it.file_id, it.to_node(db)))
+        Either::Right(it) => {
+            let node = match it.file_id.repr() {
+                HirFileIdRepr::FileId(file_id) => {
+                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                }
+                HirFileIdRepr::MacroFile(macro_file) => {
+                    let expansion_info = ctx
+                        .cache
+                        .expansion_info_cache
+                        .entry(macro_file)
+                        .or_insert_with(|| macro_file.expansion_info(ctx.db.upcast()));
+                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
+                }
+            };
+            ctx.proc_macro_to_def(InFile::new(it.file_id, &node))
         }
     }
 }
 
 pub trait ToDef: AstNode + Clone {
     type Def;
-
-    fn to_def(sema: &SemanticsImpl<'_>, src: InFile<Self>) -> Option<Self::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> {
+            fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option<Self::Def> {
                 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
             }
         }
@@ -1674,6 +1790,7 @@ to_def_impls![
     (crate::Label, ast::Label, label_to_def),
     (crate::Adt, ast::Adt, adt_to_def),
     (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
+    (MacroCallId, ast::MacroCall, macro_call_to_macro_call),
 ];
 
 fn find_root(node: &SyntaxNode) -> SyntaxNode {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 77e7cdb58ab..74ed2640f40 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -26,19 +26,19 @@
 //!
 //! 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?)
+//! * 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.
+//! 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.
@@ -98,56 +98,68 @@ use hir_def::{
     FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId,
     StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId,
 };
-use hir_expand::{attrs::AttrId, name::AsName, HirFileId, HirFileIdExt, MacroCallId};
+use hir_expand::{
+    attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, MacroCallId,
+};
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
+use span::MacroFileId;
 use stdx::impl_from;
 use syntax::{
     ast::{self, HasName},
-    AstNode, SyntaxNode,
+    AstNode, AstPtr, SyntaxNode,
 };
 
 use crate::{db::HirDatabase, InFile};
 
-pub(super) type SourceToDefCache = FxHashMap<(ChildContainer, HirFileId), DynMap>;
+#[derive(Default)]
+pub(super) struct SourceToDefCache {
+    pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>,
+    pub(super) expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>,
+    pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>,
+}
 
-pub(super) struct SourceToDefCtx<'a, 'b> {
-    pub(super) db: &'b dyn HirDatabase,
-    pub(super) dynmap_cache: &'a mut SourceToDefCache,
+pub(super) struct SourceToDefCtx<'db, 'cache> {
+    pub(super) db: &'db dyn HirDatabase,
+    pub(super) cache: &'cache mut SourceToDefCache,
 }
 
 impl SourceToDefCtx<'_, '_> {
-    pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
-        let _p = tracing::span!(tracing::Level::INFO, "SourceToDefCtx::file_to_def").entered();
-        let mut mods = SmallVec::new();
-        for &crate_id in self.db.relevant_crates(file).iter() {
-            // Note: `mod` declarations in block modules cannot be supported here
-            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)),
-            )
-        }
-        if mods.is_empty() {
-            // FIXME: detached file
-        }
-        mods
+    pub(super) fn file_to_def(&mut self, file: FileId) -> &SmallVec<[ModuleId; 1]> {
+        let _p = tracing::info_span!("SourceToDefCtx::file_to_def").entered();
+        self.cache.file_to_def_cache.entry(file).or_insert_with(|| {
+            let mut mods = SmallVec::new();
+            for &crate_id in self.db.relevant_crates(file).iter() {
+                // Note: `mod` declarations in block modules cannot be supported here
+                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)),
+                )
+            }
+            if mods.is_empty() {
+                // FIXME: detached file
+            }
+            mods
+        })
     }
 
-    pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
-        let _p = tracing::span!(tracing::Level::INFO, "module_to_def").entered();
-        let parent_declaration = src
-            .syntax()
-            .ancestors_with_macros(self.db.upcast())
-            .find_map(|it| it.map(Either::<ast::Module, ast::BlockExpr>::cast).transpose())
+    pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<ModuleId> {
+        let _p = tracing::info_span!("module_to_def").entered();
+        let parent_declaration = self
+            .ancestors_with_macros(src.syntax_ref(), |_, ancestor| {
+                ancestor.map(Either::<ast::Module, ast::BlockExpr>::cast).transpose()
+            })
             .map(|it| it.transpose());
 
         let parent_module = match parent_declaration {
             Some(Either::Right(parent_block)) => self
-                .block_to_def(parent_block)
+                .block_to_def(parent_block.as_ref())
                 .map(|block| self.db.block_def_map(block).root_module_id()),
-            Some(Either::Left(parent_declaration)) => self.module_to_def(parent_declaration),
+            Some(Either::Left(parent_declaration)) => {
+                self.module_to_def(parent_declaration.as_ref())
+            }
             None => {
                 let file_id = src.file_id.original_file(self.db.upcast());
                 self.file_to_def(file_id).first().copied()
@@ -160,73 +172,79 @@ impl SourceToDefCtx<'_, '_> {
         Some(def_map.module_id(child_id))
     }
 
-    pub(super) fn source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
-        let _p = tracing::span!(tracing::Level::INFO, "source_file_to_def").entered();
+    pub(super) fn source_file_to_def(&mut self, src: InFile<&ast::SourceFile>) -> Option<ModuleId> {
+        let _p = tracing::info_span!("source_file_to_def").entered();
         let file_id = src.file_id.original_file(self.db.upcast());
         self.file_to_def(file_id).first().copied()
     }
 
-    pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
+    pub(super) fn trait_to_def(&mut self, src: InFile<&ast::Trait>) -> Option<TraitId> {
         self.to_def(src, keys::TRAIT)
     }
     pub(super) fn trait_alias_to_def(
         &mut self,
-        src: InFile<ast::TraitAlias>,
+        src: InFile<&ast::TraitAlias>,
     ) -> Option<TraitAliasId> {
         self.to_def(src, keys::TRAIT_ALIAS)
     }
-    pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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> {
+    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 block_to_def(&mut self, src: InFile<ast::BlockExpr>) -> Option<BlockId> {
+    pub(super) fn block_to_def(&mut self, src: InFile<&ast::BlockExpr>) -> Option<BlockId> {
         self.to_def(src, keys::BLOCK)
     }
     pub(super) fn enum_variant_to_def(
         &mut self,
-        src: InFile<ast::Variant>,
+        src: InFile<&ast::Variant>,
     ) -> Option<EnumVariantId> {
         self.to_def(src, keys::ENUM_VARIANT)
     }
     pub(super) fn extern_crate_to_def(
         &mut self,
-        src: InFile<ast::ExternCrate>,
+        src: InFile<&ast::ExternCrate>,
     ) -> Option<ExternCrateId> {
         self.to_def(src, keys::EXTERN_CRATE)
     }
     #[allow(dead_code)]
-    pub(super) fn use_to_def(&mut self, src: InFile<ast::Use>) -> Option<UseId> {
+    pub(super) fn use_to_def(&mut self, src: InFile<&ast::Use>) -> Option<UseId> {
         self.to_def(src, keys::USE)
     }
     pub(super) fn adt_to_def(
         &mut self,
-        InFile { file_id, value }: InFile<ast::Adt>,
+        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),
@@ -238,11 +256,11 @@ impl SourceToDefCtx<'_, '_> {
     }
     pub(super) fn bind_pat_to_def(
         &mut self,
-        src: InFile<ast::IdentPat>,
+        src: InFile<&ast::IdentPat>,
     ) -> Option<(DefWithBodyId, BindingId)> {
-        let container = self.find_pat_or_label_container(src.syntax())?;
+        let container = self.find_pat_or_label_container(src.syntax_ref())?;
         let (body, source_map) = self.db.body_with_source_map(container);
-        let src = src.map(ast::Pat::from);
+        let src = src.cloned().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 { id, .. } = body[pat_id] {
@@ -253,25 +271,33 @@ impl SourceToDefCtx<'_, '_> {
     }
     pub(super) fn self_param_to_def(
         &mut self,
-        src: InFile<ast::SelfParam>,
+        src: InFile<&ast::SelfParam>,
     ) -> Option<(DefWithBodyId, BindingId)> {
-        let container = self.find_pat_or_label_container(src.syntax())?;
+        let container = self.find_pat_or_label_container(src.syntax_ref())?;
         let body = self.db.body(container);
         Some((container, body.self_param?))
     }
     pub(super) fn label_to_def(
         &mut self,
-        src: InFile<ast::Label>,
+        src: InFile<&ast::Label>,
     ) -> Option<(DefWithBodyId, LabelId)> {
-        let container = self.find_pat_or_label_container(src.syntax())?;
+        let container = self.find_pat_or_label_container(src.syntax_ref())?;
         let (_body, source_map) = self.db.body_with_source_map(container);
-        let label_id = source_map.node_label(src.as_ref())?;
+        let label_id = source_map.node_label(src)?;
         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()
+    pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
+        let map = self.dyn_map(src)?;
+        map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied()
+    }
+
+    pub(super) fn macro_call_to_macro_call(
+        &mut self,
+        src: InFile<&ast::MacroCall>,
+    ) -> Option<MacroCallId> {
+        let map = self.dyn_map(src)?;
+        map[keys::MACRO_CALL].get(&AstPtr::new(src.value)).copied()
     }
 
     /// (AttrId, derive attribute call id, derive call ids)
@@ -282,7 +308,7 @@ impl SourceToDefCtx<'_, '_> {
     ) -> Option<(AttrId, MacroCallId, &[Option<MacroCallId>])> {
         let map = self.dyn_map(item)?;
         map[keys::DERIVE_MACRO_CALL]
-            .get(&src.value)
+            .get(&AstPtr::new(&src.value))
             .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids))
     }
 
@@ -292,10 +318,10 @@ impl SourceToDefCtx<'_, '_> {
 
     fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
         &mut self,
-        src: InFile<Ast>,
+        src: InFile<&Ast>,
         key: Key<Ast, ID>,
     ) -> Option<ID> {
-        self.dyn_map(src.as_ref())?[key].get(&src.value).copied()
+        self.dyn_map(src)?[key].get(&AstPtr::new(src.value)).copied()
     }
 
     fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> {
@@ -305,38 +331,48 @@ impl SourceToDefCtx<'_, '_> {
 
     fn cache_for(&mut self, container: ChildContainer, file_id: HirFileId) -> &DynMap {
         let db = self.db;
-        self.dynmap_cache
+        self.cache
+            .dynmap_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();
+    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_ref())?.into();
         let dyn_map = self.cache_for(container, src.file_id);
-        dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(TypeParamId::from_unchecked)
+        dyn_map[keys::TYPE_PARAM]
+            .get(&AstPtr::new(src.value))
+            .copied()
+            .map(TypeParamId::from_unchecked)
     }
 
     pub(super) fn lifetime_param_to_def(
         &mut self,
-        src: InFile<ast::LifetimeParam>,
+        src: InFile<&ast::LifetimeParam>,
     ) -> Option<LifetimeParamId> {
-        let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
+        let container: ChildContainer = self.find_generic_param_container(src.syntax_ref())?.into();
         let dyn_map = self.cache_for(container, src.file_id);
-        dyn_map[keys::LIFETIME_PARAM].get(&src.value).copied()
+        dyn_map[keys::LIFETIME_PARAM].get(&AstPtr::new(src.value)).copied()
     }
 
     pub(super) fn const_param_to_def(
         &mut self,
-        src: InFile<ast::ConstParam>,
+        src: InFile<&ast::ConstParam>,
     ) -> Option<ConstParamId> {
-        let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
+        let container: ChildContainer = self.find_generic_param_container(src.syntax_ref())?.into();
         let dyn_map = self.cache_for(container, src.file_id);
-        dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(ConstParamId::from_unchecked)
+        dyn_map[keys::CONST_PARAM]
+            .get(&AstPtr::new(src.value))
+            .copied()
+            .map(ConstParamId::from_unchecked)
     }
 
     pub(super) fn generic_param_to_def(
         &mut self,
-        InFile { file_id, value }: InFile<ast::GenericParam>,
+        InFile { file_id, value }: InFile<&ast::GenericParam>,
     ) -> Option<GenericParamId> {
         match value {
             ast::GenericParam::ConstParam(it) => {
@@ -351,34 +387,113 @@ impl SourceToDefCtx<'_, '_> {
         }
     }
 
-    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 {
+    pub(super) fn macro_to_def(&mut self, src: InFile<&ast::Macro>) -> Option<MacroId> {
+        self.dyn_map(src).and_then(|it| match src.value {
             ast::Macro::MacroRules(value) => {
-                it[keys::MACRO_RULES].get(value).copied().map(MacroId::from)
+                it[keys::MACRO_RULES].get(&AstPtr::new(value)).copied().map(MacroId::from)
+            }
+            ast::Macro::MacroDef(value) => {
+                it[keys::MACRO2].get(&AstPtr::new(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 proc_macro_to_def(&mut self, src: InFile<&ast::Fn>) -> Option<MacroId> {
+        self.dyn_map(src).and_then(|it| {
+            it[keys::PROC_MACRO].get(&AstPtr::new(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(self.db.upcast()) {
-            if let Some(res) = self.container_to_def(container) {
-                return Some(res);
-            }
+        let _p = tracing::info_span!("find_container").entered();
+        let def =
+            self.ancestors_with_macros(src, |this, container| this.container_to_def(container));
+        if let Some(def) = def {
+            return Some(def);
         }
 
         let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).first().copied()?;
         Some(def.into())
     }
 
+    /// Skips the attributed item that caused the macro invocation we are climbing up
+    fn ancestors_with_macros<T>(
+        &mut self,
+        node: InFile<&SyntaxNode>,
+        mut cb: impl FnMut(&mut Self, InFile<SyntaxNode>) -> Option<T>,
+    ) -> Option<T> {
+        use hir_expand::MacroFileIdExt;
+        let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() {
+            Some(parent) => Some(node.with_value(parent)),
+            None => {
+                let macro_file = node.file_id.macro_file()?;
+
+                let expansion_info = this
+                    .cache
+                    .expansion_info_cache
+                    .entry(macro_file)
+                    .or_insert_with(|| macro_file.expansion_info(this.db.upcast()));
+
+                expansion_info.arg().map(|node| node?.parent()).transpose()
+            }
+        };
+        let mut node = node.cloned();
+        while let Some(parent) = parent(self, node.as_ref()) {
+            if let Some(res) = cb(self, parent.clone()) {
+                return Some(res);
+            }
+            node = parent;
+        }
+        None
+    }
+
+    fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
+        self.ancestors_with_macros(src, |this, InFile { file_id, value }| {
+            let item = ast::Item::cast(value)?;
+            match &item {
+                ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into),
+                ast::Item::Struct(it) => {
+                    this.struct_to_def(InFile::new(file_id, it)).map(Into::into)
+                }
+                ast::Item::Enum(it) => this.enum_to_def(InFile::new(file_id, it)).map(Into::into),
+                ast::Item::Trait(it) => this.trait_to_def(InFile::new(file_id, it)).map(Into::into),
+                ast::Item::TraitAlias(it) => {
+                    this.trait_alias_to_def(InFile::new(file_id, it)).map(Into::into)
+                }
+                ast::Item::TypeAlias(it) => {
+                    this.type_alias_to_def(InFile::new(file_id, it)).map(Into::into)
+                }
+                ast::Item::Impl(it) => this.impl_to_def(InFile::new(file_id, it)).map(Into::into),
+                _ => None,
+            }
+        })
+    }
+
+    fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
+        self.ancestors_with_macros(src, |this, InFile { file_id, value }| {
+            let item = match ast::Item::cast(value.clone()) {
+                Some(it) => it,
+                None => {
+                    let variant = ast::Variant::cast(value.clone())?;
+                    return this
+                        .enum_variant_to_def(InFile::new(file_id, &variant))
+                        .map(Into::into);
+                }
+            };
+            match &item {
+                ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into),
+                ast::Item::Const(it) => this.const_to_def(InFile::new(file_id, it)).map(Into::into),
+                ast::Item::Static(it) => {
+                    this.static_to_def(InFile::new(file_id, it)).map(Into::into)
+                }
+                _ => None,
+            }
+        })
+    }
+
     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 {
+            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::TraitAlias(it) => {
@@ -413,63 +528,11 @@ impl SourceToDefCtx<'_, '_> {
             }
         } else {
             let it = ast::Variant::cast(container.value)?;
-            let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
+            let def = self.enum_variant_to_def(InFile::new(container.file_id, &it))?;
             DefWithBodyId::from(def).into()
         };
         Some(cont)
     }
-
-    fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
-        let ancestors = src.ancestors_with_macros(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::Union(it) => self.union_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::TraitAlias(it) => {
-                    self.trait_alias_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(self.db.upcast());
-        for InFile { file_id, value } in ancestors {
-            let item = match ast::Item::cast(value.clone()) {
-                Some(it) => it,
-                None => {
-                    if let Some(variant) = ast::Variant::cast(value.clone()) {
-                        return self
-                            .enum_variant_to_def(InFile::new(file_id, variant))
-                            .map(Into::into);
-                    }
-                    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)]
@@ -501,6 +564,7 @@ impl_from! {
 
 impl ChildContainer {
     fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap {
+        let _p = tracing::info_span!("ChildContainer::child_by_source").entered();
         let db = db.upcast();
         match self {
             ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id),
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index d2295840642..8e71a54f804 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -24,11 +24,12 @@ use hir_def::{
     LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
 };
 use hir_expand::{
-    builtin_fn_macro::BuiltinFnLikeExpander,
     mod_path::path,
-    name,
-    name::{AsName, Name},
     HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt,
+    {
+        name,
+        name::{AsName, Name},
+    },
 };
 use hir_ty::{
     diagnostics::{
@@ -822,8 +823,10 @@ impl SourceAnalyzer {
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<MacroFileId> {
         let krate = self.resolver.krate();
+        // FIXME: This causes us to parse, generally this is the wrong approach for resolving a
+        // macro call to a macro call id!
         let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
-            self.resolver.resolve_path_as_macro_def(db.upcast(), &path, Some(MacroSubNs::Bang))
+            self.resolver.resolve_path_as_macro_def(db.upcast(), path, Some(MacroSubNs::Bang))
         })?;
         // why the 64?
         Some(macro_call_id.as_macro_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
@@ -839,37 +842,13 @@ impl SourceAnalyzer {
         infer.variant_resolution_for_expr(expr_id)
     }
 
-    pub(crate) fn is_unsafe_macro_call(
+    pub(crate) fn is_unsafe_macro_call_expr(
         &self,
         db: &dyn HirDatabase,
-        macro_call: InFile<&ast::MacroCall>,
+        macro_expr: InFile<&ast::MacroExpr>,
     ) -> 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()) {
+            if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
                 let mut is_unsafe = false;
                 unsafe_expressions(
                     db,
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index 7b70cdf4599..aa046b02e2e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -325,6 +325,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
     // Use well known types tactic before iterations as it does not depend on other tactics
     solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
+    solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
 
     while should_continue() {
         lookup.new_round();
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index 8173427cd90..bb687f5e73d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -9,8 +9,8 @@ use hir_ty::{
 use itertools::Itertools;
 
 use crate::{
-    Adt, AsAssocItem, Const, ConstParam, Field, Function, GenericDef, Local, ModuleDef,
-    SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
+    Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, GenericDef, Local,
+    ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
 };
 
 /// Helper function to get path to `ModuleDef`
@@ -138,7 +138,17 @@ impl Expr {
         let db = sema_scope.db;
         let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg);
         match self {
-            Expr::Const(it) => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
+            Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) {
+                Some(container) => {
+                    let container_name = container_name(container, sema_scope, cfg)?;
+                    let const_name = it
+                        .name(db)
+                        .map(|c| c.display(db.upcast()).to_string())
+                        .unwrap_or(String::new());
+                    Ok(format!("{container_name}::{const_name}"))
+                }
+                None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
+            },
             Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
             Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()),
             Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()),
@@ -153,22 +163,7 @@ impl Expr {
 
                 match func.as_assoc_item(db).map(|it| it.container(db)) {
                     Some(container) => {
-                        let container_name = match container {
-                            crate::AssocItemContainer::Trait(trait_) => {
-                                mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?
-                            }
-                            crate::AssocItemContainer::Impl(imp) => {
-                                let self_ty = imp.self_ty(db);
-                                // Should it be guaranteed that `mod_item_path` always exists?
-                                match self_ty
-                                    .as_adt()
-                                    .and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg))
-                                {
-                                    Some(path) => path.display(sema_scope.db.upcast()).to_string(),
-                                    None => self_ty.display(db).to_string(),
-                                }
-                            }
-                        };
+                        let container_name = container_name(container, sema_scope, cfg)?;
                         let fn_name = func.name(db).display(db.upcast()).to_string();
                         Ok(format!("{container_name}::{fn_name}({args})"))
                     }
@@ -414,3 +409,25 @@ impl Expr {
         matches!(self, Expr::Many(_))
     }
 }
+
+/// Helper function to find name of container
+fn container_name(
+    container: AssocItemContainer,
+    sema_scope: &SemanticsScope<'_>,
+    cfg: ImportPathConfig,
+) -> Result<String, DisplaySourceCodeError> {
+    let container_name = match container {
+        crate::AssocItemContainer::Trait(trait_) => {
+            mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg)?
+        }
+        crate::AssocItemContainer::Impl(imp) => {
+            let self_ty = imp.self_ty(sema_scope.db);
+            // Should it be guaranteed that `mod_item_path` always exists?
+            match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) {
+                Some(path) => path.display(sema_scope.db.upcast()).to_string(),
+                None => self_ty.display(sema_scope.db).to_string(),
+            }
+        }
+    };
+    Ok(container_name)
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index f95ff1dc0fa..b738e6af77b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -5,6 +5,7 @@
 //! * `defs` - Set of items in scope at term search target location
 //! * `lookup` - Lookup table for types
 //! * `should_continue` - Function that indicates when to stop iterating
+//!
 //! And they return iterator that yields type trees that unify with the `goal` type.
 
 use std::iter;
@@ -79,7 +80,10 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
         lookup.insert(ty.clone(), std::iter::once(expr.clone()));
 
         // Don't suggest local references as they are not valid for return
-        if matches!(expr, Expr::Local(_)) && ty.contains_reference(db) {
+        if matches!(expr, Expr::Local(_))
+            && ty.contains_reference(db)
+            && ctx.config.enable_borrowcheck
+        {
             return None;
         }
 
@@ -87,6 +91,52 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
     })
 }
 
+/// # Associated constant tactic
+///
+/// Attempts to fulfill the goal by trying constants defined as associated items.
+/// Only considers them on types that are in scope.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+///
+/// Returns iterator that yields elements that unify with `goal`.
+///
+/// _Note that there is no use of calling this tactic in every iteration as the output does not
+/// depend on the current state of `lookup`_
+pub(super) fn assoc_const<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+
+    defs.iter()
+        .filter_map(|def| match def {
+            ScopeDef::ModuleDef(ModuleDef::Adt(it)) => Some(it),
+            _ => None,
+        })
+        .flat_map(|it| Impl::all_for_type(db, it.ty(db)))
+        .filter(|it| !it.is_unsafe(db))
+        .flat_map(|it| it.items(db))
+        .filter(move |it| it.is_visible_from(db, module))
+        .filter_map(AssocItem::as_const)
+        .filter_map(|it| {
+            let expr = Expr::Const(it);
+            let ty = it.ty(db);
+
+            if ty.contains_unknown() {
+                return None;
+            }
+
+            lookup.insert(ty.clone(), std::iter::once(expr.clone()));
+
+            ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr)
+        })
+}
+
 /// # Data constructor tactic
 ///
 /// Attempts different data constructors for enums and structs in scope
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 24a32086f3d..ebfbb83bb91 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -105,7 +105,7 @@ fn add_missing_impl_members_inner(
     assist_id: &'static str,
     label: &'static str,
 ) -> Option<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "add_missing_impl_members_inner").entered();
+    let _p = tracing::info_span!("add_missing_impl_members_inner").entered();
     let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
     let impl_ = ctx.sema.to_def(&impl_def)?;
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index 3bd003a267a..fe895eb2598 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -140,7 +140,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         acc.add_group(
             &group_label,
             assist_id,
-            format!("Import `{}`", import_name),
+            format!("Import `{import_name}`"),
             range,
             |builder| {
                 let scope = match scope.clone() {
@@ -165,7 +165,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
                 acc.add_group(
                     &group_label,
                     assist_id,
-                    format!("Import `{} as _`", import_name),
+                    format!("Import `{import_name} as _`"),
                     range,
                     |builder| {
                         let scope = match scope.clone() {
@@ -272,8 +272,10 @@ fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Modu
     // cost of importing from another crate
     let crate_boundary_cost = if current.krate() == item.krate() {
         0
-    } else if item.krate().is_builtin(db) {
+    } else if item.krate().origin(db).is_local() {
         2
+    } else if item.krate().is_builtin(db) {
+        3
     } else {
         4
     };
@@ -366,6 +368,49 @@ pub struct HashMap;
     }
 
     #[test]
+    fn prefer_workspace() {
+        let before = r"
+//- /main.rs crate:main deps:foo,bar
+HashMap$0::new();
+
+//- /lib.rs crate:foo
+pub mod module {
+    pub struct HashMap;
+}
+
+//- /lib.rs crate:bar library
+pub struct HashMap;
+        ";
+
+        check_auto_import_order(before, &["Import `foo::module::HashMap`", "Import `bar::HashMap`"])
+    }
+
+    #[test]
+    fn prefer_non_local_over_long_path() {
+        let before = r"
+//- /main.rs crate:main deps:foo,bar
+HashMap$0::new();
+
+//- /lib.rs crate:foo
+pub mod deeply {
+    pub mod nested {
+        pub mod module {
+            pub struct HashMap;
+        }
+    }
+}
+
+//- /lib.rs crate:bar library
+pub struct HashMap;
+        ";
+
+        check_auto_import_order(
+            before,
+            &["Import `bar::HashMap`", "Import `foo::deeply::nested::module::HashMap`"],
+        )
+    }
+
+    #[test]
     fn not_applicable_if_scope_inside_macro() {
         check_assist_not_applicable(
             auto_import,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
index 71436e65804..c95e24693d4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -228,7 +228,7 @@ fn replace_usages(
 
                     edit.replace(
                         prefix_expr.syntax().text_range(),
-                        format!("{} == Bool::False", inner_expr),
+                        format!("{inner_expr} == Bool::False"),
                     );
                 } else if let Some((record_field, initializer)) = name
                     .as_name_ref()
@@ -275,7 +275,7 @@ fn replace_usages(
                 } else if let Some(receiver) = find_method_call_expr_usage(&name) {
                     edit.replace(
                         receiver.syntax().text_range(),
-                        format!("({} == Bool::True)", receiver),
+                        format!("({receiver} == Bool::True)"),
                     );
                 } else if name.syntax().ancestors().find_map(ast::UseTree::cast).is_none() {
                     // for any other usage in an expression, replace it with a check that it is the true variant
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 9adbdd220c2..76188715524 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -242,7 +242,7 @@ fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(
             .iter()
             .enumerate()
             .map(|(index, _)| {
-                let new_name = new_field_name((format!("_{}", index)).into(), &data.names_in_scope);
+                let new_name = new_field_name((format!("_{index}")).into(), &data.names_in_scope);
                 (index.to_string().into(), new_name)
             })
             .collect(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
index 2725a97de8e..28f645171c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
@@ -1,4 +1,4 @@
-use crate::{AssistContext, Assists};
+use crate::{utils, AssistContext, Assists};
 use hir::DescendPreference;
 use ide_db::{
     assists::{AssistId, AssistKind},
@@ -8,8 +8,12 @@ use ide_db::{
     },
 };
 use itertools::Itertools;
-use stdx::format_to;
-use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
+use syntax::{
+    ast::{self, make},
+    ted, AstNode, AstToken, NodeOrToken,
+    SyntaxKind::WHITESPACE,
+    T,
+};
 
 // Assist: extract_expressions_from_format_string
 //
@@ -34,6 +38,7 @@ pub(crate) fn extract_expressions_from_format_string(
 ) -> Option<()> {
     let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
     let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
+    let tt_delimiter = tt.left_delimiter_token()?.kind();
 
     let expanded_t = ast::String::cast(
         ctx.sema
@@ -61,72 +66,63 @@ pub(crate) fn extract_expressions_from_format_string(
         "Extract format expressions",
         tt.syntax().text_range(),
         |edit| {
-            let fmt_range = fmt_string.syntax().text_range();
-
-            // Replace old format string with new format string whose arguments have been extracted
-            edit.replace(fmt_range, new_fmt);
-
-            // Insert cursor at end of format string
-            edit.insert(fmt_range.end(), "$0");
+            let tt = edit.make_mut(tt);
 
             // Extract existing arguments in macro
-            let tokens =
-                tt.token_trees_and_tokens().collect_vec();
-
-            let mut existing_args: Vec<String> = vec![];
+            let tokens = tt.token_trees_and_tokens().collect_vec();
 
-            let mut current_arg = String::new();
-            if let [_opening_bracket, NodeOrToken::Token(format_string), _args_start_comma, tokens @ .., NodeOrToken::Token(end_bracket)] =
+            let existing_args = if let [_opening_bracket, NodeOrToken::Token(_format_string), _args_start_comma, tokens @ .., NodeOrToken::Token(_end_bracket)] =
                 tokens.as_slice()
             {
-                for t in tokens {
-                    match t {
-                        NodeOrToken::Node(n) => {
-                            format_to!(current_arg, "{n}");
-                        },
-                        NodeOrToken::Token(t) if t.kind() == COMMA => {
-                            existing_args.push(current_arg.trim().into());
-                            current_arg.clear();
-                        },
-                        NodeOrToken::Token(t) => {
-                            current_arg.push_str(t.text());
-                        },
-                    }
-                }
-                existing_args.push(current_arg.trim().into());
+                let args = tokens.split(|it| matches!(it, NodeOrToken::Token(t) if t.kind() == T![,])).map(|arg| {
+                    // Strip off leading and trailing whitespace tokens
+                    let arg = match arg.split_first() {
+                        Some((NodeOrToken::Token(t), rest)) if t.kind() == WHITESPACE => rest,
+                        _ => arg,
+                    };
+                    let arg = match arg.split_last() {
+                        Some((NodeOrToken::Token(t), rest)) if t.kind() == WHITESPACE => rest,
+                        _ => arg,
+                    };
+                    arg
+                });
 
-                // delete everything after the format string till end bracket
-                // we're going to insert the new arguments later
-                edit.delete(TextRange::new(
-                    format_string.text_range().end(),
-                    end_bracket.text_range().start(),
-                ));
-            }
+                args.collect()
+            } else {
+                vec![]
+            };
 
             // Start building the new args
             let mut existing_args = existing_args.into_iter();
-            let mut args = String::new();
+            let mut new_tt_bits = vec![NodeOrToken::Token(make::tokens::literal(&new_fmt))];
+            let mut placeholder_indexes = vec![];
 
-            let mut placeholder_idx = 1;
+            for arg in extracted_args {
+                if matches!(arg, Arg::Expr(_) | Arg::Placeholder) {
+                    // insert ", " before each arg
+                    new_tt_bits.extend_from_slice(&[
+                        NodeOrToken::Token(make::token(T![,])),
+                        NodeOrToken::Token(make::tokens::single_space()),
+                    ]);
+                }
 
-            for extracted_args in extracted_args {
-                match extracted_args {
-                    Arg::Expr(s)=> {
-                        args.push_str(", ");
+                match arg {
+                    Arg::Expr(s) => {
                         // insert arg
-                        args.push_str(&s);
+                        // FIXME: use the crate's edition for parsing
+                        let expr = ast::Expr::parse(&s, syntax::Edition::CURRENT).syntax_node();
+                        let mut expr_tt = utils::tt_from_syntax(expr);
+                        new_tt_bits.append(&mut expr_tt);
                     }
                     Arg::Placeholder => {
-                        args.push_str(", ");
                         // try matching with existing argument
                         match existing_args.next() {
-                            Some(ea) => {
-                                args.push_str(&ea);
+                            Some(arg) => {
+                                new_tt_bits.extend_from_slice(arg);
                             }
                             None => {
-                                // insert placeholder
-                                args.push_str(&format!("${placeholder_idx}"));
-                                placeholder_idx += 1;
+                                placeholder_indexes.push(new_tt_bits.len());
+                                new_tt_bits.push(NodeOrToken::Token(make::token(T![_])));
                             }
                         }
                     }
@@ -134,8 +130,31 @@ pub(crate) fn extract_expressions_from_format_string(
                 }
             }
 
+
             // Insert new args
-            edit.insert(fmt_range.end(), args);
+            let new_tt = make::token_tree(tt_delimiter, new_tt_bits).clone_for_update();
+            ted::replace(tt.syntax(), new_tt.syntax());
+
+            if let Some(cap) = ctx.config.snippet_cap {
+                // Add placeholder snippets over placeholder args
+                for pos in placeholder_indexes {
+                    // Skip the opening delimiter
+                    let Some(NodeOrToken::Token(placeholder)) =
+                        new_tt.token_trees_and_tokens().skip(1).nth(pos)
+                    else {
+                        continue;
+                    };
+
+                    if stdx::always!(placeholder.kind() == T![_]) {
+                        edit.add_placeholder_snippet_token(cap, placeholder);
+                    }
+                }
+
+                // Add the final tabstop after the format literal
+                if let Some(NodeOrToken::Token(literal)) = new_tt.token_trees_and_tokens().nth(1) {
+                    edit.add_tabstop_after_token(cap, literal);
+                }
+            }
         },
     );
 
@@ -145,7 +164,7 @@ pub(crate) fn extract_expressions_from_format_string(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::tests::check_assist;
+    use crate::tests::{check_assist, check_assist_no_snippet_cap};
 
     #[test]
     fn multiple_middle_arg() {
@@ -195,7 +214,7 @@ fn main() {
 "#,
             r#"
 fn main() {
-    print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
+    print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, ${1:_});
 }
 "#,
         );
@@ -292,4 +311,22 @@ fn main() {
             "#,
         );
     }
+
+    #[test]
+    fn without_snippets() {
+        check_assist_no_snippet_cap(
+            extract_expressions_from_format_string,
+            r#"
+//- minicore: fmt
+fn main() {
+    print!("{} {x + 1:b} {} {}$0", y + 2, 2);
+}
+"#,
+            r#"
+fn main() {
+    print!("{} {:b} {} {}", y + 2, x + 1, 2, _);
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 748acb46efb..19521b8a4b7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -758,7 +758,7 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<Ass
 }
 
 fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
-    make::path_from_text(&format!("{}::{}", qual_path_ty, path_expr_seg))
+    make::path_from_text(&format!("{qual_path_ty}::{path_expr_seg}"))
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 0fc122d623f..41693855bea 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -393,9 +393,9 @@ impl FunctionBuilder {
 /// The rule for whether we focus a return type or not (and thus focus the function body),
 /// is rather simple:
 /// * If we could *not* infer what the return type should be, focus it (so the user can fill-in
-/// the correct return type).
+///   the correct return type).
 /// * If we could infer the return type, don't focus it (and thus focus the function body) so the
-/// user can change the `todo!` function body.
+///   user can change the `todo!` function body.
 fn make_return_type(
     ctx: &AssistContext<'_>,
     expr: &ast::Expr,
@@ -918,9 +918,9 @@ fn filter_generic_params(ctx: &AssistContext<'_>, node: SyntaxNode) -> Option<hi
 /// Say we have a trait bound `Struct<T>: Trait<U>`. Given `necessary_params`, when is it relevant
 /// and when not? Some observations:
 /// - When `necessary_params` contains `T`, it's likely that we want this bound, but now we have
-/// an extra param to consider: `U`.
+///   an extra param to consider: `U`.
 /// - On the other hand, when `necessary_params` contains `U` (but not `T`), then it's unlikely
-/// that we want this bound because it doesn't really constrain `U`.
+///   that we want this bound because it doesn't really constrain `U`.
 ///
 /// (FIXME?: The latter clause might be overstating. We may want to include the bound if the self
 /// type does *not* include generic params at all - like `Option<i32>: From<U>`)
@@ -928,7 +928,7 @@ fn filter_generic_params(ctx: &AssistContext<'_>, node: SyntaxNode) -> Option<hi
 /// Can we make this a bit more formal? Let's define "dependency" between generic parameters and
 /// trait bounds:
 /// - A generic parameter `T` depends on a trait bound if `T` appears in the self type (i.e. left
-/// part) of the bound.
+///   part) of the bound.
 /// - A trait bound depends on a generic parameter `T` if `T` appears in the bound.
 ///
 /// Using the notion, what we want is all the bounds that params in `necessary_params`
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index e90a032f1cb..60214aaaf69 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -47,7 +47,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     }
 
     // Prepend set_ to fn names.
-    fn_names.iter_mut().for_each(|name| *name = format!("set_{}", name));
+    fn_names.iter_mut().for_each(|name| *name = format!("set_{name}"));
 
     // Return early if we've found an existing fn
     let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 91eaa96b6cb..6aa561ad7f0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -105,7 +105,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
         "Generate `IndexMut` impl from this `Index` trait",
         target,
         |edit| {
-            edit.insert(target.start(), format!("$0{}\n\n", impl_def));
+            edit.insert(target.start(), format!("$0{impl_def}\n\n"));
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 44307ffd75b..88fa6dc745e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -368,7 +368,7 @@ fn inline(
                     _ => None,
                 })
                 .for_each(|usage| {
-                    ted::replace(usage, &this());
+                    ted::replace(usage, this());
                 });
         }
     }
@@ -483,7 +483,7 @@ fn inline(
                 cov_mark::hit!(inline_call_inline_direct_field);
                 field.replace_expr(replacement.clone_for_update());
             } else {
-                ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
+                ted::replace(usage.syntax(), replacement.syntax().clone_for_update());
             }
         };
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
index dee74afcbe2..e405af5533d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
@@ -67,9 +67,9 @@ pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>)
                 edit.replace(
                     method_call.syntax().text_range(),
                     if sc.chars().all(|c| c.is_alphanumeric() || c == ':') {
-                        format!("{}::from({})", sc, receiver)
+                        format!("{sc}::from({receiver})")
                     } else {
-                        format!("<{}>::from({})", sc, receiver)
+                        format!("<{sc}>::from({receiver})")
                     },
                 );
             },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
index 2f3136f027b..7a0037fa202 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
@@ -86,7 +86,7 @@ pub(crate) fn merge_nested_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                 nested_if_cond.syntax().text().to_string()
             };
 
-            let replace_cond = format!("{} && {}", cond_text, nested_if_cond_text);
+            let replace_cond = format!("{cond_text} && {nested_if_cond_text}");
 
             edit.replace(cond_range, replace_cond);
             edit.replace(then_branch_range, nested_if_then_branch.syntax().text());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
index 99c55e9ff7c..799d36be93e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
@@ -48,7 +48,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 }
                 None => false,
             };
-            let expr = if need_to_add_ws { format!(" {}", expr) } else { expr.to_string() };
+            let expr = if need_to_add_ws { format!(" {expr}") } else { expr.to_string() };
 
             builder.replace(parens.syntax().text_range(), expr)
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 94e0519cba0..8a9229c549f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -290,4 +290,34 @@ fn f() { let a = 1; let b: Foo<i32> = todo$0!(); }"#,
 fn f() { let a = 1; let b: Foo<i32> = Foo(a); }"#,
         )
     }
+
+    #[test]
+    fn test_struct_assoc_item() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+struct Foo;
+impl Foo { const FOO: i32 = 0; }
+fn f() { let a: i32 = todo$0!(); }"#,
+            r#"struct Foo;
+impl Foo { const FOO: i32 = 0; }
+fn f() { let a: i32 = Foo::FOO; }"#,
+        )
+    }
+
+    #[test]
+    fn test_trait_assoc_item() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+struct Foo;
+trait Bar { const BAR: i32; }
+impl Bar for Foo { const BAR: i32 = 0; }
+fn f() { let a: i32 = todo$0!(); }"#,
+            r#"struct Foo;
+trait Bar { const BAR: i32; }
+impl Bar for Foo { const BAR: i32 = 0; }
+fn f() { let a: i32 = Foo::BAR; }"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index bc0c9b79c75..ba6ef1921ac 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -14,9 +14,9 @@ use syntax::{
         edit_in_place::{AttrsOwnerEdit, Indent, Removable},
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
-    ted, AstNode, AstToken, Direction, SourceFile,
+    ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile,
     SyntaxKind::*,
-    SyntaxNode, TextRange, TextSize, T,
+    SyntaxNode, SyntaxToken, TextRange, TextSize, T,
 };
 
 use crate::assist_context::{AssistContext, SourceChangeBuilder};
@@ -916,3 +916,46 @@ pub(crate) fn replace_record_field_expr(
         edit.replace(file_range.range, initializer.syntax().text());
     }
 }
+
+/// Creates a token tree list from a syntax node, creating the needed delimited sub token trees.
+/// Assumes that the input syntax node is a valid syntax tree.
+pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec<NodeOrToken<ast::TokenTree, SyntaxToken>> {
+    let mut tt_stack = vec![(None, vec![])];
+
+    for element in node.descendants_with_tokens() {
+        let NodeOrToken::Token(token) = element else { continue };
+
+        match token.kind() {
+            T!['('] | T!['{'] | T!['['] => {
+                // Found an opening delimiter, start a new sub token tree
+                tt_stack.push((Some(token.kind()), vec![]));
+            }
+            T![')'] | T!['}'] | T![']'] => {
+                // Closing a subtree
+                let (delimiter, tt) = tt_stack.pop().expect("unbalanced delimiters");
+                let (_, parent_tt) = tt_stack
+                    .last_mut()
+                    .expect("parent token tree was closed before it was completed");
+                let closing_delimiter = delimiter.map(|it| match it {
+                    T!['('] => T![')'],
+                    T!['{'] => T!['}'],
+                    T!['['] => T![']'],
+                    _ => unreachable!(),
+                });
+                stdx::always!(
+                    closing_delimiter == Some(token.kind()),
+                    "mismatched opening and closing delimiters"
+                );
+
+                let sub_tt = make::token_tree(delimiter.expect("unbalanced delimiters"), tt);
+                parent_tt.push(NodeOrToken::Node(sub_tt));
+            }
+            _ => {
+                let (_, current_tt) = tt_stack.last_mut().expect("unmatched delimiters");
+                current_tt.push(NodeOrToken::Token(token))
+            }
+        }
+    }
+
+    tt_stack.pop().expect("parent token tree was closed before it was completed").1
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
index 23a06404f30..f2a097afc86 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
@@ -254,7 +254,7 @@ fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<St
 
     let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap();
     let param = func.params().into_iter().nth(idx)?;
-    let pat = param.source(sema.db)?.value.right()?.pat()?;
+    let pat = sema.source(param)?.value.right()?.pat()?;
     let name = var_name_from_pat(&pat)?;
     normalize(&name.to_string())
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index 4005753773c..23d93d3b746 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -1,4 +1,5 @@
-//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
+//! Completes environment variables defined by Cargo
+//! (<https://doc.rust-lang.org/cargo/reference/environment-variables.html>)
 use hir::MacroFileIdExt;
 use ide_db::syntax_helpers::node_ext::macro_call_for_string_token;
 use syntax::{
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index ddb1aeb3711..7281c607da4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -15,7 +15,7 @@ pub(crate) fn complete_expr_path(
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
     expr_ctx: &PathExprCtx,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "complete_expr_path").entered();
+    let _p = tracing::info_span!("complete_expr_path").entered();
     if !ctx.qualifier_ctx.none() {
         return;
     }
@@ -334,7 +334,7 @@ pub(crate) fn complete_expr_path(
 }
 
 pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>) {
-    let _p = tracing::span!(tracing::Level::INFO, "complete_expr").entered();
+    let _p = tracing::info_span!("complete_expr").entered();
 
     if !ctx.config.enable_term_search {
         return;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
index 53fcb7ca6c0..b795bbd872a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
@@ -20,9 +20,9 @@ pub(crate) fn complete_field_list_tuple_variant(
     } = path_ctx
     {
         let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
-        add_keyword("pub(crate)", "pub(crate)");
-        add_keyword("pub(super)", "pub(super)");
-        add_keyword("pub", "pub");
+        add_keyword("pub(crate)", "pub(crate) $0");
+        add_keyword("pub(super)", "pub(super) $0");
+        add_keyword("pub", "pub $0");
     }
 }
 
@@ -32,8 +32,8 @@ pub(crate) fn complete_field_list_record_variant(
 ) {
     if ctx.qualifier_ctx.vis_node.is_none() {
         let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
-        add_keyword("pub(crate)", "pub(crate)");
-        add_keyword("pub(super)", "pub(super)");
-        add_keyword("pub", "pub");
+        add_keyword("pub(crate)", "pub(crate) $0");
+        add_keyword("pub(super)", "pub(super) $0");
+        add_keyword("pub", "pub $0");
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index d5a4e9ecdcc..71d44a57cb9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -207,8 +207,7 @@ fn import_on_the_fly(
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
-    let _p =
-        tracing::span!(tracing::Level::INFO, "import_on_the_fly", ?potential_import_name).entered();
+    let _p = tracing::info_span!("import_on_the_fly", ?potential_import_name).entered();
 
     ImportScope::find_insert_use_container(&position, &ctx.sema)?;
 
@@ -296,8 +295,7 @@ fn import_on_the_fly_pat_(
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat_", ?potential_import_name)
-        .entered();
+    let _p = tracing::info_span!("import_on_the_fly_pat_", ?potential_import_name).entered();
 
     ImportScope::find_insert_use_container(&position, &ctx.sema)?;
 
@@ -347,9 +345,7 @@ fn import_on_the_fly_method(
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
-    let _p =
-        tracing::span!(tracing::Level::INFO, "import_on_the_fly_method", ?potential_import_name)
-            .entered();
+    let _p = tracing::info_span!("import_on_the_fly_method", ?potential_import_name).entered();
 
     ImportScope::find_insert_use_container(&position, &ctx.sema)?;
 
@@ -397,13 +393,8 @@ fn import_assets_for_path(
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
 ) -> Option<ImportAssets> {
-    let _p = tracing::span!(
-        tracing::Level::INFO,
-        "import_assets_for_path",
-        ?potential_import_name,
-        ?qualifier
-    )
-    .entered();
+    let _p =
+        tracing::info_span!("import_assets_for_path", ?potential_import_name, ?qualifier).entered();
 
     let fuzzy_name_length = potential_import_name.len();
     let mut assets_for_path = ImportAssets::for_fuzzy_path(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
index 0a6a8633a2c..02298b1e9b0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
@@ -28,7 +28,7 @@ pub(crate) fn complete_item_list(
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
     kind: &ItemListKind,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "complete_item_list").entered();
+    let _p = tracing::info_span!("complete_item_list").entered();
     if path_ctx.is_trivial_path() {
         add_keywords(acc, ctx, Some(kind));
     }
@@ -79,7 +79,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
     let in_trait = matches!(kind, Some(ItemListKind::Trait));
     let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_)));
     let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
-    let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
+    let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
     let in_block = kind.is_none();
 
     if !in_trait_impl {
@@ -89,7 +89,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             }
             if in_item_list {
                 add_keyword("trait", "trait $1 {\n    $0\n}");
-                if no_qualifiers {
+                if no_vis_qualifiers {
                     add_keyword("impl", "impl $1 {\n    $0\n}");
                 }
             }
@@ -100,19 +100,20 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             add_keyword("enum", "enum $1 {\n    $0\n}");
             add_keyword("mod", "mod $0");
             add_keyword("static", "static $0");
+            add_keyword("async", "async $0");
             add_keyword("struct", "struct $0");
             add_keyword("trait", "trait $1 {\n    $0\n}");
             add_keyword("union", "union $1 {\n    $0\n}");
             add_keyword("use", "use $0");
-            if no_qualifiers {
+            if no_vis_qualifiers {
                 add_keyword("impl", "impl $1 {\n    $0\n}");
             }
         }
 
-        if !in_trait && !in_block && no_qualifiers {
-            add_keyword("pub(crate)", "pub(crate)");
-            add_keyword("pub(super)", "pub(super)");
-            add_keyword("pub", "pub");
+        if !in_trait && !in_block && no_vis_qualifiers {
+            add_keyword("pub(crate)", "pub(crate) $0");
+            add_keyword("pub(super)", "pub(super) $0");
+            add_keyword("pub", "pub $0");
         }
 
         if in_extern_block {
@@ -126,7 +127,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             }
 
             add_keyword("fn", "fn $1($2) {\n    $0\n}");
-            add_keyword("unsafe", "unsafe");
+            add_keyword("unsafe", "unsafe $0");
             add_keyword("const", "const $0");
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
index 1322c05e30e..d79b5398828 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
@@ -14,9 +14,9 @@ pub(crate) fn complete_for_and_where(
     match keyword_item {
         Item::Impl(it) => {
             if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
-                add_keyword("for", "for");
+                add_keyword("for", "for $0");
             }
-            add_keyword("where", "where");
+            add_keyword("where", "where $0");
         }
         Item::Enum(_)
         | Item::Fn(_)
@@ -24,7 +24,7 @@ pub(crate) fn complete_for_and_where(
         | Item::Trait(_)
         | Item::TypeAlias(_)
         | Item::Union(_) => {
-            add_keyword("where", "where");
+            add_keyword("where", "where $0");
         }
         _ => (),
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index c2faa2d939d..f307ba9eb33 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -21,7 +21,7 @@ pub(crate) fn complete_mod(
         return None;
     }
 
-    let _p = tracing::span!(tracing::Level::INFO, "completion::complete_mod").entered();
+    let _p = tracing::info_span!("completion::complete_mod").entered();
 
     let mut current_module = ctx.module;
     // For `mod $0`, `ctx.module` is its parent, but for `mod f$0`, it's `mod f` itself, but we're
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
index 40b2c831a5d..60cfb7e5a8c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
@@ -14,25 +14,27 @@ pub(crate) fn complete_pattern(
     ctx: &CompletionContext<'_>,
     pattern_ctx: &PatternContext,
 ) {
+    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
+
     match pattern_ctx.parent_pat.as_ref() {
         Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
         Some(Pat::RefPat(r)) => {
             if r.mut_token().is_none() {
-                acc.add_keyword(ctx, "mut");
+                add_keyword("mut", "mut $0");
             }
         }
         _ => {
             let tok = ctx.token.text_range().start();
             match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
                 (None, None) => {
-                    acc.add_keyword(ctx, "ref");
-                    acc.add_keyword(ctx, "mut");
+                    add_keyword("ref", "ref $0");
+                    add_keyword("mut", "mut $0");
                 }
                 (None, Some(m)) if tok < m.text_range().start() => {
-                    acc.add_keyword(ctx, "ref");
+                    add_keyword("ref", "ref $0");
                 }
                 (Some(r), None) if tok > r.text_range().end() => {
-                    acc.add_keyword(ctx, "mut");
+                    add_keyword("mut", "mut $0");
                 }
                 _ => (),
             }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index a230edd39b6..5041ef8d8a1 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -668,7 +668,7 @@ fn main() {
         check_edit(
             "unsafe",
             r#"fn main() { let x = true else {panic!()}.$0}"#,
-            r#"fn main() { let x = true else {panic!()}.unsafe}"#,
+            r#"fn main() { let x = true else {panic!()}.unsafe $0}"#,
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
index fd50fd4e8c5..2755329bb31 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -65,7 +65,7 @@ pub(crate) fn add_format_like_completions(
         let exprs = with_placeholders(exprs);
         for (label, macro_name) in KINDS {
             let snippet = if exprs.is_empty() {
-                format!(r#"{}({})"#, macro_name, out)
+                format!(r#"{macro_name}({out})"#)
             } else {
                 format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", "))
             };
@@ -108,7 +108,7 @@ mod tests {
 
         for (kind, input, output) in test_vector {
             let (parsed_string, _exprs) = parse_format_exprs(input).unwrap();
-            let snippet = format!(r#"{}("{}")"#, kind, parsed_string);
+            let snippet = format!(r#"{kind}("{parsed_string}")"#);
             assert_eq!(&snippet, output);
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index 2361d14aae7..b0714880932 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -15,7 +15,7 @@ pub(crate) fn complete_type_path(
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
     location: &TypeLocation,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "complete_type_path").entered();
+    let _p = tracing::info_span!("complete_type_path").entered();
 
     let scope_def_applicable = |def| {
         use hir::{GenericParam::*, ModuleDef::*};
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
index e0a959ad0b3..0ea5157fb46 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
@@ -33,7 +33,7 @@ pub(crate) fn complete_vis_path(
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
-                acc.add_keyword(ctx, "in");
+                acc.add_keyword_snippet(ctx, "in", "in $0");
             }
             acc.add_nameref_keywords(ctx);
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index db34beadc0f..992ca18bb06 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -452,6 +452,7 @@ pub(crate) struct CompletionContext<'a> {
     /// - crate-root
     ///  - mod foo
     ///   - mod bar
+    ///
     /// Here depth will be 2
     pub(crate) depth_from_crate_root: usize,
 }
@@ -585,8 +586,7 @@ impl CompletionContext<'_> {
     /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and
     /// passes all doc-aliases along, to funnel it into [`Completions::add_path_resolution`].
     pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "CompletionContext::process_all_names").entered();
+        let _p = tracing::info_span!("CompletionContext::process_all_names").entered();
         self.scope.process_all_names(&mut |name, def| {
             if self.is_scope_def_hidden(def) {
                 return;
@@ -597,8 +597,7 @@ impl CompletionContext<'_> {
     }
 
     pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
-        let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::process_all_names_raw")
-            .entered();
+        let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered();
         self.scope.process_all_names(f);
     }
 
@@ -656,7 +655,7 @@ impl<'a> CompletionContext<'a> {
         position @ FilePosition { file_id, offset }: FilePosition,
         config: &'a CompletionConfig,
     ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> {
-        let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::new").entered();
+        let _p = tracing::info_span!("CompletionContext::new").entered();
         let sema = Semantics::new(db);
 
         let original_file = sema.parse(file_id);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index f0c6e7a63b0..80ce5bd4cf2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -74,7 +74,7 @@ fn expand(
     mut fake_ident_token: SyntaxToken,
     relative_offset: TextSize,
 ) -> ExpansionResult {
-    let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::expand").entered();
+    let _p = tracing::info_span!("CompletionContext::expand").entered();
     let mut derive_ctx = None;
 
     'expansion: loop {
@@ -278,7 +278,7 @@ fn analyze(
     original_token: &SyntaxToken,
     self_token: &SyntaxToken,
 ) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
-    let _p = tracing::span!(tracing::Level::INFO, "CompletionContext::analyze").entered();
+    let _p = tracing::info_span!("CompletionContext::analyze").entered();
     let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } =
         expansion_result;
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index b9a2c383bdd..debfefc4801 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -483,7 +483,7 @@ impl Builder {
     }
 
     pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
-        let _p = tracing::span!(tracing::Level::INFO, "item::Builder::build").entered();
+        let _p = tracing::info_span!("item::Builder::build").entered();
 
         let label = self.label;
         let mut label_detail = None;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index a83fa28b875..8323b8f9331 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -238,7 +238,7 @@ pub fn resolve_completion_edits(
     FilePosition { file_id, offset }: FilePosition,
     imports: impl IntoIterator<Item = (String, String)>,
 ) -> Option<Vec<TextEdit>> {
-    let _p = tracing::span!(tracing::Level::INFO, "resolve_completion_edits").entered();
+    let _p = tracing::info_span!("resolve_completion_edits").entered();
     let sema = hir::Semantics::new(db);
 
     let original_file = sema.parse(file_id);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 8f563790737..ebdc813f3d7 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -353,7 +353,7 @@ fn render_resolution_pat(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_pat").entered();
+    let _p = tracing::info_span!("render_resolution_pat").entered();
     use hir::ModuleDef::*;
 
     if let ScopeDef::ModuleDef(Macro(mac)) = resolution {
@@ -371,7 +371,7 @@ fn render_resolution_path(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_path").entered();
+    let _p = tracing::info_span!("render_resolution_path").entered();
     use hir::ModuleDef::*;
 
     match resolution {
@@ -479,7 +479,7 @@ fn render_resolution_simple_(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_simple_").entered();
+    let _p = tracing::info_span!("render_resolution_simple_").entered();
 
     let db = ctx.db();
     let ctx = ctx.import_to_add(import_to_add);
@@ -1799,6 +1799,7 @@ fn go(world: &WorldSnapshot) { go(w$0) }
 "#,
             expect![[r#"
                 lc world [type+name+local]
+                ex world [type]
                 st WorldSnapshot {…} []
                 st &WorldSnapshot {…} [type]
                 st WorldSnapshot []
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index 0d24882156d..a6a1c79e668 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -6,7 +6,7 @@ use ide_db::SymbolKind;
 use crate::{item::CompletionItem, render::RenderContext};
 
 pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_const").entered();
+    let _p = tracing::info_span!("render_const").entered();
     render(ctx, const_)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 1634b0a9206..48c9d624f63 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -30,7 +30,7 @@ pub(crate) fn render_fn(
     local_name: Option<hir::Name>,
     func: hir::Function,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_fn").entered();
+    let _p = tracing::info_span!("render_fn").entered();
     render(ctx, local_name, func, FuncKind::Function(path_ctx))
 }
 
@@ -41,7 +41,7 @@ pub(crate) fn render_method(
     local_name: Option<hir::Name>,
     func: hir::Function,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_method").entered();
+    let _p = tracing::info_span!("render_method").entered();
     render(ctx, local_name, func, FuncKind::Method(dot_access, receiver))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index 9c5cb1e37d9..27435307d50 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -27,7 +27,7 @@ pub(crate) fn render_variant_lit(
     variant: hir::Variant,
     path: Option<hir::ModPath>,
 ) -> Option<Builder> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_variant_lit").entered();
+    let _p = tracing::info_span!("render_variant_lit").entered();
     let db = ctx.db();
 
     let name = local_name.unwrap_or_else(|| variant.name(db));
@@ -41,7 +41,7 @@ pub(crate) fn render_struct_literal(
     path: Option<hir::ModPath>,
     local_name: Option<hir::Name>,
 ) -> Option<Builder> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_struct_literal").entered();
+    let _p = tracing::info_span!("render_struct_literal").entered();
     let db = ctx.db();
 
     let name = local_name.unwrap_or_else(|| strukt.name(db));
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 8b81a95abbe..a6c8c0e853c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -17,7 +17,7 @@ pub(crate) fn render_macro(
     name: hir::Name,
     macro_: hir::Macro,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered();
+    let _p = tracing::info_span!("render_macro").entered();
     render(ctx, *kind == PathKind::Use, *has_macro_bang, *has_call_parens, name, macro_)
 }
 
@@ -27,7 +27,7 @@ pub(crate) fn render_macro_pat(
     name: hir::Name,
     macro_: hir::Macro,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_macro_pat").entered();
+    let _p = tracing::info_span!("render_macro_pat").entered();
     render(ctx, false, false, false, name, macro_)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index c07966f7a7a..942670be2a3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -20,7 +20,7 @@ pub(crate) fn render_struct_pat(
     strukt: hir::Struct,
     local_name: Option<Name>,
 ) -> Option<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_struct_pat").entered();
+    let _p = tracing::info_span!("render_struct_pat").entered();
 
     let fields = strukt.fields(ctx.db());
     let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, strukt)?;
@@ -50,7 +50,7 @@ pub(crate) fn render_variant_pat(
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
 ) -> Option<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_variant_pat").entered();
+    let _p = tracing::info_span!("render_variant_pat").entered();
 
     let fields = variant.fields(ctx.db());
     let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index 8f80793dd72..47254e6a184 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -10,7 +10,7 @@ pub(crate) fn render_type_alias(
     ctx: RenderContext<'_>,
     type_alias: hir::TypeAlias,
 ) -> Option<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_type_alias").entered();
+    let _p = tracing::info_span!("render_type_alias").entered();
     render(ctx, type_alias, false)
 }
 
@@ -18,7 +18,7 @@ pub(crate) fn render_type_alias_with_eq(
     ctx: RenderContext<'_>,
     type_alias: hir::TypeAlias,
 ) -> Option<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_type_alias_with_eq").entered();
+    let _p = tracing::info_span!("render_type_alias_with_eq").entered();
     render(ctx, type_alias, true)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index a653314233d..545c2a2a8a0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -141,6 +141,7 @@ impl Unit {
             un Union        Union
             ev TupleV(…)    TupleV(u32)
             bt u32          u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -217,6 +218,7 @@ fn complete_in_block() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -264,6 +266,7 @@ fn complete_after_if_expr() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -336,6 +339,7 @@ fn completes_in_loop_ctx() {
         expect![[r#"
             fn my()        fn()
             bt u32         u32
+            kw async
             kw break
             kw const
             kw continue
@@ -799,6 +803,7 @@ fn foo() { if foo {} $0 }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -839,6 +844,7 @@ fn foo() { if foo {} el$0 }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -927,6 +933,7 @@ fn foo() { if foo {} $0 let x = 92; }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -967,6 +974,7 @@ fn foo() { if foo {} el$0 let x = 92; }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -1007,6 +1015,7 @@ fn foo() { if foo {} el$0 { let x = 92; } }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw else
@@ -1059,6 +1068,7 @@ pub struct UnstableThisShouldNotBeListed;
             fn main()      fn()
             md std
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -1111,6 +1121,7 @@ pub struct UnstableButWeAreOnNightlyAnyway;
             md std
             st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
             bt u32                    u32
+            kw async
             kw const
             kw crate::
             kw enum
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
index de3fd05189f..09254aed7cb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
@@ -6,6 +6,8 @@ use expect_test::{expect, Expect};
 
 use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
 
+use super::check_edit;
+
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
     expect.assert_eq(&actual)
@@ -152,3 +154,90 @@ struct Foo {
         "#]],
     )
 }
+
+#[test]
+fn add_space_after_vis_kw() {
+    check_edit(
+        "pub(crate)",
+        r"
+$0
+",
+        r#"
+pub(crate) $0
+"#,
+    );
+
+    check_edit(
+        "pub",
+        r"
+$0
+",
+        r#"
+pub $0
+"#,
+    );
+
+    check_edit(
+        "pub(super)",
+        r"
+$0
+",
+        r#"
+pub(super) $0
+"#,
+    );
+
+    check_edit(
+        "in",
+        r"
+pub($0)
+",
+        r#"
+pub(in $0)
+"#,
+    );
+}
+
+#[test]
+fn add_space_after_unsafe_kw() {
+    check_edit(
+        "unsafe",
+        r"
+$0
+",
+        r#"
+unsafe $0
+"#,
+    );
+}
+
+#[test]
+fn add_space_after_for_where_kw() {
+    check_edit(
+        "for",
+        r#"
+struct S {}
+
+impl Copy $0
+"#,
+        r#"
+struct S {}
+
+impl Copy for $0
+"#,
+    );
+
+    check_edit(
+        "where",
+        r#"
+struct S {}
+
+impl Copy for S $0
+"#,
+        r#"
+struct S {}
+
+impl Copy for S where $0
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
index 2b5b4dd773c..c37900478e1 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
@@ -14,6 +14,7 @@ fn in_mod_item_list() {
         r#"mod tests { $0 }"#,
         expect![[r#"
             ma makro!(…)           macro_rules! makro
+            kw async
             kw const
             kw crate::
             kw enum
@@ -47,6 +48,7 @@ fn in_source_file_item_list() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
+            kw async
             kw const
             kw crate::
             kw enum
@@ -79,6 +81,7 @@ fn in_item_list_after_attr() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
+            kw async
             kw const
             kw crate::
             kw enum
@@ -132,6 +135,7 @@ fn after_visibility() {
     check(
         r#"pub $0"#,
         expect![[r#"
+            kw async
             kw const
             kw enum
             kw extern
@@ -356,6 +360,7 @@ fn after_unit_struct() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
+            kw async
             kw const
             kw crate::
             kw enum
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index 67cf551fce8..8720cb555a1 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -819,3 +819,34 @@ pub enum Enum {
         "#]],
     );
 }
+
+#[test]
+fn add_space_after_mut_ref_kw() {
+    check_edit(
+        "mut",
+        r#"
+fn foo() {
+    let $0
+}
+"#,
+        r#"
+fn foo() {
+    let mut $0
+}
+"#,
+    );
+
+    check_edit(
+        "ref",
+        r#"
+fn foo() {
+    let $0
+}
+"#,
+        r#"
+fn foo() {
+    let ref $0
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
index e64ec74c610..56162bb57b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
@@ -2,6 +2,8 @@ use expect_test::{expect, Expect};
 
 use crate::tests::completion_list;
 
+use super::check_edit;
+
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(ra_fixture);
     expect.assert_eq(&actual);
@@ -301,3 +303,48 @@ fn foo() {
         expect![[r#""#]],
     )
 }
+
+#[test]
+fn add_space_after_vis_kw() {
+    check_edit(
+        "pub(crate)",
+        r"
+pub(crate) struct S {
+    $0
+}
+",
+        r#"
+pub(crate) struct S {
+    pub(crate) $0
+}
+"#,
+    );
+
+    check_edit(
+        "pub",
+        r"
+pub struct S {
+    $0
+}
+",
+        r#"
+pub struct S {
+    pub $0
+}
+"#,
+    );
+
+    check_edit(
+        "pub(super)",
+        r"
+pub(super) struct S {
+    $0
+}
+",
+        r#"
+pub(super) struct S {
+    pub(super) $0
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index 69d8fe91040..2ae7d37889e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1017,6 +1017,7 @@ fn here_we_go() {
             fn here_we_go()    fn()
             st Foo (alias Bar) Foo
             bt u32             u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -1066,6 +1067,7 @@ fn here_we_go() {
             fn here_we_go()           fn()
             st Foo (alias Bar, Qux, Baz) Foo
             bt u32                    u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -1188,6 +1190,7 @@ fn bar() { qu$0 }
             fn bar()             fn()
             fn foo() (alias qux) fn()
             bt u32               u32
+            kw async
             kw const
             kw crate::
             kw enum
@@ -1443,6 +1446,7 @@ fn foo() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
+            kw async
             kw const
             kw crate::
             kw enum
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
index 98d2e817546..088d2ec5e3f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
@@ -28,7 +28,7 @@ impl ActiveParameter {
             return None;
         }
         let param = params.swap_remove(idx);
-        Some(ActiveParameter { ty: param.ty().clone(), src: param.source(sema.db) })
+        Some(ActiveParameter { ty: param.ty().clone(), src: sema.source(param) })
     }
 
     pub fn ident(&self) -> Option<ast::Name> {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index ce9a5f0dd29..74c8fc96d4a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -15,13 +15,12 @@ use crate::{symbol_index::SymbolsDatabase, ChangeWithProcMacros, RootDatabase};
 
 impl RootDatabase {
     pub fn request_cancellation(&mut self) {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "RootDatabase::request_cancellation").entered();
+        let _p = tracing::info_span!("RootDatabase::request_cancellation").entered();
         self.synthetic_write(Durability::LOW);
     }
 
     pub fn apply_change(&mut self, change: ChangeWithProcMacros) {
-        let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered();
+        let _p = tracing::info_span!("RootDatabase::apply_change").entered();
         self.request_cancellation();
         tracing::trace!("apply_change {:?}", change);
         if let Some(roots) = &change.source_change.roots {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 634277e8698..a75a708d956 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -413,7 +413,7 @@ impl NameClass {
     }
 
     pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameClass::classify").entered();
+        let _p = tracing::info_span!("NameClass::classify").entered();
 
         let parent = name.syntax().parent()?;
 
@@ -505,8 +505,7 @@ impl NameClass {
         sema: &Semantics<'_, RootDatabase>,
         lifetime: &ast::Lifetime,
     ) -> Option<NameClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameClass::classify_lifetime", ?lifetime)
-            .entered();
+        let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered();
         let parent = lifetime.syntax().parent()?;
 
         if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
@@ -597,8 +596,7 @@ impl NameRefClass {
         sema: &Semantics<'_, RootDatabase>,
         name_ref: &ast::NameRef,
     ) -> Option<NameRefClass> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "NameRefClass::classify", ?name_ref).entered();
+        let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered();
 
         let parent = name_ref.syntax().parent()?;
 
@@ -697,8 +695,7 @@ impl NameRefClass {
         sema: &Semantics<'_, RootDatabase>,
         lifetime: &ast::Lifetime,
     ) -> Option<NameRefClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
-            .entered();
+        let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered();
         if lifetime.text() == "'static" {
             return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime)));
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index e445e9fb68d..51ac0b71911 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -15,7 +15,7 @@ use crate::RootDatabase;
 /// you'd want to include minicore (see `test_utils::MiniCore`) declaration at
 /// the start of your tests:
 ///
-/// ```
+/// ```text
 /// //- minicore: iterator, ord, derive
 /// ```
 pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
index db44b1e7232..c069e1c25b6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
@@ -35,13 +35,13 @@ pub fn pick_token<T: AstToken>(mut tokens: TokenAtOffset<SyntaxToken>) -> Option
 
 /// Converts the mod path struct into its ast representation.
 pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
-    let _p = tracing::span!(tracing::Level::INFO, "mod_path_to_ast").entered();
+    let _p = tracing::info_span!("mod_path_to_ast").entered();
 
     let mut segments = Vec::new();
     let mut is_abs = false;
     match path.kind {
         hir::PathKind::Plain => {}
-        hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
+        hir::PathKind::SELF => segments.push(make::path_segment_self()),
         hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
         hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
             segments.push(make::path_segment_crate())
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index 4caecb3f2fe..088717a66e5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -208,7 +208,7 @@ impl ImportAssets {
         cfg: ImportPathConfig,
         prefix_kind: PrefixKind,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_imports").entered();
+        let _p = tracing::info_span!("ImportAssets::search_for_imports").entered();
         self.search_for(sema, Some(prefix_kind), cfg)
     }
 
@@ -218,8 +218,7 @@ impl ImportAssets {
         sema: &Semantics<'_, RootDatabase>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_relative_paths")
-            .entered();
+        let _p = tracing::info_span!("ImportAssets::search_for_relative_paths").entered();
         self.search_for(sema, None, cfg)
     }
 
@@ -259,7 +258,7 @@ impl ImportAssets {
         prefixed: Option<PrefixKind>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for").entered();
+        let _p = tracing::info_span!("ImportAssets::search_for").entered();
 
         let scope = match sema.scope(&self.candidate_node) {
             Some(it) => it,
@@ -303,7 +302,7 @@ impl ImportAssets {
     }
 
     fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
-        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::scope_definitions").entered();
+        let _p = tracing::info_span!("ImportAssets::scope_definitions").entered();
         let mut scope_definitions = FxHashSet::default();
         if let Some(scope) = sema.scope(&self.candidate_node) {
             scope.process_all_names(&mut |_, scope_def| {
@@ -321,8 +320,7 @@ fn path_applicable_imports(
     mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
     scope_filter: impl Fn(ItemInNs) -> bool + Copy,
 ) -> FxHashSet<LocatedImport> {
-    let _p =
-        tracing::span!(tracing::Level::INFO, "ImportAssets::path_applicable_imports").entered();
+    let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
 
     match &path_candidate.qualifier {
         None => {
@@ -369,7 +367,7 @@ fn import_for_item(
     original_item: ItemInNs,
     scope_filter: impl Fn(ItemInNs) -> bool,
 ) -> Option<LocatedImport> {
-    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::import_for_item").entered();
+    let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
     let [first_segment, ..] = unresolved_qualifier else { return None };
 
     let item_as_assoc = item_as_assoc(db, original_item);
@@ -503,7 +501,7 @@ fn trait_applicable_items(
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
 ) -> FxHashSet<LocatedImport> {
-    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::trait_applicable_items").entered();
+    let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered();
 
     let db = sema.db;
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index 026d4e36f97..9102980677c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -194,7 +194,7 @@ fn insert_use_with_alias_option(
     cfg: &InsertUseConfig,
     alias: Option<ast::Rename>,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "insert_use_with_alias_option").entered();
+    let _p = tracing::info_span!("insert_use_with_alias_option").entered();
     let mut mb = match cfg.granularity {
         ImportGranularity::Crate => Some(MergeBehavior::Crate),
         ImportGranularity::Module => Some(MergeBehavior::Module),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
index 1b6f650768b..47549a1d008 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
@@ -21,7 +21,7 @@ pub fn items_with_name<'a>(
     assoc_item_search: AssocSearchMode,
 ) -> impl Iterator<Item = ItemInNs> + 'a {
     let krate_name = krate.display_name(sema.db).map(|name| name.to_string());
-    let _p = tracing::span!(tracing::Level::INFO, "items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate_name)
+    let _p = tracing::info_span!("items_with_name", name = name.text(), assoc_item_search = ?assoc_item_search, crate = ?krate_name)
         .entered();
 
     let prefix = matches!(name, NameToImport::Prefix(..));
@@ -72,7 +72,7 @@ fn find_items<'a>(
     local_query: symbol_index::Query,
     external_query: import_map::Query,
 ) -> impl Iterator<Item = ItemInNs> + 'a {
-    let _p = tracing::span!(tracing::Level::INFO, "find_items").entered();
+    let _p = tracing::info_span!("find_items").entered();
     let db = sema.db;
 
     // NOTE: `external_query` includes `assoc_item_search`, so we don't need to
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index 58077f636b6..62104fb7dce 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -11,9 +11,9 @@ use hir::db::DefDatabase;
 use crate::{
     base_db::{
         salsa::{Database, ParallelDatabase, Snapshot},
-        Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt,
+        Cancelled, CrateId, SourceDatabase, SourceDatabaseExt,
     },
-    FxHashSet, FxIndexMap, RootDatabase,
+    FxIndexMap, RootDatabase,
 };
 
 /// We're indexing many crates.
@@ -29,26 +29,17 @@ pub struct ParallelPrimeCachesProgress {
 
 pub fn parallel_prime_caches(
     db: &RootDatabase,
-    num_worker_threads: u8,
+    num_worker_threads: usize,
     cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync),
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "parallel_prime_caches").entered();
+    let _p = tracing::info_span!("parallel_prime_caches").entered();
 
     let graph = db.crate_graph();
     let mut crates_to_prime = {
-        let crate_ids = compute_crates_to_prime(db, &graph);
-
         let mut builder = topologic_sort::TopologicalSortIter::builder();
 
-        for &crate_id in &crate_ids {
-            let crate_data = &graph[crate_id];
-            let dependencies = crate_data
-                .dependencies
-                .iter()
-                .map(|d| d.crate_id)
-                .filter(|i| crate_ids.contains(i));
-
-            builder.add(crate_id, dependencies);
+        for crate_id in graph.iter() {
+            builder.add(crate_id, graph[crate_id].dependencies.iter().map(|d| d.crate_id));
         }
 
         builder.build()
@@ -62,13 +53,20 @@ pub fn parallel_prime_caches(
     let (work_sender, progress_receiver) = {
         let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
         let (work_sender, work_receiver) = crossbeam_channel::unbounded();
+        let graph = graph.clone();
         let prime_caches_worker = move |db: Snapshot<RootDatabase>| {
             while let Ok((crate_id, crate_name)) = work_receiver.recv() {
                 progress_sender
                     .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
 
-                // This also computes the DefMap
-                db.import_map(crate_id);
+                let file_id = graph[crate_id].root_file_id;
+                let root_id = db.file_source_root(file_id);
+                if db.source_root(root_id).is_library {
+                    db.crate_def_map(crate_id);
+                } else {
+                    // This also computes the DefMap
+                    db.import_map(crate_id);
+                }
 
                 progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?;
             }
@@ -76,13 +74,13 @@ pub fn parallel_prime_caches(
             Ok::<_, crossbeam_channel::SendError<_>>(())
         };
 
-        for _ in 0..num_worker_threads {
+        for id in 0..num_worker_threads {
             let worker = prime_caches_worker.clone();
             let db = db.snapshot();
 
             stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
                 .allow_leak(true)
-                .name("PrimeCaches".to_owned())
+                .name(format!("PrimeCaches#{id}"))
                 .spawn(move || Cancelled::catch(|| worker(db)))
                 .expect("failed to spawn thread");
         }
@@ -96,7 +94,7 @@ pub fn parallel_prime_caches(
     // an index map is used to preserve ordering so we can sort the progress report in order of
     // "longest crate to index" first
     let mut crates_currently_indexing =
-        FxIndexMap::with_capacity_and_hasher(num_worker_threads as _, Default::default());
+        FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
 
     while crates_done < crates_total {
         db.unwind_if_cancelled();
@@ -144,19 +142,3 @@ pub fn parallel_prime_caches(
         cb(progress);
     }
 }
-
-fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet<CrateId> {
-    // We're only interested in the workspace crates and the `ImportMap`s of their direct
-    // dependencies, though in practice the latter also compute the `DefMap`s.
-    // We don't prime transitive dependencies because they're generally not visible in
-    // the current workspace.
-    graph
-        .iter()
-        .filter(|&id| {
-            let file_id = graph[id].root_file_id;
-            let root_id = db.file_source_root(file_id);
-            !db.source_root(root_id).is_library
-        })
-        .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id))
-        .collect()
-}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 288d56b534e..484c65c2b01 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -24,7 +24,7 @@ use std::fmt;
 
 use base_db::{AnchoredPathBuf, FileId, FileRange};
 use either::Either;
-use hir::{FieldSource, HasSource, HirFileIdExt, InFile, ModuleSource, Semantics};
+use hir::{FieldSource, HirFileIdExt, InFile, ModuleSource, Semantics};
 use span::SyntaxContextId;
 use stdx::{never, TupleExt};
 use syntax::{
@@ -109,7 +109,7 @@ impl Definition {
         let syn_ctx_is_root = |(range, ctx): (_, SyntaxContextId)| ctx.is_root().then_some(range);
         let res = match self {
             Definition::Macro(mac) => {
-                let src = mac.source(sema.db)?;
+                let src = sema.source(mac)?;
                 let name = match &src.value {
                     Either::Left(it) => it.name()?,
                     Either::Right(it) => it.name()?,
@@ -119,7 +119,7 @@ impl Definition {
                     .and_then(syn_ctx_is_root)
             }
             Definition::Field(field) => {
-                let src = field.source(sema.db)?;
+                let src = sema.source(field)?;
                 match &src.value {
                     FieldSource::Named(record_field) => {
                         let name = record_field.name()?;
@@ -154,18 +154,18 @@ impl Definition {
             }
             Definition::GenericParam(generic_param) => match generic_param {
                 hir::GenericParam::LifetimeParam(lifetime_param) => {
-                    let src = lifetime_param.source(sema.db)?;
+                    let src = sema.source(lifetime_param)?;
                     src.with_value(src.value.lifetime()?.syntax())
                         .original_file_range_opt(sema.db)
                         .and_then(syn_ctx_is_root)
                 }
                 _ => {
-                    let x = match generic_param {
+                    let param = 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 src = sema.source(param)?;
                     let name = match &src.value {
                         Either::Left(x) => x.name()?,
                         Either::Right(_) => return None,
@@ -176,14 +176,14 @@ impl Definition {
                 }
             },
             Definition::Label(label) => {
-                let src = label.source(sema.db);
+                let src = sema.source(label)?;
                 let lifetime = src.value.lifetime()?;
                 src.with_value(lifetime.syntax())
                     .original_file_range_opt(sema.db)
                     .and_then(syn_ctx_is_root)
             }
             Definition::ExternCrateDecl(it) => {
-                let src = it.source(sema.db)?;
+                let src = sema.source(it)?;
                 if let Some(rename) = src.value.rename() {
                     let name = rename.name()?;
                     src.with_value(name.syntax())
@@ -212,10 +212,10 @@ impl Definition {
             sema: &Semantics<'_, RootDatabase>,
         ) -> Option<(FileRange, SyntaxContextId)>
         where
-            D: HasSource,
+            D: hir::HasSource,
             D::Ast: ast::HasName,
         {
-            let src = def.source(sema.db)?;
+            let src = sema.source(def)?;
             let name = src.value.name()?;
             src.with_value(name.syntax()).original_file_range_opt(sema.db)
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 8f633065f3c..b62f34f4157 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -266,7 +266,7 @@ impl IntoIterator for SearchScope {
 
 impl Definition {
     fn search_scope(&self, db: &RootDatabase) -> SearchScope {
-        let _p = tracing::span!(tracing::Level::INFO, "search_scope").entered();
+        let _p = tracing::info_span!("search_scope").entered();
 
         if let Definition::BuiltinType(_) = self {
             return SearchScope::crate_graph(db);
@@ -434,7 +434,7 @@ impl<'a> FindUsages<'a> {
     }
 
     pub fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
-        let _p = tracing::span!(tracing::Level::INFO, "FindUsages:search").entered();
+        let _p = tracing::info_span!("FindUsages:search").entered();
         let sema = self.sema;
 
         let search_scope = {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index f59d8d08c89..7ef7b7ae1d0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -338,6 +338,12 @@ impl SourceChangeBuilder {
         self.add_snippet(PlaceSnippet::Over(node.syntax().clone().into()))
     }
 
+    /// Adds a snippet to move the cursor selected over `token`
+    pub fn add_placeholder_snippet_token(&mut self, _cap: SnippetCap, token: SyntaxToken) {
+        assert!(token.parent().is_some());
+        self.add_snippet(PlaceSnippet::Over(token.into()))
+    }
+
     /// Adds a snippet to move the cursor selected over `nodes`
     ///
     /// This allows for renaming newly generated items without having to go
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index 12085f9ebd2..c70aed4c43b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -124,7 +124,7 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatab
 }
 
 fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Arc<SymbolIndex> {
-    let _p = tracing::span!(tracing::Level::INFO, "library_symbols").entered();
+    let _p = tracing::info_span!("library_symbols").entered();
 
     let mut symbol_collector = SymbolCollector::new(db.upcast());
 
@@ -142,14 +142,14 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
 }
 
 fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
-    let _p = tracing::span!(tracing::Level::INFO, "module_symbols").entered();
+    let _p = tracing::info_span!("module_symbols").entered();
 
     let symbols = SymbolCollector::collect_module(db.upcast(), module);
     Arc::new(SymbolIndex::new(symbols))
 }
 
 pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
-    let _p = tracing::span!(tracing::Level::INFO, "crate_symbols").entered();
+    let _p = tracing::info_span!("crate_symbols").entered();
     krate.modules(db.upcast()).into_iter().map(|module| db.module_symbols(module)).collect()
 }
 
@@ -192,7 +192,8 @@ impl<DB> std::ops::Deref for Snap<DB> {
 // Note that filtering does not currently work in VSCode due to the editor never
 // sending the special symbols to the language server. Instead, you can configure
 // the filtering via the `rust-analyzer.workspace.symbol.search.scope` and
-// `rust-analyzer.workspace.symbol.search.kind` settings.
+// `rust-analyzer.workspace.symbol.search.kind` settings. Symbols prefixed
+// with `__` are hidden from the search results unless configured otherwise.
 //
 // |===
 // | Editor  | Shortcut
@@ -200,7 +201,7 @@ impl<DB> std::ops::Deref for Snap<DB> {
 // | VS Code | kbd:[Ctrl+T]
 // |===
 pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
-    let _p = tracing::span!(tracing::Level::INFO, "world_symbols", query = ?query.query).entered();
+    let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
 
     let indices: Vec<_> = if query.libs {
         db.library_roots()
@@ -320,7 +321,7 @@ impl Query {
         indices: &'sym [Arc<SymbolIndex>],
         cb: impl FnMut(&'sym FileSymbol),
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "symbol_index::Query::search").entered();
+        let _p = tracing::info_span!("symbol_index::Query::search").entered();
         let mut op = fst::map::OpBuilder::new();
         match self.mode {
             SearchMode::Exact => {
@@ -356,6 +357,7 @@ impl Query {
         mut stream: fst::map::Union<'_>,
         mut cb: impl FnMut(&'sym FileSymbol),
     ) {
+        let ignore_underscore_prefixed = !self.query.starts_with("__");
         while let Some((_, indexed_values)) = stream.next() {
             for &IndexedValue { index, value } in indexed_values {
                 let symbol_index = &indices[index];
@@ -374,6 +376,10 @@ impl Query {
                     if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) {
                         continue;
                     }
+                    // Hide symbols that start with `__` unless the query starts with `__`
+                    if ignore_underscore_prefixed && symbol.name.starts_with("__") {
+                        continue;
+                    }
                     if self.mode.check(&self.query, self.case_sensitive, &symbol.name) {
                         cb(symbol);
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 132b93df10a..2b8779044fb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -37,7 +37,7 @@ impl State {
             self.names.insert(name.clone(), 1);
             1
         };
-        make::name(&format!("{}{}", name, count))
+        make::name(&format!("{name}{count}"))
     }
 
     fn serde_derive(&self) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 6a957ac1c97..f8780fc0da7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -11,7 +11,6 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
         d.message.clone(),
         display_range,
     )
-    .experimental()
 }
 
 // Diagnostic: macro-error
@@ -26,7 +25,6 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr
         d.message.clone(),
         display_range,
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 1b29e0a3746..30dd26a118d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -183,6 +183,20 @@ fn main() {
     }
 
     #[test]
+    fn no_missing_unsafe_diagnostic_with_deprecated_safe_2024() {
+        check_diagnostics(
+            r#"
+#[rustc_deprecated_safe_2024]
+fn set_var() {}
+
+fn main() {
+    set_var();
+}
+"#,
+        );
+    }
+
+    #[test]
     fn add_unsafe_block_when_dereferencing_a_raw_pointer() {
         check_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 00710ef5076..be1e6ed5722 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -27,7 +27,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
         hir::AssocItem::Function(id) => {
             let function = id;
             (
-                format!("`fn {}`", redundant_assoc_item_name),
+                format!("`fn {redundant_assoc_item_name}`"),
                 function
                     .source(db)
                     .map(|it| it.syntax().value.text_range())
@@ -38,7 +38,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
         hir::AssocItem::Const(id) => {
             let constant = id;
             (
-                format!("`const {}`", redundant_assoc_item_name),
+                format!("`const {redundant_assoc_item_name}`"),
                 constant
                     .source(db)
                     .map(|it| it.syntax().value.text_range())
@@ -49,7 +49,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
         hir::AssocItem::TypeAlias(id) => {
             let type_alias = id;
             (
-                format!("`type {}`", redundant_assoc_item_name),
+                format!("`type {redundant_assoc_item_name}`"),
                 type_alias
                     .source(db)
                     .map(|it| it.syntax().value.text_range())
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index b9327f85567..cbf50d13f58 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -26,8 +26,6 @@ pub(crate) fn unlinked_file(
     acc: &mut Vec<Diagnostic>,
     file_id: FileId,
 ) {
-    // Limit diagnostic to the first few characters in the file. This matches how VS Code
-    // renders it with the full span, but on other editors, and is less invasive.
     let fixes = fixes(ctx, file_id);
     // FIXME: This is a hack for the vscode extension to notice whether there is an autofix or not before having to resolve diagnostics.
     // This is to prevent project linking popups from appearing when there is an autofix. https://github.com/rust-lang/rust-analyzer/issues/14523
@@ -37,14 +35,27 @@ pub(crate) fn unlinked_file(
         "file not included in module tree"
     };
 
-    let range = ctx.sema.db.parse(file_id).syntax_node().text_range();
-    let range = FileLoader::file_text(ctx.sema.db, file_id)
-        .char_indices()
-        .take(3)
-        .last()
-        .map(|(i, _)| i)
-        .map(|i| TextRange::up_to(i.try_into().unwrap()))
-        .unwrap_or(range);
+    let mut range = ctx.sema.db.parse(file_id).syntax_node().text_range();
+    let mut unused = true;
+
+    if fixes.is_none() {
+        // If we don't have a fix, the unlinked-file diagnostic is not
+        // actionable. This generally means that rust-analyzer hasn't
+        // finished startup, or we couldn't find the Cargo.toml.
+        //
+        // Only show this diagnostic on the first three characters of
+        // the file, to avoid overwhelming the user during startup.
+        range = FileLoader::file_text(ctx.sema.db, file_id)
+            .char_indices()
+            .take(3)
+            .last()
+            .map(|(i, _)| i)
+            .map(|i| TextRange::up_to(i.try_into().unwrap()))
+            .unwrap_or(range);
+        // Prefer a diagnostic underline over graying out the text,
+        // since we're only highlighting a small region.
+        unused = false;
+    }
 
     acc.push(
         Diagnostic::new(
@@ -52,6 +63,7 @@ pub(crate) fn unlinked_file(
             message,
             FileRange { file_id, range },
         )
+        .with_unused(unused)
         .with_fixes(fixes),
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 0614fdc5514..42211cdbe5d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -161,12 +161,11 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         // we could omit generic parameters cause compiler can deduce it automatically
         if !need_to_take_receiver_as_first_arg && !generic_parameters.is_empty() {
             let generic_parameters = generic_parameters.join(", ");
-            receiver_type_adt_name =
-                format!("{}::<{}>", receiver_type_adt_name, generic_parameters);
+            receiver_type_adt_name = format!("{receiver_type_adt_name}::<{generic_parameters}>");
         }
 
         let method_name = call.name_ref()?;
-        let assoc_func_call = format!("{}::{}()", receiver_type_adt_name, method_name);
+        let assoc_func_call = format!("{receiver_type_adt_name}::{method_name}()");
 
         let assoc_func_call = make::expr_path(make::path_from_text(&assoc_func_call));
 
@@ -184,8 +183,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         Some(Assist {
             id: AssistId("method_call_to_assoc_func_call_fix", AssistKind::QuickFix),
             label: Label::new(format!(
-                "Use associated func call instead: `{}`",
-                assoc_func_call_expr_string
+                "Use associated func call instead: `{assoc_func_call_expr_string}`"
             )),
             group: None,
             target: range,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 15543a5d655..a419f04bfae 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -86,7 +86,7 @@ use ide_db::{
     label::Label,
     source_change::SourceChange,
     syntax_helpers::node_ext::parse_tt_as_comma_sep_paths,
-    FxHashMap, FxHashSet, RootDatabase,
+    FxHashMap, FxHashSet, RootDatabase, SnippetCap,
 };
 use once_cell::sync::Lazy;
 use stdx::never;
@@ -229,6 +229,7 @@ pub struct DiagnosticsConfig {
     pub expr_fill_default: ExprFillDefaultMode,
     pub style_lints: bool,
     // FIXME: We may want to include a whole `AssistConfig` here
+    pub snippet_cap: Option<SnippetCap>,
     pub insert_use: InsertUseConfig,
     pub prefer_no_std: bool,
     pub prefer_prelude: bool,
@@ -248,6 +249,7 @@ impl DiagnosticsConfig {
             disabled: Default::default(),
             expr_fill_default: Default::default(),
             style_lints: true,
+            snippet_cap: SnippetCap::new(true),
             insert_use: InsertUseConfig {
                 granularity: ImportGranularity::Preserve,
                 enforce_granularity: false,
@@ -297,7 +299,7 @@ pub fn diagnostics(
     resolve: &AssistResolveStrategy,
     file_id: FileId,
 ) -> Vec<Diagnostic> {
-    let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered();
+    let _p = tracing::info_span!("diagnostics").entered();
     let sema = Semantics::new(db);
     let mut res = Vec::new();
 
@@ -482,7 +484,7 @@ fn handle_lint_attributes(
     clippy_stack: &mut FxHashMap<String, Vec<Severity>>,
     diagnostics_of_range: &mut FxHashMap<InFile<SyntaxNode>, &mut Diagnostic>,
 ) {
-    let _g = tracing::span!(tracing::Level::INFO, "handle_lint_attributes").entered();
+    let _g = tracing::info_span!("handle_lint_attributes").entered();
     let file_id = sema.hir_file_for(root);
     let preorder = root.preorder();
     for ev in preorder {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index cf7e7e08bc5..b29053c0c2d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -575,7 +575,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                             .resolve_method_call_as_callable(code)
                             .and_then(|callable| {
                                 let (self_param, _) = callable.receiver_param(self.sema.db)?;
-                                Some(self_param.source(self.sema.db)?.value.kind())
+                                Some(self.sema.source(self_param)?.value.kind())
                             })
                             .unwrap_or(ast::SelfParamKind::Owned);
                     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index 654a1cd3164..f7e5b40dde1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -19,13 +19,6 @@ pub struct CallItem {
     pub ranges: Vec<TextRange>,
 }
 
-impl CallItem {
-    #[cfg(test)]
-    pub(crate) fn debug_render(&self) -> String {
-        format!("{} : {:?}", self.target.debug_render(), self.ranges)
-    }
-}
-
 pub(crate) fn call_hierarchy(
     db: &RootDatabase,
     position: FilePosition,
@@ -159,6 +152,10 @@ mod tests {
         expected_incoming: Expect,
         expected_outgoing: Expect,
     ) {
+        fn debug_render(item: crate::CallItem) -> String {
+            format!("{} : {:?}", item.target.debug_render(), item.ranges)
+        }
+
         let (analysis, pos) = fixture::position(ra_fixture);
 
         let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
@@ -169,12 +166,10 @@ mod tests {
         let item_pos =
             FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
         let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
-        expected_incoming
-            .assert_eq(&incoming_calls.into_iter().map(|call| call.debug_render()).join("\n"));
+        expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
 
         let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
-        expected_outgoing
-            .assert_eq(&outgoing_calls.into_iter().map(|call| call.debug_render()).join("\n"));
+        expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 1ead045788f..4b54c057bf3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -111,9 +111,10 @@ fn expand_macro_recur(
     macro_call: &ast::Item,
 ) -> Option<SyntaxNode> {
     let expanded = match macro_call {
-        item @ ast::Item::MacroCall(macro_call) => {
-            sema.expand_attr_macro(item).or_else(|| sema.expand(macro_call))?.clone_for_update()
-        }
+        item @ ast::Item::MacroCall(macro_call) => sema
+            .expand_attr_macro(item)
+            .or_else(|| sema.expand_allowed_builtins(macro_call))?
+            .clone_for_update(),
         item => sema.expand_attr_macro(item)?.clone_for_update(),
     };
     expand(sema, expanded)
@@ -229,6 +230,29 @@ mod tests {
     }
 
     #[test]
+    fn expand_allowed_builtin_macro() {
+        check(
+            r#"
+//- minicore: concat
+$0concat!("test", 10, 'b', true);"#,
+            expect![[r#"
+                concat!
+                "test10btrue""#]],
+        );
+    }
+
+    #[test]
+    fn do_not_expand_disallowed_macro() {
+        let (analysis, pos) = fixture::position(
+            r#"
+//- minicore: asm
+$0asm!("0x300, x0");"#,
+        );
+        let expansion = analysis.expand_macro(pos).unwrap();
+        assert!(expansion.is_none());
+    }
+
+    #[test]
     fn macro_expand_as_keyword() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
index b706e959d34..e8d6dc97341 100644
--- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
@@ -210,7 +210,13 @@ fn extend_single_word_in_comment_or_string(
     let start_idx = before.rfind(non_word_char)? as u32;
     let end_idx = after.find(non_word_char).unwrap_or(after.len()) as u32;
 
-    let from: TextSize = (start_idx + 1).into();
+    // FIXME: use `ceil_char_boundary` from `std::str` when it gets stable
+    // https://github.com/rust-lang/rust/issues/93743
+    fn ceil_char_boundary(text: &str, index: u32) -> u32 {
+        (index..).find(|&index| text.is_char_boundary(index as usize)).unwrap_or(text.len() as u32)
+    }
+
+    let from: TextSize = ceil_char_boundary(text, start_idx + 1).into();
     let to: TextSize = (cursor_position + end_idx).into();
 
     let range = TextRange::new(from, to);
@@ -662,4 +668,18 @@ fn main() { let (
             ],
         );
     }
+
+    #[test]
+    fn extend_selection_inside_str_with_wide_char() {
+        // should not panic
+        do_check(
+            r#"fn main() { let x = "═$0═══════"; }"#,
+            &[
+                r#""════════""#,
+                r#"let x = "════════";"#,
+                r#"{ let x = "════════"; }"#,
+                r#"fn main() { let x = "════════"; }"#,
+            ],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 76b80fcefa4..f57cb1cb730 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -2289,4 +2289,28 @@ macro_rules! baz {
             "#,
         );
     }
+
+    #[test]
+    fn goto_shadowed_preludes_in_block_module() {
+        check(
+            r#"
+//- /main.rs crate:main edition:2021 deps:core
+pub struct S;
+         //^
+
+fn main() {
+    fn f() -> S$0 {
+        fn inner() {} // forces a block def map
+        return S;
+    }
+}
+//- /core.rs crate:core
+pub mod prelude {
+    pub mod rust_2021 {
+        pub enum S;
+    }
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 6f32ce76b22..a5689403ee1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -55,7 +55,7 @@ pub(crate) fn highlight_related(
     config: HighlightRelatedConfig,
     pos @ FilePosition { offset, file_id }: FilePosition,
 ) -> Option<Vec<HighlightedRange>> {
-    let _p = tracing::span!(tracing::Level::INFO, "highlight_related").entered();
+    let _p = tracing::info_span!("highlight_related").entered();
     let syntax = sema.parse(file_id).syntax().clone();
 
     let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index bdb56081c33..2006baa30a8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -375,8 +375,8 @@ pub(crate) fn hover_for_definition(
     HoverResult {
         markup: render::process_markup(sema.db, def, &markup, config),
         actions: [
-            show_implementations_action(sema.db, def),
             show_fn_references_action(sema.db, def),
+            show_implementations_action(sema.db, def),
             runnable_action(sema, def, file_id),
             goto_type_action_for_def(sema.db, def, &notable_traits),
         ]
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 3bc17f95e70..99568c9922b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -430,6 +430,7 @@ pub(super) fn definition(
             }
             label
         }
+        Definition::Function(fn_) => fn_.display_with_container_bounds(db, true).to_string(),
         _ => def.label(db),
     };
     let docs = def.docs(db, famous_defs);
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index dda5a005a72..3f10bed5110 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -455,6 +455,23 @@ fn ty_to_text_edit(
 // * elided lifetimes
 // * compiler inserted reborrows
 //
+// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
+// any of the
+// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria]
+// are met:
+//
+// * the parameter name is a suffix of the function's name
+// * the argument is a qualified constructing or call expression where the qualifier is an ADT
+// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
+//   of argument with _ splitting it off
+// * the parameter name starts with `ra_fixture`
+// * the parameter name is a
+// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name]
+// in a unary function
+// * the parameter name is a
+// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character]
+// in a unary function
+//
 // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
@@ -462,7 +479,7 @@ pub(crate) fn inlay_hints(
     range_limit: Option<TextRange>,
     config: &InlayHintsConfig,
 ) -> Vec<InlayHint> {
-    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
+    let _p = tracing::info_span!("inlay_hints").entered();
     let sema = Semantics::new(db);
     let file = sema.parse(file_id);
     let file = file.syntax();
@@ -496,7 +513,7 @@ pub(crate) fn inlay_hints_resolve(
     config: &InlayHintsConfig,
     hasher: impl Fn(&InlayHint) -> u64,
 ) -> Option<InlayHint> {
-    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints_resolve").entered();
+    let _p = tracing::info_span!("inlay_hints_resolve").entered();
     let sema = Semantics::new(db);
     let file = sema.parse(file_id);
     let file = file.syntax();
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 20128a286f2..7932d8efbcf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -709,4 +709,25 @@ fn main() {
             "#,
         )
     }
+
+    // regression test for a stackoverflow in hir display code
+    #[test]
+    fn adjustment_hints_method_call_on_impl_trait_self() {
+        check_with_config(
+            InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
+            r#"
+//- minicore: slice, coerce_unsized
+trait T<RHS = Self> {}
+
+fn hello(it: &&[impl T]) {
+    it.len();
+  //^^(
+  //^^&
+  //^^*
+  //^^*
+  //^^)
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index fb50c49a3ae..9819d0e3fbb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -30,7 +30,7 @@ pub(super) fn hints(
         .filter_map(|(p, arg)| {
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
-            let source = p.source(sema.db)?;
+            let source = sema.source(p)?;
             let (param_name, name_syntax) = match source.value.as_ref() {
                 Either::Left(pat) => (pat.name()?, pat.name()),
                 Either::Right(param) => match param.pat()? {
@@ -38,8 +38,6 @@ pub(super) fn hints(
                     _ => return None,
                 },
             };
-            // make sure the file is cached so we can map out of macros
-            sema.parse_or_expand(source.file_id);
             Some((name_syntax, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
index df444a3f4d0..7bd2da9f88a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
@@ -43,7 +43,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<Strin
         let path = path.as_deref().unwrap_or("<unknown file>");
         match db.line_index(file_id).try_line_col(text_range.start()) {
             Some(line_col) => format!("file://{path}#{}:{}", line_col.line + 1, line_col.col),
-            None => format!("file://{path} range {:?}", text_range),
+            None => format!("file://{path} range {text_range:?}"),
         }
     };
     Some(def.eval(db, span_formatter))
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 431aa30e56f..a2ac62341df 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -273,11 +273,18 @@ impl Analysis {
         self.with_db(|db| status::status(db, file_id))
     }
 
-    pub fn source_root(&self, file_id: FileId) -> Cancellable<SourceRootId> {
+    pub fn source_root_id(&self, file_id: FileId) -> Cancellable<SourceRootId> {
         self.with_db(|db| db.file_source_root(file_id))
     }
 
-    pub fn parallel_prime_caches<F>(&self, num_worker_threads: u8, cb: F) -> Cancellable<()>
+    pub fn is_local_source_root(&self, source_root_id: SourceRootId) -> Cancellable<bool> {
+        self.with_db(|db| {
+            let sr = db.source_root(source_root_id);
+            !sr.is_library
+        })
+    }
+
+    pub fn parallel_prime_caches<F>(&self, num_worker_threads: usize, cb: F) -> Cancellable<()>
     where
         F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
     {
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index fc836d55409..bfd62e76243 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -220,7 +220,7 @@ impl TryToNav for Definition {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         match self {
             Definition::Local(it) => Some(it.to_nav(db)),
-            Definition::Label(it) => Some(it.to_nav(db)),
+            Definition::Label(it) => it.try_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),
@@ -562,12 +562,12 @@ impl ToNav for hir::Local {
     }
 }
 
-impl ToNav for hir::Label {
-    fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db);
+impl TryToNav for hir::Label {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
+        let InFile { file_id, value } = self.source(db)?;
         let name = self.name(db).to_smol_str();
 
-        orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
+        Some(orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
             |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
                 file_id,
                 name: name.clone(),
@@ -579,7 +579,7 @@ impl ToNav for hir::Label {
                 description: None,
                 docs: None,
             },
-        )
+        ))
     }
 }
 
@@ -926,4 +926,26 @@ struct Foo;
         let navs = analysis.symbol_search(Query::new("foo".to_owned()), !0).unwrap();
         assert_eq!(navs.len(), 2)
     }
+
+    #[test]
+    fn test_ensure_hidden_symbols_are_not_returned() {
+        let (analysis, _) = fixture::file(
+            r#"
+fn foo() {}
+struct Foo;
+static __FOO_CALLSITE: () = ();
+"#,
+        );
+
+        // It doesn't show the hidden symbol
+        let navs = analysis.symbol_search(Query::new("foo".to_owned()), !0).unwrap();
+        assert_eq!(navs.len(), 2);
+        let navs = analysis.symbol_search(Query::new("_foo".to_owned()), !0).unwrap();
+        assert_eq!(navs.len(), 0);
+
+        // Unless we explicitly search for a `__` prefix
+        let query = Query::new("__foo".to_owned());
+        let navs = analysis.symbol_search(query, !0).unwrap();
+        assert_eq!(navs.len(), 1);
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 01af864cdf5..6f9e1b3740c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -55,7 +55,7 @@ pub(crate) fn find_all_refs(
     position: FilePosition,
     search_scope: Option<SearchScope>,
 ) -> Option<Vec<ReferenceSearchResult>> {
-    let _p = tracing::span!(tracing::Level::INFO, "find_all_refs").entered();
+    let _p = tracing::info_span!("find_all_refs").entered();
     let syntax = sema.parse(position.file_id).syntax().clone();
     let make_searcher = |literal_search: bool| {
         move |def: Definition| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 8c2ae327c7f..3d08e2f3718 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -119,9 +119,9 @@ pub(crate) fn rename(
                 };
 
                 let mut source_change = SourceChange::default();
-                source_change.extend(usages.iter().map(|(&file_id, refs)| {
-                    (file_id, source_edit_from_references(refs, def, new_name))
-                }));
+                source_change.extend(usages.references.get_mut(&position.file_id).iter().map(
+                    |refs| (position.file_id, source_edit_from_references(refs, def, new_name)),
+                ));
 
                 Ok(source_change)
             })
@@ -361,8 +361,9 @@ fn rename_to_self(
         bail!("Parameter type differs from impl block type");
     }
 
-    let InFile { file_id, value: param_source } =
-        first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?;
+    let InFile { file_id, value: param_source } = sema
+        .source(first_param.clone())
+        .ok_or_else(|| format_err!("No source for parameter found"))?;
 
     let def = Definition::Local(local);
     let usages = def.usages(sema).all();
@@ -392,7 +393,7 @@ fn rename_self_to_param(
     let identifier_kind = IdentifierKind::classify(new_name)?;
 
     let InFile { file_id, value: self_param } =
-        self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?;
+        sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
 
     let def = Definition::Local(local);
     let usages = def.usages(sema).all();
@@ -444,12 +445,8 @@ mod tests {
 
     use super::{RangeInfo, RenameError};
 
-    fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-        check_with_rename_config(new_name, ra_fixture_before, ra_fixture_after);
-    }
-
     #[track_caller]
-    fn check_with_rename_config(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
         let ra_fixture_after = &trim_indent(ra_fixture_after);
         let (analysis, position) = fixture::position(ra_fixture_before);
         if !ra_fixture_after.starts_with("error: ") {
@@ -466,7 +463,7 @@ mod tests {
                 let (&file_id, edit) = match source_change.source_file_edits.len() {
                     0 => return,
                     1 => source_change.source_file_edits.iter().next().unwrap(),
-                    _ => (&position.file_id, &source_change.source_file_edits[&position.file_id]),
+                    _ => panic!(),
                 };
                 for indel in edit.0.iter() {
                     text_edit_builder.replace(indel.delete, indel.insert.clone());
@@ -2689,7 +2686,7 @@ use qux as frob;
 
     #[test]
     fn disallow_renaming_for_non_local_definition() {
-        check_with_rename_config(
+        check(
             "Baz",
             r#"
 //- /lib.rs crate:lib new_source_root:library
@@ -2704,7 +2701,7 @@ fn main() { let _: S$0; }
 
     #[test]
     fn disallow_renaming_for_builtin_macros() {
-        check_with_rename_config(
+        check(
             "Baz",
             r#"
 //- minicore: derive, hash
@@ -2762,14 +2759,19 @@ fn test() {
         check(
             "Baz",
             r#"
+//- /main.rs crate:main
+mod module;
 mod foo { pub struct Foo; }
 mod bar { use super::Foo; }
 
 use foo::Foo$0;
 
 fn main() { let _: Foo; }
+//- /module.rs
+use crate::foo::Foo;
 "#,
             r#"
+mod module;
 mod foo { pub struct Foo; }
 mod bar { use super::Baz; }
 
@@ -2779,4 +2781,22 @@ fn main() { let _: Baz; }
 "#,
         )
     }
+
+    #[test]
+    fn rename_path_inside_use_tree_foreign() {
+        check(
+            "Baz",
+            r#"
+//- /lib.rs crate:lib new_source_root:library
+pub struct S;
+//- /main.rs crate:main deps:lib new_source_root:local
+use lib::S$0;
+fn main() { let _: S; }
+"#,
+            r#"
+use lib::S as Baz;
+fn main() { let _: Baz; }
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 378a38892c7..89c725a6c47 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -226,7 +226,7 @@ fn signature_help_for_call(
         let mut buf = String::new();
         for (idx, p) in callable.params().into_iter().enumerate() {
             buf.clear();
-            if let Some(param) = p.source(sema.db) {
+            if let Some(param) = sema.source(p.clone()) {
                 match param.value {
                     Either::Right(param) => match param.pat() {
                         Some(pat) => format_to!(buf, "{}: ", pat),
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 6aaf8f8e779..fd8e6f40465 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -186,7 +186,7 @@ pub(crate) fn highlight(
     file_id: FileId,
     range_to_highlight: Option<TextRange>,
 ) -> Vec<HlRange> {
-    let _p = tracing::span!(tracing::Level::INFO, "highlight").entered();
+    let _p = tracing::info_span!("highlight").entered();
     let sema = Semantics::new(db);
 
     // Determine the root based on the given range.
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
index 2f387968c96..552ce9cd8c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
@@ -28,7 +28,7 @@ pub(super) fn highlight_escape_string<T: IsString>(
 pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
     if char.value().is_err() {
         // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
-        // state and this token contains junks, since `'` is not a reliable delimiter (consider
+        // state and this token contains junk, since `'` is not a reliable delimiter (consider
         // lifetimes). Nonetheless, parser errors should already be emitted.
         return;
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 3b784ebec3b..c73b6acb0d0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -584,6 +584,9 @@ fn highlight_method_call(
     if func.is_async(sema.db) {
         h |= HlMod::Async;
     }
+    if func.is_const(sema.db) {
+        h |= HlMod::Const;
+    }
     if func
         .as_assoc_item(sema.db)
         .and_then(|it| it.container_or_implemented_trait(sema.db))
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index eed3968a906..70f2d7203e9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -48,16 +48,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">foo</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>foo<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="keyword">mod</span> y <span class="brace">{</span>
-            <span class="keyword">struct</span> <span class="punctuation">$</span>foo<span class="semicolon">;</span>
+            <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="punctuation">$</span>foo<span class="semicolon">;</span>
         <span class="brace">}</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span>
-        <span class="comment">// FIXME: IDE layer has this unresolved</span>
-        <span class="unresolved_reference">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-        <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+        <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+        <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span>
             <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
                 <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
             <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
index cd6ffc2c3ae..a14f2cc88cd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -66,10 +66,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
         <span class="keyword macro">const</span>
     <span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="operator">.</span><span class="method const consuming trait">assoc_const_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 <span class="keyword">trait</span> <span class="trait declaration">ConstTrait</span> <span class="brace">{</span>
     <span class="keyword const">const</span> <span class="constant associated const declaration static trait">ASSOC_CONST</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration static trait">assoc_const_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+    <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="method associated const consuming declaration trait">assoc_const_method</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 <span class="keyword">impl</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword const">const</span> <span class="constant associated const declaration static trait">ASSOC_CONST</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 893e3c06751..dfad3a6605c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -49,5 +49,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="enum_variant default_library library">Some</span><span class="parenthesis">(</span><span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method const default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 413edb6d65f..9be7c92fc79 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -218,7 +218,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="bool_literal">true</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
-<span class="keyword const">const</span> <span class="constant const declaration">USAGE_OF_BOOL</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="enum public">Bool</span><span class="operator">::</span><span class="enum_variant public">True</span><span class="operator">.</span><span class="method consuming public">to_primitive</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword const">const</span> <span class="constant const declaration">USAGE_OF_BOOL</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="enum public">Bool</span><span class="operator">::</span><span class="enum_variant public">True</span><span class="operator">.</span><span class="method const consuming public">to_primitive</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
 <span class="keyword">trait</span> <span class="trait declaration">Baz</span> <span class="brace">{</span>
     <span class="keyword">type</span> <span class="type_alias associated declaration static trait">Qux</span><span class="semicolon">;</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 22706dea1fa..cb47fc68bc1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -165,7 +165,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
-    <span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
+    <span class="macro default_library library">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
         <span class="string_literal macro">"mov </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>
         <span class="string_literal macro">"add </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, 5"</span><span class="comma macro">,</span>
         <span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 901e41d27cd..08acfca2cb6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -657,10 +657,12 @@ const fn const_fn<const CONST_PARAM: ()>(const {}: const fn()) where (): const C
         &raw const ();
         const
     );
+    ().assoc_const_method();
 }
 trait ConstTrait {
     const ASSOC_CONST: () = ();
     const fn assoc_const_fn() {}
+    const fn assoc_const_method(self) {}
 }
 impl const ConstTrait for () {
     const ASSOC_CONST: () = ();
@@ -1070,16 +1072,15 @@ fn test_block_mod_items() {
 macro_rules! foo {
     ($foo:ident) => {
         mod y {
-            struct $foo;
+            pub struct $foo;
         }
     };
 }
 fn main() {
     foo!(Foo);
     mod module {
-        // FIXME: IDE layer has this unresolved
         foo!(Bar);
-        fn func() {
+        fn func(_: y::Bar) {
             mod inner {
                 struct Innerest<const C: usize> { field: [(); {C}] }
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index a229bc87c89..826447d058d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -40,7 +40,7 @@ impl fmt::Display for RecursiveMemoryLayout {
                 "{}: {} (size: {}, align: {}, field offset: {})\n",
                 node.item_name, node.typename, node.size, node.alignment, node.offset
             );
-            write!(fmt, "{}", out)?;
+            write!(fmt, "{out}")?;
             if node.children_start != -1 {
                 for j in nodes[idx].children_start
                     ..(nodes[idx].children_start + nodes[idx].children_len as i64)
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 76940ab57ab..de68b867145 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -15,9 +15,9 @@ use ide_db::{
 };
 use itertools::Itertools;
 use proc_macro_api::{MacroDylib, ProcMacroServer};
-use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
+use project_model::{CargoConfig, ManifestPath, PackageRoot, ProjectManifest, ProjectWorkspace};
 use span::Span;
-use tracing::{instrument, Level};
+use tracing::instrument;
 use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
 
 pub struct LoadCargoConfig {
@@ -238,6 +238,19 @@ impl ProjectFolders {
             fsc.add_file_set(file_set_roots)
         }
 
+        // register the workspace manifest as well, note that this currently causes duplicates for
+        // non-virtual cargo workspaces! We ought to fix that
+        for manifest in workspaces.iter().filter_map(|ws| ws.manifest().map(ManifestPath::as_ref)) {
+            let file_set_roots: Vec<VfsPath> = vec![VfsPath::from(manifest.to_owned())];
+
+            let entry = vfs::loader::Entry::Files(vec![manifest.to_owned()]);
+
+            res.watch.push(res.load.len());
+            res.load.push(entry);
+            local_filesets.push(fsc.len() as u64);
+            fsc.add_file_set(file_set_roots)
+        }
+
         let fsc = fsc.build();
         res.source_root_config = SourceRootConfig { fsc, local_filesets };
 
@@ -272,24 +285,53 @@ impl SourceRootConfig {
     /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot`.
     pub fn source_root_parent_map(&self) -> FxHashMap<SourceRootId, SourceRootId> {
         let roots = self.fsc.roots();
-        let mut map = FxHashMap::<SourceRootId, SourceRootId>::default();
-        roots
-            .iter()
-            .enumerate()
-            .filter(|(_, (_, id))| self.local_filesets.contains(id))
-            .filter_map(|(idx, (root, root_id))| {
-                // We are interested in parents if they are also local source roots.
-                // So instead of a non-local parent we may take a local ancestor as a parent to a node.
-                roots.iter().take(idx).find_map(|(root2, root2_id)| {
-                    if self.local_filesets.contains(root2_id) && root.starts_with(root2) {
-                        return Some((root_id, root2_id));
+
+        let mut map = FxHashMap::default();
+
+        // See https://github.com/rust-lang/rust-analyzer/issues/17409
+        //
+        // We can view the connections between roots as a graph. The problem is
+        // that this graph may contain cycles, so when adding edges, it is necessary
+        // to check whether it will lead to a cycle.
+        //
+        // Since we ensure that each node has at most one outgoing edge (because
+        // each SourceRoot can have only one parent), we can use a disjoint-set to
+        // maintain the connectivity between nodes. If an edge’s two nodes belong
+        // to the same set, they are already connected.
+        let mut dsu = FxHashMap::default();
+        fn find_parent(dsu: &mut FxHashMap<u64, u64>, id: u64) -> u64 {
+            if let Some(&parent) = dsu.get(&id) {
+                let parent = find_parent(dsu, parent);
+                dsu.insert(id, parent);
+                parent
+            } else {
+                id
+            }
+        }
+
+        for (idx, (root, root_id)) in roots.iter().enumerate() {
+            if !self.local_filesets.contains(root_id)
+                || map.contains_key(&SourceRootId(*root_id as u32))
+            {
+                continue;
+            }
+
+            for (root2, root2_id) in roots[..idx].iter().rev() {
+                if self.local_filesets.contains(root2_id)
+                    && root_id != root2_id
+                    && root.starts_with(root2)
+                {
+                    // check if the edge will create a cycle
+                    if find_parent(&mut dsu, *root_id) != find_parent(&mut dsu, *root2_id) {
+                        map.insert(SourceRootId(*root_id as u32), SourceRootId(*root2_id as u32));
+                        dsu.insert(*root_id, *root2_id);
                     }
-                    None
-                })
-            })
-            .for_each(|(child, parent)| {
-                map.insert(SourceRootId(*child as u32), SourceRootId(*parent as u32));
-            });
+
+                    break;
+                }
+            }
+        }
+
         map
     }
 }
@@ -352,8 +394,8 @@ fn load_crate_graph(
                 }
             }
             vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
-                let _p = tracing::span!(Level::INFO, "load_cargo::load_crate_craph/LoadedChanged")
-                    .entered();
+                let _p =
+                    tracing::info_span!("load_cargo::load_crate_craph/LoadedChanged").entered();
                 for (path, contents) in files {
                     vfs.set_file_contents(path.into(), contents);
                 }
@@ -560,4 +602,36 @@ mod tests {
 
         assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),])
     }
+
+    #[test]
+    fn parents_with_identical_root_id() {
+        let mut builder = FileSetConfigBuilder::default();
+        builder.add_file_set(vec![
+            VfsPath::new_virtual_path("/ROOT/def".to_owned()),
+            VfsPath::new_virtual_path("/ROOT/def/abc/def".to_owned()),
+        ]);
+        builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc/def/ghi".to_owned())]);
+        let fsc = builder.build();
+        let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
+        let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+        vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
+
+        assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0)),])
+    }
+
+    #[test]
+    fn circular_reference() {
+        let mut builder = FileSetConfigBuilder::default();
+        builder.add_file_set(vec![
+            VfsPath::new_virtual_path("/ROOT/def".to_owned()),
+            VfsPath::new_virtual_path("/ROOT/def/abc/def".to_owned()),
+        ]);
+        builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]);
+        let fsc = builder.build();
+        let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
+        let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+        vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
+
+        assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0)),])
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index f73e188c797..19ba5c7a156 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -215,7 +215,7 @@ fn invocation_fixtures(
 
                 token_trees.push(subtree.into());
             }
-            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
+            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => {}
         };
 
         // Simple linear congruential generator for deterministic result
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index 78d4bfee2a1..0cec4e70daa 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -566,7 +566,7 @@ fn match_loop_inner<'t>(
                 error_items.push(item);
             }
             OpDelimited::Op(
-                Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. },
+                Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. },
             ) => {
                 stdx::never!("metavariable expression in lhs found");
             }
@@ -832,7 +832,7 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate)
             Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
             Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
             Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {}
-            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {
+            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => {
                 stdx::never!("metavariable expression in lhs found");
             }
         }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 5e6e45f1521..0f689a2692c 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -242,7 +242,7 @@ fn expand_subtree(
                     .into(),
                 );
             }
-            Op::Length { depth } => {
+            Op::Len { depth } => {
                 let length = ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |_nest| {
                     // FIXME: to be implemented
                     0
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index 6920832dd2e..ed3200964df 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -317,6 +317,12 @@ pub struct ValueResult<T, E> {
     pub err: Option<E>,
 }
 
+impl<T: Default, E> Default for ValueResult<T, E> {
+    fn default() -> Self {
+        Self { value: Default::default(), err: Default::default() }
+    }
+}
+
 impl<T, E> ValueResult<T, E> {
     pub fn new(value: T, err: E) -> Self {
         Self { value, err: Some(err) }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
index eaf2fd8c273..bbe00f0afca 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
@@ -75,7 +75,7 @@ pub(crate) enum Op {
     Index {
         depth: usize,
     },
-    Length {
+    Len {
         depth: usize,
     },
     Count {
@@ -345,7 +345,7 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result
             Op::Ignore { name: ident.text.clone(), id: ident.span }
         }
         "index" => Op::Index { depth: parse_depth(&mut args)? },
-        "length" => Op::Length { depth: parse_depth(&mut args)? },
+        "len" => Op::Len { depth: parse_depth(&mut args)? },
         "count" => {
             if new_meta_vars {
                 args.expect_dollar()?;
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index 412e4921768..c8ff8c35e93 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -47,7 +47,7 @@ pub(crate) mod dummy_test_span_utils {
     pub const DUMMY: Span = Span {
         range: TextRange::empty(TextSize::new(0)),
         anchor: span::SpanAnchor {
-            file_id: span::FileId::BOGUS,
+            file_id: span::FileId::from_raw(0xe4e4e),
             ast_id: span::ROOT_ERASED_FILE_AST_ID,
         },
         ctx: SyntaxContextId::ROOT,
@@ -60,7 +60,7 @@ pub(crate) mod dummy_test_span_utils {
             Span {
                 range,
                 anchor: span::SpanAnchor {
-                    file_id: span::FileId::BOGUS,
+                    file_id: span::FileId::from_raw(0xe4e4e),
                     ast_id: span::ROOT_ERASED_FILE_AST_ID,
                 },
                 ctx: SyntaxContextId::ROOT,
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
index 4e5837312fe..2930190cb33 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -13,7 +13,7 @@
 //! Code in this module also contains inline tests, which start with
 //! `// test name-of-the-test` comment and look like this:
 //!
-//! ```
+//! ```text
 //! // test function_with_zero_parameters
 //! // fn foo() {}
 //! ```
@@ -418,7 +418,7 @@ fn delimited(
         }
         if !p.eat(delim) {
             if p.at_ts(first_set) {
-                p.error(format!("expected {:?}", delim));
+                p.error(format!("expected {delim:?}"));
             } else {
                 break;
             }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
index eff6b664049..882c243b0cd 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -181,7 +181,7 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
                 //       ^
                 if matches!(
                     p.current(),
-                    T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']'] | T![if]
+                    T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']'] | T![if] | EOF
                 ) {
                     // test half_open_range_pat
                     // fn f() {
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index e5fec67de70..52b24b73725 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -31,7 +31,7 @@ struct LexError {
 
 impl<'a> LexedStr<'a> {
     pub fn new(text: &'a str) -> LexedStr<'a> {
-        let _p = tracing::span!(tracing::Level::INFO, "LexedStr::new").entered();
+        let _p = tracing::info_span!("LexedStr::new").entered();
         let mut conv = Converter::new(text);
         if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
             conv.res.push(SHEBANG, conv.offset);
diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs
index c7ad025f6b0..c2f9ea47728 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs
@@ -89,7 +89,7 @@ pub enum TopEntryPoint {
 
 impl TopEntryPoint {
     pub fn parse(&self, input: &Input, edition: Edition) -> Output {
-        let _p = tracing::span!(tracing::Level::INFO, "TopEntryPoint::parse", ?self).entered();
+        let _p = tracing::info_span!("TopEntryPoint::parse", ?self).entered();
         let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
             TopEntryPoint::SourceFile => grammar::entry::top::source_file,
             TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
index cc2b63d1e66..7f49cc087ae 100644
--- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
@@ -26,7 +26,7 @@ pub enum StrStep<'a> {
 
 impl LexedStr<'_> {
     pub fn to_input(&self) -> crate::Input {
-        let _p = tracing::span!(tracing::Level::INFO, "LexedStr::to_input").entered();
+        let _p = tracing::info_span!("LexedStr::to_input").entered();
         let mut res = crate::Input::default();
         let mut was_joint = false;
         for i in 0..self.len() {
diff --git a/src/tools/rust-analyzer/crates/paths/src/lib.rs b/src/tools/rust-analyzer/crates/paths/src/lib.rs
index 2d3653401d2..33c3f83db50 100644
--- a/src/tools/rust-analyzer/crates/paths/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/paths/src/lib.rs
@@ -106,7 +106,7 @@ impl AbsPathBuf {
     /// Panics if `path` is not absolute.
     pub fn assert(path: Utf8PathBuf) -> AbsPathBuf {
         AbsPathBuf::try_from(path)
-            .unwrap_or_else(|path| panic!("expected absolute path, got {}", path))
+            .unwrap_or_else(|path| panic!("expected absolute path, got {path}"))
     }
 
     /// Wrap the given absolute path in `AbsPathBuf`
@@ -135,6 +135,24 @@ impl AbsPathBuf {
     pub fn pop(&mut self) -> bool {
         self.0.pop()
     }
+
+    /// Equivalent of [`PathBuf::push`] for `AbsPathBuf`.
+    ///
+    /// Extends `self` with `path`.
+    ///
+    /// If `path` is absolute, it replaces the current path.
+    ///
+    /// On Windows:
+    ///
+    /// * if `path` has a root but no prefix (e.g., `\windows`), it
+    ///   replaces everything except for the prefix (if any) of `self`.
+    /// * if `path` has a prefix but no root, it replaces `self`.
+    /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
+    ///   and `path` is not empty, the new path is normalized: all references
+    ///   to `.` and `..` are removed.
+    pub fn push<P: AsRef<Utf8Path>>(&mut self, suffix: P) {
+        self.0.push(suffix)
+    }
 }
 
 impl fmt::Display for AbsPathBuf {
@@ -197,7 +215,7 @@ impl AbsPath {
     ///
     /// Panics if `path` is not absolute.
     pub fn assert(path: &Utf8Path) -> &AbsPath {
-        assert!(path.is_absolute());
+        assert!(path.is_absolute(), "{path} is not absolute");
         unsafe { &*(path as *const Utf8Path as *const AbsPath) }
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 87494172907..8970bdd0121 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -129,7 +129,7 @@ impl ProcMacroServer {
     }
 
     pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
-        let _p = tracing::span!(tracing::Level::INFO, "ProcMacroServer::load_dylib").entered();
+        let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered();
         let macros =
             self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?;
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index dce086d4299..718a96dc80f 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -50,8 +50,7 @@ impl ProcMacroProcessSrv {
             Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
                 io::ErrorKind::Other,
                 format!(
-                    "proc-macro server's api version ({}) is newer than rust-analyzer's ({})",
-                    v, CURRENT_API_VERSION
+                    "proc-macro server's api version ({v}) is newer than rust-analyzer's ({CURRENT_API_VERSION})"
                 ),
             )),
             Ok(v) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
index f768de3e31d..09b81250715 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
@@ -93,6 +93,7 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'
 ///   means bytes from here(including this sequence) are compressed in
 ///   snappy compression format. Version info is inside here, so decompress
 ///   this.
+///
 /// The bytes you get after decompressing the snappy format portion has
 /// following layout:
 /// * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes(again)
@@ -102,6 +103,7 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'
 ///   for the version string's utf8 bytes
 /// * [version string bytes encoded in utf8] <- GET THIS BOI
 /// * [some more bytes that we don't really care but about still there] :-)
+///
 /// Check this issue for more about the bytes layout:
 /// <https://github.com/rust-lang/rust-analyzer/issues/6174>
 pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 181c07f46b2..35643dcc028 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -22,7 +22,7 @@ mod cargo_workspace;
 mod cfg;
 mod env;
 mod manifest_path;
-mod project_json;
+pub mod project_json;
 mod rustc_cfg;
 mod sysroot;
 pub mod target_data_layout;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index 5bee446f619..4a916e570be 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -33,7 +33,7 @@
 //!
 //! * file on disk
 //! * a field in the config (ie, you can send a JSON request with the contents
-//!   of rust-project.json to rust-analyzer, no need to write anything to disk)
+//!   of `rust-project.json` to rust-analyzer, no need to write anything to disk)
 //!
 //! Another possible thing we don't do today, but which would be totally valid,
 //! is to add an extension point to VS Code extension to register custom
@@ -55,8 +55,7 @@ use rustc_hash::FxHashMap;
 use serde::{de, Deserialize, Serialize};
 use span::Edition;
 
-use crate::cfg::CfgFlag;
-use crate::ManifestPath;
+use crate::{cfg::CfgFlag, ManifestPath, TargetKind};
 
 /// Roots and crates that compose this Rust project.
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -68,6 +67,10 @@ pub struct ProjectJson {
     project_root: AbsPathBuf,
     manifest: Option<ManifestPath>,
     crates: Vec<Crate>,
+    /// Configuration for CLI commands.
+    ///
+    /// Examples include a check build or a test run.
+    runnables: Vec<Runnable>,
 }
 
 /// A crate points to the root module of a crate and lists the dependencies of the crate. This is
@@ -88,6 +91,86 @@ pub struct Crate {
     pub(crate) exclude: Vec<AbsPathBuf>,
     pub(crate) is_proc_macro: bool,
     pub(crate) repository: Option<String>,
+    pub build: Option<Build>,
+}
+
+/// Additional, build-specific data about a crate.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Build {
+    /// The name associated with this crate.
+    ///
+    /// This is determined by the build system that produced
+    /// the `rust-project.json` in question. For instance, if buck were used,
+    /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
+    ///
+    /// Do not attempt to parse the contents of this string; it is a build system-specific
+    /// identifier similar to [`Crate::display_name`].
+    pub label: String,
+    /// Path corresponding to the build system-specific file defining the crate.
+    ///
+    /// It is roughly analogous to [`ManifestPath`], but it should *not* be used with
+    /// [`crate::ProjectManifest::from_manifest_file`], as the build file may not be
+    /// be in the `rust-project.json`.
+    pub build_file: Utf8PathBuf,
+    /// The kind of target.
+    ///
+    /// Examples (non-exhaustively) include [`TargetKind::Bin`], [`TargetKind::Lib`],
+    /// and [`TargetKind::Test`]. This information is used to determine what sort
+    /// of runnable codelens to provide, if any.
+    pub target_kind: TargetKind,
+}
+
+/// A template-like structure for describing runnables.
+///
+/// These are used for running and debugging binaries and tests without encoding
+/// build system-specific knowledge into rust-analyzer.
+///
+/// # Example
+///
+/// Below is an example of a test runnable. `{label}` and `{test_id}`
+/// are explained in [`Runnable::args`]'s documentation.
+///
+/// ```json
+/// {
+///     "program": "buck",
+///     "args": [
+///         "test",
+///          "{label}",
+///          "--",
+///          "{test_id}",
+///          "--print-passing-details"
+///     ],
+///     "cwd": "/home/user/repo-root/",
+///     "kind": "testOne"
+/// }
+/// ```
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Runnable {
+    /// The program invoked by the runnable.
+    ///
+    /// For example, this might be `cargo`, `buck`, or `bazel`.
+    pub program: String,
+    /// The arguments passed to [`Runnable::program`].
+    ///
+    /// The args can contain two template strings: `{label}` and `{test_id}`.
+    /// rust-analyzer will find and replace `{label}` with [`Build::label`] and
+    /// `{test_id}` with the test name.
+    pub args: Vec<String>,
+    /// The current working directory of the runnable.
+    pub cwd: Utf8PathBuf,
+    pub kind: RunnableKind,
+}
+
+/// The kind of runnable.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum RunnableKind {
+    Check,
+
+    /// Can run a binary.
+    Run,
+
+    /// Run a single test.
+    TestOne,
 }
 
 impl ProjectJson {
@@ -95,6 +178,7 @@ impl ProjectJson {
     ///
     /// # Arguments
     ///
+    /// * `manifest` - The path to the `rust-project.json`.
     /// * `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.
@@ -109,6 +193,7 @@ impl ProjectJson {
             sysroot_src: data.sysroot_src.map(absolutize_on_base),
             project_root: base.to_path_buf(),
             manifest,
+            runnables: data.runnables.into_iter().map(Runnable::from).collect(),
             crates: data
                 .crates
                 .into_iter()
@@ -127,6 +212,15 @@ impl ProjectJson {
                         None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
                     };
 
+                    let build = match crate_data.build {
+                        Some(build) => Some(Build {
+                            label: build.label,
+                            build_file: build.build_file,
+                            target_kind: build.target_kind.into(),
+                        }),
+                        None => None,
+                    };
+
                     Crate {
                         display_name: crate_data
                             .display_name
@@ -146,6 +240,7 @@ impl ProjectJson {
                         exclude,
                         is_proc_macro: crate_data.is_proc_macro,
                         repository: crate_data.repository,
+                        build,
                     }
                 })
                 .collect(),
@@ -167,10 +262,27 @@ impl ProjectJson {
         &self.project_root
     }
 
+    pub fn crate_by_root(&self, root: &AbsPath) -> Option<Crate> {
+        self.crates
+            .iter()
+            .filter(|krate| krate.is_workspace_member)
+            .find(|krate| krate.root_module == root)
+            .cloned()
+    }
+
+    /// Returns the path to the project's manifest, if it exists.
+    pub fn manifest(&self) -> Option<&ManifestPath> {
+        self.manifest.as_ref()
+    }
+
     /// Returns the path to the project's manifest or root folder, if no manifest exists.
     pub fn manifest_or_root(&self) -> &AbsPath {
         self.manifest.as_ref().map_or(&self.project_root, |manifest| manifest.as_ref())
     }
+
+    pub fn runnables(&self) -> &[Runnable] {
+        &self.runnables
+    }
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -178,6 +290,8 @@ pub struct ProjectJsonData {
     sysroot: Option<Utf8PathBuf>,
     sysroot_src: Option<Utf8PathBuf>,
     crates: Vec<CrateData>,
+    #[serde(default)]
+    runnables: Vec<RunnableData>,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -200,6 +314,8 @@ struct CrateData {
     is_proc_macro: bool,
     #[serde(default)]
     repository: Option<String>,
+    #[serde(default)]
+    build: Option<BuildData>,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -215,6 +331,48 @@ enum EditionData {
     Edition2024,
 }
 
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct BuildData {
+    label: String,
+    build_file: Utf8PathBuf,
+    target_kind: TargetKindData,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct RunnableData {
+    pub program: String,
+    pub args: Vec<String>,
+    pub cwd: Utf8PathBuf,
+    pub kind: RunnableKindData,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum RunnableKindData {
+    Check,
+    Run,
+    TestOne,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum TargetKindData {
+    Bin,
+    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
+    Lib,
+    Test,
+}
+
+impl From<TargetKindData> for TargetKind {
+    fn from(data: TargetKindData) -> Self {
+        match data {
+            TargetKindData::Bin => TargetKind::Bin,
+            TargetKindData::Lib => TargetKind::Lib { is_proc_macro: false },
+            TargetKindData::Test => TargetKind::Test,
+        }
+    }
+}
+
 impl From<EditionData> for Edition {
     fn from(data: EditionData) -> Self {
         match data {
@@ -226,6 +384,22 @@ impl From<EditionData> for Edition {
     }
 }
 
+impl From<RunnableData> for Runnable {
+    fn from(data: RunnableData) -> Self {
+        Runnable { program: data.program, args: data.args, cwd: data.cwd, kind: data.kind.into() }
+    }
+}
+
+impl From<RunnableKindData> for RunnableKind {
+    fn from(data: RunnableKindData) -> Self {
+        match data {
+            RunnableKindData::Check => RunnableKind::Check,
+            RunnableKindData::Run => RunnableKind::Run,
+            RunnableKindData::TestOne => RunnableKind::TestOne,
+        }
+    }
+}
+
 /// Identifies a crate by position in the crates array.
 ///
 /// This will differ from `CrateId` when multiple `ProjectJson`
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index 26499308ce9..599897f84a0 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -21,7 +21,7 @@ pub(crate) fn get(
     extra_env: &FxHashMap<String, String>,
     config: RustcCfgConfig<'_>,
 ) -> Vec<CfgFlag> {
-    let _p = tracing::span!(tracing::Level::INFO, "rustc_cfg::get").entered();
+    let _p = tracing::info_span!("rustc_cfg::get").entered();
     let mut res = Vec::with_capacity(6 * 2 + 1);
 
     // Some nightly-only cfgs, which are required for stdlib
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 653e7157bcb..1eeec4cedeb 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -219,8 +219,7 @@ impl Sysroot {
                         ", try running `rustup component add rust-src` to possibly fix this"
                     };
                     sysroot.error = Some(format!(
-                        "sysroot at `{}` is missing a `core` library{var_note}",
-                        src_root,
+                        "sysroot at `{src_root}` is missing a `core` library{var_note}",
                     ));
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index a6730863d6b..2762de5997a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -126,7 +126,7 @@ fn replace_fake_sys_root(s: &mut String) {
     let fake_sysroot_path = get_test_path("fake-sysroot");
     let fake_sysroot_path = if cfg!(windows) {
         let normalized_path = fake_sysroot_path.as_str().replace('\\', r#"\\"#);
-        format!(r#"{}\\"#, normalized_path)
+        format!(r#"{normalized_path}\\"#)
     } else {
         format!("{}/", fake_sysroot_path.as_str())
     };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 0d2174073a2..17e40e74de3 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -76,7 +76,7 @@ pub enum ProjectWorkspaceKind {
         /// Environment variables set in the `.cargo/config` file.
         cargo_config_extra_env: FxHashMap<String, String>,
     },
-    /// Project workspace was manually specified using a `rust-project.json` file.
+    /// Project workspace was specified using a `rust-project.json` file.
     Json(ProjectJson),
     // 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.
@@ -527,6 +527,16 @@ impl ProjectWorkspace {
         }
     }
 
+    pub fn manifest(&self) -> Option<&ManifestPath> {
+        match &self.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. } => Some(cargo.manifest_path()),
+            ProjectWorkspaceKind::Json(project) => project.manifest(),
+            ProjectWorkspaceKind::DetachedFile { cargo, .. } => {
+                Some(cargo.as_ref()?.0.manifest_path())
+            }
+        }
+    }
+
     pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
         self.sysroot.discover_proc_macro_srv()
     }
@@ -705,7 +715,7 @@ impl ProjectWorkspace {
         load: FileLoader<'_>,
         extra_env: &FxHashMap<String, String>,
     ) -> (CrateGraph, ProcMacroPaths) {
-        let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
+        let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered();
 
         let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
         let ((mut crate_graph, proc_macros), sysroot) = match kind {
@@ -949,7 +959,7 @@ fn cargo_to_crate_graph(
     override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let _p = tracing::span!(tracing::Level::INFO, "cargo_to_crate_graph").entered();
+    let _p = tracing::info_span!("cargo_to_crate_graph").entered();
     let mut res = (CrateGraph::default(), ProcMacroPaths::default());
     let crate_graph = &mut res.0;
     let proc_macros = &mut res.1;
@@ -1134,7 +1144,7 @@ fn detached_file_to_crate_graph(
     sysroot: &Sysroot,
     override_cfg: &CfgOverrides,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered();
+    let _p = tracing::info_span!("detached_file_to_crate_graph").entered();
     let mut crate_graph = CrateGraph::default();
     let (public_deps, _libproc_macro) =
         sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
@@ -1365,7 +1375,7 @@ fn sysroot_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: FileLoader<'_>,
 ) -> (SysrootPublicDeps, Option<CrateId>) {
-    let _p = tracing::span!(tracing::Level::INFO, "sysroot_to_crate_graph").entered();
+    let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
     match sysroot.mode() {
         SysrootMode::Workspace(cargo) => {
             let (mut cg, mut pm) = cargo_to_crate_graph(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 34b3e493140..8ff7235b8fa 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -22,6 +22,7 @@ path = "src/bin/main.rs"
 [dependencies]
 anyhow.workspace = true
 crossbeam-channel = "0.5.5"
+dirs = "5.0.1"
 dissimilar.workspace = true
 itertools.workspace = true
 scip = "0.3.3"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 9daae914d79..774784f37b0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -15,7 +15,11 @@ use std::{env, fs, path::PathBuf, process::ExitCode, sync::Arc};
 
 use anyhow::Context;
 use lsp_server::Connection;
-use rust_analyzer::{cli::flags, config::Config, from_json};
+use rust_analyzer::{
+    cli::flags,
+    config::{Config, ConfigChange, ConfigErrors},
+    from_json,
+};
 use semver::Version;
 use tracing_subscriber::fmt::writer::BoxMakeWriter;
 use vfs::AbsPathBuf;
@@ -220,16 +224,22 @@ fn run_server() -> anyhow::Result<()> {
         .filter(|workspaces| !workspaces.is_empty())
         .unwrap_or_else(|| vec![root_path.clone()]);
     let mut config =
-        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version);
+        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version, None);
     if let Some(json) = initialization_options {
-        if let Err(e) = config.update(json) {
+        let mut change = ConfigChange::default();
+        change.change_client_config(json);
+
+        let error_sink: ConfigErrors;
+        (config, error_sink, _) = config.apply_change(change);
+
+        if !error_sink.is_empty() {
             use lsp_types::{
                 notification::{Notification, ShowMessage},
                 MessageType, ShowMessageParams,
             };
             let not = lsp_server::Notification::new(
                 ShowMessage::METHOD.to_owned(),
-                ShowMessageParams { typ: MessageType::WARNING, message: e.to_string() },
+                ShowMessageParams { typ: MessageType::WARNING, message: error_sink.to_string() },
             );
             connection.sender.send(lsp_server::Message::Notification(not)).unwrap();
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
index a1469c22abf..a207be3cac3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
@@ -223,7 +223,7 @@ fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProvi
 
 fn more_trigger_character(config: &Config) -> Vec<String> {
     let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()];
-    if config.snippet_cap() {
+    if config.snippet_cap().is_some() {
         res.push("<".to_owned());
     }
     res
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index bded41932c0..90b81d0a80d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -25,7 +25,7 @@ use ide_db::{
         salsa::{self, debug::DebugQueryTable, ParallelDatabase},
         SourceDatabase, SourceDatabaseExt,
     },
-    LineIndexDatabase,
+    LineIndexDatabase, SnippetCap,
 };
 use itertools::Itertools;
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
@@ -479,7 +479,7 @@ impl flags::AnalysisStats {
                                         .or_insert(1);
                                 } else {
                                     acc.syntax_errors += 1;
-                                    bar.println(format!("Syntax error: \n{}", err));
+                                    bar.println(format!("Syntax error: \n{err}"));
                                 }
                             }
                         }
@@ -982,6 +982,7 @@ impl flags::AnalysisStats {
                     disable_experimental: false,
                     disabled: Default::default(),
                     expr_fill_default: Default::default(),
+                    snippet_cap: SnippetCap::new(true),
                     insert_use: ide_db::imports::insert_use::InsertUseConfig {
                         granularity: ide_db::imports::insert_use::ImportGranularity::Crate,
                         enforce_granularity: true,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
index ed048aa635b..85ec95409ae 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
@@ -6,7 +6,7 @@ use crate::cli::{flags, read_stdin};
 
 impl flags::Parse {
     pub fn run(self) -> anyhow::Result<()> {
-        let _p = tracing::span!(tracing::Level::INFO, "flags::Parse::run").entered();
+        let _p = tracing::info_span!("flags::Parse::run").entered();
         let text = read_stdin()?;
         let file = SourceFile::parse(&text, Edition::CURRENT).tree();
         if !self.no_dump {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
index a2d0dcc599c..10cb2d5ad6e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
@@ -49,7 +49,7 @@ impl flags::RunTests {
         let mut sw_all = StopWatch::start();
         for test in tests {
             let full_name = full_name_of_item(db, test.module(db), test.name(db));
-            println!("test {}", full_name);
+            println!("test {full_name}");
             if test.is_ignore(db) {
                 println!("ignored");
                 ignore_count += 1;
@@ -62,7 +62,7 @@ impl flags::RunTests {
             } else {
                 fail_count += 1;
             }
-            println!("{}", result);
+            println!("{result}");
             eprintln!("{:<20} {}", format!("test {}", full_name), sw_one.elapsed());
         }
         println!("{pass_count} passed, {fail_count} failed, {ignore_count} ignored");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index e9a4db7a2b0..31565878d84 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -220,8 +220,8 @@ impl Tester {
             self.pass_count += 1;
         } else {
             println!("{p:?} FAIL");
-            println!("actual   (r-a)   = {:?}", actual);
-            println!("expected (rustc) = {:?}", expected);
+            println!("actual   (r-a)   = {actual:?}");
+            println!("expected (rustc) = {expected:?}");
             self.fail_count += 1;
         }
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index aef2c1be224..8f60b17b594 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -10,9 +10,11 @@ use ide_db::LineIndexDatabase;
 use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
 use rustc_hash::{FxHashMap, FxHashSet};
 use scip::types as scip_types;
+use tracing::error;
 
 use crate::{
     cli::flags,
+    config::ConfigChange,
     line_index::{LineEndings, LineIndex, PositionEncoding},
 };
 
@@ -35,12 +37,20 @@ impl flags::Scip {
             lsp_types::ClientCapabilities::default(),
             vec![],
             None,
+            None,
         );
 
         if let Some(p) = self.config_path {
             let mut file = std::io::BufReader::new(std::fs::File::open(p)?);
             let json = serde_json::from_reader(&mut file)?;
-            config.update(json)?;
+            let mut change = ConfigChange::default();
+            change.change_client_config(json);
+
+            let error_sink;
+            (config, error_sink, _) = config.apply_change(change);
+
+            // FIXME @alibektas : What happens to errors without logging?
+            error!(?error_sink, "Config Error(s)");
         }
         let cargo_config = config.cargo();
         let (db, vfs, _) = load_workspace_at(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index a8d1e72aed9..e8504979bed 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -1,14 +1,12 @@
 //! Config used by the language server.
 //!
-//! We currently get this config from `initialize` LSP request, which is not the
-//! best way to do it, but was the simplest thing we could implement.
-//!
 //! Of particular interest is the `feature_flags` hash map: while other fields
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
-use std::{fmt, iter, ops::Not};
+use std::{fmt, iter, ops::Not, sync::OnceLock};
 
 use cfg::{CfgAtom, CfgDiff};
+use dirs::config_dir;
 use flycheck::{CargoOptions, FlycheckConfig};
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
@@ -29,9 +27,13 @@ use project_model::{
 };
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
-use serde::{de::DeserializeOwned, Deserialize, Serialize};
+use serde::{
+    de::{DeserializeOwned, Error},
+    Deserialize, Serialize,
+};
 use stdx::format_to_acc;
-use vfs::{AbsPath, AbsPathBuf};
+use triomphe::Arc;
+use vfs::{AbsPath, AbsPathBuf, VfsPath};
 
 use crate::{
     caps::completion_item_edit_resolve,
@@ -60,6 +62,7 @@ mod patch_old_style;
 // parsing the old name.
 config_data! {
     /// Configs that apply on a workspace-wide scope. There are 3 levels on which a global configuration can be configured
+    // FIXME: 1. and 3. should be split, some configs do not make sense per project
     ///
     /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer.toml)
     /// 2. Client's own configurations (e.g `settings.json` on VS Code)
@@ -67,16 +70,10 @@ config_data! {
     ///
     /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
     global: struct GlobalDefaultConfigData <- GlobalConfigInput -> {
-        /// Whether to insert #[must_use] when generating `as_` methods
-        /// for enum variants.
-        assist_emitMustUse: bool               = false,
-        /// Placeholder expression to use for missing expressions in assists.
-        assist_expressionFillDefault: ExprFillDefaultDef              = ExprFillDefaultDef::Todo,
-
         /// Warm up caches on project load.
         cachePriming_enable: bool = true,
         /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
-        cachePriming_numThreads: ParallelCachePrimingNumThreads = 0u8,
+        cachePriming_numThreads: NumThreads = NumThreads::Physical,
 
         /// Pass `--all-targets` to cargo invocation.
         cargo_allTargets: bool           = true,
@@ -272,87 +269,12 @@ config_data! {
         /// The warnings will be indicated by a blue squiggly underline in code
         /// and a blue icon in the `Problems Panel`.
         diagnostics_warningsAsInfo: Vec<String> = vec![],
+
         /// These directories will be ignored by rust-analyzer. They are
         /// relative to the workspace root, and globs are not supported. You may
         /// also need to add the folders to Code's `files.watcherExclude`.
         files_excludeDirs: Vec<Utf8PathBuf> = vec![],
-        /// Controls file watching implementation.
-        files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
 
-        /// Whether to show `Debug` action. Only applies when
-        /// `#rust-analyzer.hover.actions.enable#` is set.
-        hover_actions_debug_enable: bool           = true,
-        /// Whether to show HoverActions in Rust files.
-        hover_actions_enable: bool          = true,
-        /// Whether to show `Go to Type Definition` action. Only applies when
-        /// `#rust-analyzer.hover.actions.enable#` is set.
-        hover_actions_gotoTypeDef_enable: bool     = true,
-        /// Whether to show `Implementations` action. Only applies when
-        /// `#rust-analyzer.hover.actions.enable#` is set.
-        hover_actions_implementations_enable: bool = true,
-        /// Whether to show `References` action. Only applies when
-        /// `#rust-analyzer.hover.actions.enable#` is set.
-        hover_actions_references_enable: bool      = false,
-        /// Whether to show `Run` action. Only applies when
-        /// `#rust-analyzer.hover.actions.enable#` is set.
-        hover_actions_run_enable: bool             = true,
-
-        /// Whether to show documentation on hover.
-        hover_documentation_enable: bool           = true,
-        /// Whether to show keyword hover popups. Only applies when
-        /// `#rust-analyzer.hover.documentation.enable#` is set.
-        hover_documentation_keywords_enable: bool  = true,
-        /// Use markdown syntax for links on hover.
-        hover_links_enable: bool = true,
-        /// How to render the align information in a memory layout hover.
-        hover_memoryLayout_alignment: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
-        /// Whether to show memory layout data on hover.
-        hover_memoryLayout_enable: bool = true,
-        /// How to render the niche information in a memory layout hover.
-        hover_memoryLayout_niches: Option<bool> = Some(false),
-        /// How to render the offset information in a memory layout hover.
-        hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
-        /// How to render the size information in a memory layout hover.
-        hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
-
-        /// How many variants of an enum to display when hovering on. Show none if empty.
-        hover_show_enumVariants: Option<usize> = Some(5),
-        /// How many fields of a struct, variant or union to display when hovering on. Show none if empty.
-        hover_show_fields: Option<usize> = Some(5),
-        /// How many associated items of a trait to display when hovering a trait.
-        hover_show_traitAssocItems: Option<usize> = None,
-
-        /// Enables the experimental support for interpreting tests.
-        interpret_tests: bool                                      = false,
-
-        /// Whether to show `Debug` lens. Only applies when
-        /// `#rust-analyzer.lens.enable#` is set.
-        lens_debug_enable: bool            = true,
-        /// Whether to show CodeLens in Rust files.
-        lens_enable: bool           = true,
-        /// Internal config: use custom client-side commands even when the
-        /// client doesn't set the corresponding capability.
-        lens_forceCustomCommands: bool = true,
-        /// Whether to show `Implementations` lens. Only applies when
-        /// `#rust-analyzer.lens.enable#` is set.
-        lens_implementations_enable: bool  = true,
-        /// Where to render annotations.
-        lens_location: AnnotationLocation = AnnotationLocation::AboveName,
-        /// Whether to show `References` lens for Struct, Enum, and Union.
-        /// Only applies when `#rust-analyzer.lens.enable#` is set.
-        lens_references_adt_enable: bool = false,
-        /// Whether to show `References` lens for Enum Variants.
-        /// Only applies when `#rust-analyzer.lens.enable#` is set.
-        lens_references_enumVariant_enable: bool = false,
-        /// Whether to show `Method References` lens. Only applies when
-        /// `#rust-analyzer.lens.enable#` is set.
-        lens_references_method_enable: bool = false,
-        /// Whether to show `References` lens for Trait.
-        /// Only applies when `#rust-analyzer.lens.enable#` is set.
-        lens_references_trait_enable: bool = false,
-        /// Whether to show `Run` lens. Only applies when
-        /// `#rust-analyzer.lens.enable#` is set.
-        lens_run_enable: bool              = true,
 
         /// Disable project auto-discovery in favor of explicitly specified set
         /// of projects.
@@ -367,31 +289,10 @@ config_data! {
         /// Sets the LRU capacity of the specified queries.
         lru_query_capacities: FxHashMap<Box<str>, usize> = FxHashMap::default(),
 
-        /// Whether to show `can't find Cargo.toml` error message.
-        notifications_cargoTomlNotFound: bool      = true,
-
-        /// Whether to send an UnindexedProject notification to the client.
-        notifications_unindexedProject: bool      = false,
-
-        /// How many worker threads in the main loop. The default `null` means to pick automatically.
-        numThreads: Option<usize> = None,
-
-        /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
-        procMacro_attributes_enable: bool = true,
-        /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
-        procMacro_enable: bool                     = true,
         /// These proc-macros will be ignored when trying to expand them.
         ///
         /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
         procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>>          = FxHashMap::default(),
-        /// Internal config, path to proc-macro server executable.
-        procMacro_server: Option<Utf8PathBuf>          = None,
-
-        /// Exclude imports from find-all-references.
-        references_excludeImports: bool = false,
-
-        /// Exclude tests from find-all-references.
-        references_excludeTests: bool = false,
 
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_command: Option<String> = None,
@@ -429,34 +330,41 @@ config_data! {
         /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
         /// available on a nightly build.
         rustfmt_rangeFormatting_enable: bool = false,
-
-
-        /// Show full signature of the callable. Only shows parameters if disabled.
-        signatureInfo_detail: SignatureDetail                           = SignatureDetail::Full,
-        /// Show documentation.
-        signatureInfo_documentation_enable: bool                       = true,
-
-        /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
-        typing_autoClosingAngleBrackets_enable: bool = false,
-
-        /// Workspace symbol search kind.
-        workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
-        /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
-        /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
-        /// Other clients requires all results upfront and might require a higher limit.
-        workspace_symbol_search_limit: usize = 128,
-        /// Workspace symbol search scope.
-        workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace,
     }
 }
 
 config_data! {
-    /// Local configurations can be overridden for every crate by placing a `rust-analyzer.toml` on crate root.
-    /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
+    /// Local configurations can be defined per `SourceRoot`. This almost always corresponds to a `Crate`.
     local: struct LocalDefaultConfigData <- LocalConfigInput ->  {
+        /// Whether to insert #[must_use] when generating `as_` methods
+        /// for enum variants.
+        assist_emitMustUse: bool               = false,
+        /// Placeholder expression to use for missing expressions in assists.
+        assist_expressionFillDefault: ExprFillDefaultDef              = ExprFillDefaultDef::Todo,
         /// Term search fuel in "units of work" for assists (Defaults to 400).
         assist_termSearch_fuel: usize = 400,
 
+        /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
+        imports_granularity_enforce: bool              = false,
+        /// How imports should be grouped into use statements.
+        imports_granularity_group: ImportGranularityDef  = ImportGranularityDef::Crate,
+        /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
+        imports_group_enable: bool                           = true,
+        /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
+        imports_merge_glob: bool           = true,
+        /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
+        imports_preferNoStd | imports_prefer_no_std: bool = false,
+         /// Whether to prefer import paths containing a `prelude` module.
+        imports_preferPrelude: bool                       = false,
+        /// The path structure for newly inserted paths to use.
+        imports_prefix: ImportPrefixDef               = ImportPrefixDef::Plain,
+    }
+}
+
+config_data! {
+    /// Configs that only make sense when they are set by a client. As such they can only be defined
+    /// by setting them using client's settings (e.g `settings.json` on VS Code).
+    client: struct ClientDefaultConfigData <- ClientConfigInput -> {
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = true,
@@ -521,6 +429,9 @@ config_data! {
         /// Term search fuel in "units of work" for autocompletion (Defaults to 200).
         completion_termSearch_fuel: usize = 200,
 
+        /// Controls file watching implementation.
+        files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
+
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = true,
         /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.
@@ -532,21 +443,48 @@ config_data! {
         /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
         highlightRelated_yieldPoints_enable: bool = true,
 
-        /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
-        imports_granularity_enforce: bool              = false,
-        /// How imports should be grouped into use statements.
-        imports_granularity_group: ImportGranularityDef  = ImportGranularityDef::Crate,
-        /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
-        imports_group_enable: bool                           = true,
-        /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
-        imports_merge_glob: bool           = true,
-        /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
-        imports_preferNoStd | imports_prefer_no_std: bool = false,
-         /// Whether to prefer import paths containing a `prelude` module.
-        imports_preferPrelude: bool                       = false,
-        /// The path structure for newly inserted paths to use.
-        imports_prefix: ImportPrefixDef               = ImportPrefixDef::Plain,
+        /// Whether to show `Debug` action. Only applies when
+        /// `#rust-analyzer.hover.actions.enable#` is set.
+        hover_actions_debug_enable: bool           = true,
+        /// Whether to show HoverActions in Rust files.
+        hover_actions_enable: bool          = true,
+        /// Whether to show `Go to Type Definition` action. Only applies when
+        /// `#rust-analyzer.hover.actions.enable#` is set.
+        hover_actions_gotoTypeDef_enable: bool     = true,
+        /// Whether to show `Implementations` action. Only applies when
+        /// `#rust-analyzer.hover.actions.enable#` is set.
+        hover_actions_implementations_enable: bool = true,
+        /// Whether to show `References` action. Only applies when
+        /// `#rust-analyzer.hover.actions.enable#` is set.
+        hover_actions_references_enable: bool      = false,
+        /// Whether to show `Run` action. Only applies when
+        /// `#rust-analyzer.hover.actions.enable#` is set.
+        hover_actions_run_enable: bool             = true,
 
+        /// Whether to show documentation on hover.
+        hover_documentation_enable: bool           = true,
+        /// Whether to show keyword hover popups. Only applies when
+        /// `#rust-analyzer.hover.documentation.enable#` is set.
+        hover_documentation_keywords_enable: bool  = true,
+        /// Use markdown syntax for links on hover.
+        hover_links_enable: bool = true,
+        /// How to render the align information in a memory layout hover.
+        hover_memoryLayout_alignment: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
+        /// Whether to show memory layout data on hover.
+        hover_memoryLayout_enable: bool = true,
+        /// How to render the niche information in a memory layout hover.
+        hover_memoryLayout_niches: Option<bool> = Some(false),
+        /// How to render the offset information in a memory layout hover.
+        hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
+        /// How to render the size information in a memory layout hover.
+        hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
+
+        /// How many variants of an enum to display when hovering on. Show none if empty.
+        hover_show_enumVariants: Option<usize> = Some(5),
+        /// How many fields of a struct, variant or union to display when hovering on. Show none if empty.
+        hover_show_fields: Option<usize> = Some(5),
+        /// How many associated items of a trait to display when hovering a trait.
+        hover_show_traitAssocItems: Option<usize> = None,
 
         /// Whether to show inlay type hints for binding modes.
         inlayHints_bindingModeHints_enable: bool                   = false,
@@ -597,6 +535,8 @@ config_data! {
         /// Whether to hide inlay type hints for constructors.
         inlayHints_typeHints_hideNamedConstructor: bool            = false,
 
+        /// Enables the experimental support for interpreting tests.
+        interpret_tests: bool = false,
 
         /// Join lines merges consecutive declaration and initialization of an assignment.
         joinLines_joinAssignments: bool = true,
@@ -607,6 +547,57 @@ config_data! {
         /// Join lines unwraps trivial blocks.
         joinLines_unwrapTrivialBlock: bool = true,
 
+        /// Whether to show `Debug` lens. Only applies when
+        /// `#rust-analyzer.lens.enable#` is set.
+        lens_debug_enable: bool            = true,
+        /// Whether to show CodeLens in Rust files.
+        lens_enable: bool           = true,
+        /// Internal config: use custom client-side commands even when the
+        /// client doesn't set the corresponding capability.
+        lens_forceCustomCommands: bool = true,
+        /// Whether to show `Implementations` lens. Only applies when
+        /// `#rust-analyzer.lens.enable#` is set.
+        lens_implementations_enable: bool  = true,
+        /// Where to render annotations.
+        lens_location: AnnotationLocation = AnnotationLocation::AboveName,
+        /// Whether to show `References` lens for Struct, Enum, and Union.
+        /// Only applies when `#rust-analyzer.lens.enable#` is set.
+        lens_references_adt_enable: bool = false,
+        /// Whether to show `References` lens for Enum Variants.
+        /// Only applies when `#rust-analyzer.lens.enable#` is set.
+        lens_references_enumVariant_enable: bool = false,
+        /// Whether to show `Method References` lens. Only applies when
+        /// `#rust-analyzer.lens.enable#` is set.
+        lens_references_method_enable: bool = false,
+        /// Whether to show `References` lens for Trait.
+        /// Only applies when `#rust-analyzer.lens.enable#` is set.
+        lens_references_trait_enable: bool = false,
+        /// Whether to show `Run` lens. Only applies when
+        /// `#rust-analyzer.lens.enable#` is set.
+        lens_run_enable: bool              = true,
+
+        /// Whether to show `can't find Cargo.toml` error message.
+        notifications_cargoTomlNotFound: bool      = true,
+
+        /// Whether to send an UnindexedProject notification to the client.
+        notifications_unindexedProject: bool      = false,
+
+        /// How many worker threads in the main loop. The default `null` means to pick automatically.
+        numThreads: Option<NumThreads> = None,
+
+        /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
+        procMacro_attributes_enable: bool = true,
+        /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
+        procMacro_enable: bool                     = true,
+        /// Internal config, path to proc-macro server executable.
+        procMacro_server: Option<Utf8PathBuf>          = None,
+
+        /// Exclude imports from find-all-references.
+        references_excludeImports: bool = false,
+
+        /// Exclude tests from find-all-references.
+        references_excludeTests: bool = false,
+
         /// Inject additional highlighting into doc comments.
         ///
         /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
@@ -643,13 +634,24 @@ config_data! {
         /// By disabling semantic tokens for strings, other grammars can be used to highlight
         /// their contents.
         semanticHighlighting_strings_enable: bool = true,
-    }
-}
 
-config_data! {
-    /// Configs that only make sense when they are set by a client. As such they can only be defined
-    /// by setting them using client's settings (e.g `settings.json` on VS Code).
-    client: struct ClientDefaultConfigData <- ClientConfigInput -> {}
+        /// Show full signature of the callable. Only shows parameters if disabled.
+        signatureInfo_detail: SignatureDetail                           = SignatureDetail::Full,
+        /// Show documentation.
+        signatureInfo_documentation_enable: bool                       = true,
+
+        /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
+        typing_autoClosingAngleBrackets_enable: bool = false,
+
+        /// Workspace symbol search kind.
+        workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
+        /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
+        /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
+        /// Other clients requires all results upfront and might require a higher limit.
+        workspace_symbol_search_limit: usize = 128,
+        /// Workspace symbol search scope.
+        workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace,
+    }
 }
 
 #[derive(Debug, Clone)]
@@ -659,23 +661,294 @@ pub struct Config {
     workspace_roots: Vec<AbsPathBuf>,
     caps: lsp_types::ClientCapabilities,
     root_path: AbsPathBuf,
-    detached_files: Vec<AbsPathBuf>,
     snippets: Vec<Snippet>,
     visual_studio_code_version: Option<Version>,
 
-    default_config: DefaultConfigData,
-    client_config: FullConfigInput,
-    user_config: GlobalLocalConfigInput,
-    #[allow(dead_code)]
-    ratoml_files: FxHashMap<SourceRootId, RatomlNode>,
+    default_config: &'static DefaultConfigData,
+    /// Config node that obtains its initial value during the server initialization and
+    /// by receiving a `lsp_types::notification::DidChangeConfiguration`.
+    client_config: (FullConfigInput, ConfigErrors),
+
+    /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
+    /// If not specified by init of a `Config` object this value defaults to :
+    ///
+    /// |Platform | Value                                 | Example                                  |
+    /// | ------- | ------------------------------------- | ---------------------------------------- |
+    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
+    /// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support |
+    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
+    user_config_path: VfsPath,
+
+    /// FIXME @alibektas : Change this to sth better.
+    /// Config node whose values apply to **every** Rust project.
+    user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>,
+
+    /// A special file for this session whose path is set to `self.root_path.join("rust-analyzer.toml")`
+    root_ratoml_path: VfsPath,
+
+    /// This file can be used to make global changes while having only a workspace-wide scope.
+    root_ratoml: Option<(GlobalLocalConfigInput, ConfigErrors)>,
+
+    /// For every `SourceRoot` there can be at most one RATOML file.
+    ratoml_files: FxHashMap<SourceRootId, (LocalConfigInput, ConfigErrors)>,
+
+    /// Clone of the value that is stored inside a `GlobalState`.
+    source_root_parent_map: Arc<FxHashMap<SourceRootId, SourceRootId>>,
+
+    detached_files: Vec<AbsPathBuf>,
 }
 
-#[derive(Clone, Debug)]
-struct RatomlNode {
-    #[allow(dead_code)]
-    node: GlobalLocalConfigInput,
-    #[allow(dead_code)]
-    parent: Option<SourceRootId>,
+impl Config {
+    pub fn user_config_path(&self) -> &VfsPath {
+        &self.user_config_path
+    }
+
+    pub fn same_source_root_parent_map(
+        &self,
+        other: &Arc<FxHashMap<SourceRootId, SourceRootId>>,
+    ) -> bool {
+        Arc::ptr_eq(&self.source_root_parent_map, other)
+    }
+
+    // FIXME @alibektas : Server's health uses error sink but in other places it is not used atm.
+    /// Changes made to client and global configurations will partially not be reflected even after `.apply_change()` was called.
+    /// The return tuple's bool component signals whether the `GlobalState` should call its `update_configuration()` method.
+    fn apply_change_with_sink(&self, change: ConfigChange) -> (Config, bool) {
+        let mut config = self.clone();
+
+        let mut should_update = false;
+
+        if let Some(change) = change.user_config_change {
+            if let Ok(table) = toml::from_str(&change) {
+                let mut toml_errors = vec![];
+                validate_toml_table(
+                    GlobalLocalConfigInput::FIELDS,
+                    &table,
+                    &mut String::new(),
+                    &mut toml_errors,
+                );
+                config.user_config = Some((
+                    GlobalLocalConfigInput::from_toml(table, &mut toml_errors),
+                    ConfigErrors(
+                        toml_errors
+                            .into_iter()
+                            .map(|(a, b)| ConfigErrorInner::Toml { config_key: a, error: b })
+                            .map(Arc::new)
+                            .collect(),
+                    ),
+                ));
+                should_update = true;
+            }
+        }
+
+        if let Some(mut json) = change.client_config_change {
+            tracing::info!("updating config from JSON: {:#}", json);
+            if !(json.is_null() || json.as_object().map_or(false, |it| it.is_empty())) {
+                let mut json_errors = vec![];
+                let detached_files = get_field::<Vec<Utf8PathBuf>>(
+                    &mut json,
+                    &mut json_errors,
+                    "detachedFiles",
+                    None,
+                )
+                .unwrap_or_default()
+                .into_iter()
+                .map(AbsPathBuf::assert)
+                .collect();
+
+                patch_old_style::patch_json_for_outdated_configs(&mut json);
+
+                config.client_config = (
+                    FullConfigInput::from_json(json, &mut json_errors),
+                    ConfigErrors(
+                        json_errors
+                            .into_iter()
+                            .map(|(a, b)| ConfigErrorInner::Json { config_key: a, error: b })
+                            .map(Arc::new)
+                            .collect(),
+                    ),
+                );
+                config.detached_files = detached_files;
+            }
+            should_update = true;
+        }
+
+        if let Some(change) = change.root_ratoml_change {
+            tracing::info!("updating root ra-toml config: {:#}", change);
+            #[allow(clippy::single_match)]
+            match toml::from_str(&change) {
+                Ok(table) => {
+                    let mut toml_errors = vec![];
+                    validate_toml_table(
+                        GlobalLocalConfigInput::FIELDS,
+                        &table,
+                        &mut String::new(),
+                        &mut toml_errors,
+                    );
+                    config.root_ratoml = Some((
+                        GlobalLocalConfigInput::from_toml(table, &mut toml_errors),
+                        ConfigErrors(
+                            toml_errors
+                                .into_iter()
+                                .map(|(a, b)| ConfigErrorInner::Toml { config_key: a, error: b })
+                                .map(Arc::new)
+                                .collect(),
+                        ),
+                    ));
+                    should_update = true;
+                }
+                // FIXME
+                Err(_) => (),
+            }
+        }
+
+        if let Some(change) = change.ratoml_file_change {
+            for (source_root_id, (_, text)) in change {
+                if let Some(text) = text {
+                    let mut toml_errors = vec![];
+                    tracing::info!("updating ra-toml config: {:#}", text);
+                    #[allow(clippy::single_match)]
+                    match toml::from_str(&text) {
+                        Ok(table) => {
+                            validate_toml_table(
+                                &[LocalConfigInput::FIELDS],
+                                &table,
+                                &mut String::new(),
+                                &mut toml_errors,
+                            );
+                            config.ratoml_files.insert(
+                                source_root_id,
+                                (
+                                    LocalConfigInput::from_toml(&table, &mut toml_errors),
+                                    ConfigErrors(
+                                        toml_errors
+                                            .into_iter()
+                                            .map(|(a, b)| ConfigErrorInner::Toml {
+                                                config_key: a,
+                                                error: b,
+                                            })
+                                            .map(Arc::new)
+                                            .collect(),
+                                    ),
+                                ),
+                            );
+                        }
+                        // FIXME
+                        Err(_) => (),
+                    }
+                }
+            }
+        }
+
+        if let Some(source_root_map) = change.source_map_change {
+            config.source_root_parent_map = source_root_map;
+        }
+
+        let snips = self.completion_snippets_custom().to_owned();
+
+        for (name, def) in snips.iter() {
+            if def.prefix.is_empty() && def.postfix.is_empty() {
+                continue;
+            }
+            let scope = match def.scope {
+                SnippetScopeDef::Expr => SnippetScope::Expr,
+                SnippetScopeDef::Type => SnippetScope::Type,
+                SnippetScopeDef::Item => SnippetScope::Item,
+            };
+            #[allow(clippy::single_match)]
+            match Snippet::new(
+                &def.prefix,
+                &def.postfix,
+                &def.body,
+                def.description.as_ref().unwrap_or(name),
+                &def.requires,
+                scope,
+            ) {
+                Some(snippet) => config.snippets.push(snippet),
+                // FIXME
+                // None => error_sink.0.push(ConfigErrorInner::Json {
+                //     config_key: "".to_owned(),
+                //     error: <serde_json::Error as serde::de::Error>::custom(format!(
+                //         "snippet {name} is invalid or triggers are missing",
+                //     )),
+                // }),
+                None => (),
+            }
+        }
+
+        // FIXME: bring this back
+        // if config.check_command().is_empty() {
+        //     error_sink.0.push(ConfigErrorInner::Json {
+        //         config_key: "/check/command".to_owned(),
+        //         error: serde_json::Error::custom("expected a non-empty string"),
+        //     });
+        // }
+        (config, should_update)
+    }
+
+    /// Given `change` this generates a new `Config`, thereby collecting errors of type `ConfigError`.
+    /// If there are changes that have global/client level effect, the last component of the return type
+    /// will be set to `true`, which should be used by the `GlobalState` to update itself.
+    pub fn apply_change(&self, change: ConfigChange) -> (Config, ConfigErrors, bool) {
+        let (config, should_update) = self.apply_change_with_sink(change);
+        let e = ConfigErrors(
+            config
+                .client_config
+                .1
+                 .0
+                .iter()
+                .chain(config.root_ratoml.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
+                .chain(config.user_config.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
+                .chain(config.ratoml_files.values().flat_map(|it| it.1 .0.iter()))
+                .cloned()
+                .collect(),
+        );
+        (config, e, should_update)
+    }
+}
+
+#[derive(Default, Debug)]
+pub struct ConfigChange {
+    user_config_change: Option<Arc<str>>,
+    root_ratoml_change: Option<Arc<str>>,
+    client_config_change: Option<serde_json::Value>,
+    ratoml_file_change: Option<FxHashMap<SourceRootId, (VfsPath, Option<Arc<str>>)>>,
+    source_map_change: Option<Arc<FxHashMap<SourceRootId, SourceRootId>>>,
+}
+
+impl ConfigChange {
+    pub fn change_ratoml(
+        &mut self,
+        source_root: SourceRootId,
+        vfs_path: VfsPath,
+        content: Option<Arc<str>>,
+    ) -> Option<(VfsPath, Option<Arc<str>>)> {
+        self.ratoml_file_change
+            .get_or_insert_with(Default::default)
+            .insert(source_root, (vfs_path, content))
+    }
+
+    pub fn change_user_config(&mut self, content: Option<Arc<str>>) {
+        assert!(self.user_config_change.is_none()); // Otherwise it is a double write.
+        self.user_config_change = content;
+    }
+
+    pub fn change_root_ratoml(&mut self, content: Option<Arc<str>>) {
+        assert!(self.root_ratoml_change.is_none()); // Otherwise it is a double write.
+        self.root_ratoml_change = content;
+    }
+
+    pub fn change_client_config(&mut self, change: serde_json::Value) {
+        self.client_config_change = Some(change);
+    }
+
+    pub fn change_source_root_parent_map(
+        &mut self,
+        source_root_map: Arc<FxHashMap<SourceRootId, SourceRootId>>,
+    ) {
+        assert!(self.source_map_change.is_none());
+        self.source_map_change = Some(source_root_map.clone());
+    }
 }
 
 macro_rules! try_ {
@@ -695,8 +968,6 @@ macro_rules! try_or_def {
     };
 }
 
-type ParallelCachePrimingNumThreads = u8;
-
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum LinkedProject {
     ProjectManifest(ProjectManifest),
@@ -866,27 +1137,39 @@ pub struct ClientCommandsConfig {
 }
 
 #[derive(Debug)]
-pub struct ConfigError {
-    errors: Vec<(String, serde_json::Error)>,
+pub enum ConfigErrorInner {
+    Json { config_key: String, error: serde_json::Error },
+    Toml { config_key: String, error: toml::de::Error },
 }
 
-impl fmt::Display for ConfigError {
+#[derive(Clone, Debug)]
+pub struct ConfigErrors(Vec<Arc<ConfigErrorInner>>);
+
+impl ConfigErrors {
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
+impl fmt::Display for ConfigErrors {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let errors = self.errors.iter().format_with("\n", |(key, e), f| {
-            f(key)?;
-            f(&": ")?;
-            f(e)
+        let errors = self.0.iter().format_with("\n", |inner, f| match &**inner {
+            ConfigErrorInner::Json { config_key: key, error: e } => {
+                f(key)?;
+                f(&": ")?;
+                f(e)
+            }
+            ConfigErrorInner::Toml { config_key: key, error: e } => {
+                f(key)?;
+                f(&": ")?;
+                f(e)
+            }
         });
-        write!(
-            f,
-            "invalid config value{}:\n{}",
-            if self.errors.len() == 1 { "" } else { "s" },
-            errors
-        )
+        write!(f, "invalid config value{}:\n{}", if self.0.len() == 1 { "" } else { "s" }, errors)
     }
 }
 
-impl std::error::Error for ConfigError {}
+impl std::error::Error for ConfigErrors {}
 
 impl Config {
     pub fn new(
@@ -894,19 +1177,46 @@ impl Config {
         caps: ClientCapabilities,
         workspace_roots: Vec<AbsPathBuf>,
         visual_studio_code_version: Option<Version>,
+        user_config_path: Option<Utf8PathBuf>,
     ) -> Self {
+        static DEFAULT_CONFIG_DATA: OnceLock<&'static DefaultConfigData> = OnceLock::new();
+        let user_config_path = if let Some(user_config_path) = user_config_path {
+            user_config_path.join("rust-analyzer").join("rust-analyzer.toml")
+        } else {
+            let p = config_dir()
+                .expect("A config dir is expected to existed on all platforms ra supports.")
+                .join("rust-analyzer")
+                .join("rust-analyzer.toml");
+            Utf8PathBuf::from_path_buf(p).expect("Config dir expected to be abs.")
+        };
+
+        // A user config cannot be a virtual path as rust-analyzer cannot support watching changes in virtual paths.
+        // See `GlobalState::process_changes` to get more info.
+        // FIXME @alibektas : Temporary solution. I don't think this is right as at some point we may allow users to specify
+        // custom USER_CONFIG_PATHs which may also be relative.
+        let user_config_path = VfsPath::from(AbsPathBuf::assert(user_config_path));
+        let root_ratoml_path = {
+            let mut p = root_path.clone();
+            p.push("rust-analyzer.toml");
+            VfsPath::new_real_path(p.to_string())
+        };
+
         Config {
             caps,
-            detached_files: Vec::new(),
             discovered_projects: Vec::new(),
             root_path,
             snippets: Default::default(),
             workspace_roots,
             visual_studio_code_version,
-            client_config: FullConfigInput::default(),
-            user_config: GlobalLocalConfigInput::default(),
+            client_config: (FullConfigInput::default(), ConfigErrors(vec![])),
             ratoml_files: FxHashMap::default(),
-            default_config: DefaultConfigData::default(),
+            default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())),
+            source_root_parent_map: Arc::new(FxHashMap::default()),
+            user_config: None,
+            user_config_path,
+            root_ratoml: None,
+            root_ratoml_path,
+            detached_files: Default::default(),
         }
     }
 
@@ -929,71 +1239,6 @@ impl Config {
         self.workspace_roots.extend(paths);
     }
 
-    pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigError> {
-        tracing::info!("updating config from JSON: {:#}", json);
-        if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
-            return Ok(());
-        }
-        let mut errors = Vec::new();
-        self.detached_files =
-            get_field::<Vec<Utf8PathBuf>>(&mut json, &mut errors, "detachedFiles", None)
-                .unwrap_or_default()
-                .into_iter()
-                .map(AbsPathBuf::assert)
-                .collect();
-        patch_old_style::patch_json_for_outdated_configs(&mut json);
-        self.client_config = FullConfigInput::from_json(json, &mut errors);
-        tracing::debug!(?self.client_config, "deserialized config data");
-        self.snippets.clear();
-
-        let snips = self.completion_snippets_custom(None).to_owned();
-
-        for (name, def) in snips.iter() {
-            if def.prefix.is_empty() && def.postfix.is_empty() {
-                continue;
-            }
-            let scope = match def.scope {
-                SnippetScopeDef::Expr => SnippetScope::Expr,
-                SnippetScopeDef::Type => SnippetScope::Type,
-                SnippetScopeDef::Item => SnippetScope::Item,
-            };
-            match Snippet::new(
-                &def.prefix,
-                &def.postfix,
-                &def.body,
-                def.description.as_ref().unwrap_or(name),
-                &def.requires,
-                scope,
-            ) {
-                Some(snippet) => self.snippets.push(snippet),
-                None => errors.push((
-                    format!("snippet {name} is invalid"),
-                    <serde_json::Error as serde::de::Error>::custom(
-                        "snippet path is invalid or triggers are missing",
-                    ),
-                )),
-            }
-        }
-
-        self.validate(&mut errors);
-
-        if errors.is_empty() {
-            Ok(())
-        } else {
-            Err(ConfigError { errors })
-        }
-    }
-
-    fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) {
-        use serde::de::Error;
-        if self.check_command().is_empty() {
-            error_sink.push((
-                "/check/command".to_owned(),
-                serde_json::Error::custom("expected a non-empty string"),
-            ));
-        }
-    }
-
     pub fn json_schema() -> serde_json::Value {
         FullConfigInput::json_schema()
     }
@@ -1002,23 +1247,23 @@ impl Config {
         &self.root_path
     }
 
-    pub fn caps(&self) -> &lsp_types::ClientCapabilities {
-        &self.caps
+    pub fn root_ratoml_path(&self) -> &VfsPath {
+        &self.root_ratoml_path
     }
 
-    pub fn detached_files(&self) -> &[AbsPathBuf] {
-        &self.detached_files
+    pub fn caps(&self) -> &lsp_types::ClientCapabilities {
+        &self.caps
     }
 }
 
 impl Config {
     pub fn assist(&self, source_root: Option<SourceRootId>) -> AssistConfig {
         AssistConfig {
-            snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
+            snippet_cap: self.snippet_cap(),
             allowed: None,
             insert_use: self.insert_use_config(source_root),
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
-            assist_emit_must_use: self.assist_emitMustUse().to_owned(),
+            assist_emit_must_use: self.assist_emitMustUse(source_root).to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
             term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
         }
@@ -1026,17 +1271,13 @@ impl Config {
 
     pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
         CompletionConfig {
-            enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
-            enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
+            enable_postfix_completions: self.completion_postfix_enable().to_owned(),
+            enable_imports_on_the_fly: self.completion_autoimport_enable().to_owned()
                 && completion_item_edit_resolve(&self.caps),
-            enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
-            enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
-            enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
-            term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
-            full_function_signatures: self
-                .completion_fullFunctionSignatures_enable(source_root)
-                .to_owned(),
-            callable: match self.completion_callable_snippets(source_root) {
+            enable_self_on_the_fly: self.completion_autoself_enable().to_owned(),
+            enable_private_editable: self.completion_privateEditable_enable().to_owned(),
+            full_function_signatures: self.completion_fullFunctionSignatures_enable().to_owned(),
+            callable: match self.completion_callable_snippets() {
                 CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
                 CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
                 CallableCompletionDef::None => None,
@@ -1055,10 +1296,18 @@ impl Config {
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
             snippets: self.snippets.clone().to_vec(),
-            limit: self.completion_limit(source_root).to_owned(),
+            limit: self.completion_limit().to_owned(),
+            enable_term_search: self.completion_termSearch_enable().to_owned(),
+            term_search_fuel: self.completion_termSearch_fuel().to_owned() as u64,
         }
     }
 
+    pub fn detached_files(&self) -> &Vec<AbsPathBuf> {
+        // FIXME @alibektas : This is the only config that is confusing. If it's a proper configuration
+        // why is it not among the others? If it's client only which I doubt it is current state should be alright
+        &self.detached_files
+    }
+
     pub fn diagnostics(&self, source_root: Option<SourceRootId>) -> DiagnosticsConfig {
         DiagnosticsConfig {
             enabled: *self.diagnostics_enable(),
@@ -1066,10 +1315,11 @@ impl Config {
             proc_macros_enabled: *self.procMacro_enable(),
             disable_experimental: !self.diagnostics_experimental_enable(),
             disabled: self.diagnostics_disabled().clone(),
-            expr_fill_default: match self.assist_expressionFillDefault() {
+            expr_fill_default: match self.assist_expressionFillDefault(source_root) {
                 ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
             },
+            snippet_cap: self.snippet_cap(),
             insert_use: self.insert_use_config(source_root),
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
@@ -1081,13 +1331,13 @@ impl Config {
         self.procMacro_enable().to_owned() && self.procMacro_attributes_enable().to_owned()
     }
 
-    pub fn highlight_related(&self, source_root: Option<SourceRootId>) -> HighlightRelatedConfig {
+    pub fn highlight_related(&self, _source_root: Option<SourceRootId>) -> HighlightRelatedConfig {
         HighlightRelatedConfig {
-            references: self.highlightRelated_references_enable(source_root).to_owned(),
-            break_points: self.highlightRelated_breakPoints_enable(source_root).to_owned(),
-            exit_points: self.highlightRelated_exitPoints_enable(source_root).to_owned(),
-            yield_points: self.highlightRelated_yieldPoints_enable(source_root).to_owned(),
-            closure_captures: self.highlightRelated_closureCaptures_enable(source_root).to_owned(),
+            references: self.highlightRelated_references_enable().to_owned(),
+            break_points: self.highlightRelated_breakPoints_enable().to_owned(),
+            exit_points: self.highlightRelated_exitPoints_enable().to_owned(),
+            yield_points: self.highlightRelated_yieldPoints_enable().to_owned(),
+            closure_captures: self.highlightRelated_closureCaptures_enable().to_owned(),
         }
     }
 
@@ -1141,7 +1391,7 @@ impl Config {
         }
     }
 
-    pub fn inlay_hints(&self, source_root: Option<SourceRootId>) -> InlayHintsConfig {
+    pub fn inlay_hints(&self) -> InlayHintsConfig {
         let client_capability_fields = self
             .caps
             .text_document
@@ -1155,74 +1405,65 @@ impl Config {
             .collect::<FxHashSet<_>>();
 
         InlayHintsConfig {
-            render_colons: self.inlayHints_renderColons(source_root).to_owned(),
-            type_hints: self.inlayHints_typeHints_enable(source_root).to_owned(),
-            parameter_hints: self.inlayHints_parameterHints_enable(source_root).to_owned(),
-            chaining_hints: self.inlayHints_chainingHints_enable(source_root).to_owned(),
-            discriminant_hints: match self.inlayHints_discriminantHints_enable(source_root) {
+            render_colons: self.inlayHints_renderColons().to_owned(),
+            type_hints: self.inlayHints_typeHints_enable().to_owned(),
+            parameter_hints: self.inlayHints_parameterHints_enable().to_owned(),
+            chaining_hints: self.inlayHints_chainingHints_enable().to_owned(),
+            discriminant_hints: match self.inlayHints_discriminantHints_enable() {
                 DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
                 DiscriminantHintsDef::Never => ide::DiscriminantHints::Never,
                 DiscriminantHintsDef::Fieldless => ide::DiscriminantHints::Fieldless,
             },
-            closure_return_type_hints: match self
-                .inlayHints_closureReturnTypeHints_enable(source_root)
-            {
+            closure_return_type_hints: match self.inlayHints_closureReturnTypeHints_enable() {
                 ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
                 ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
                 ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock,
             },
-            lifetime_elision_hints: match self.inlayHints_lifetimeElisionHints_enable(source_root) {
+            lifetime_elision_hints: match self.inlayHints_lifetimeElisionHints_enable() {
                 LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always,
                 LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never,
                 LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
             },
             hide_named_constructor_hints: self
-                .inlayHints_typeHints_hideNamedConstructor(source_root)
+                .inlayHints_typeHints_hideNamedConstructor()
                 .to_owned(),
             hide_closure_initialization_hints: self
-                .inlayHints_typeHints_hideClosureInitialization(source_root)
+                .inlayHints_typeHints_hideClosureInitialization()
                 .to_owned(),
-            closure_style: match self.inlayHints_closureStyle(source_root) {
+            closure_style: match self.inlayHints_closureStyle() {
                 ClosureStyle::ImplFn => hir::ClosureStyle::ImplFn,
                 ClosureStyle::RustAnalyzer => hir::ClosureStyle::RANotation,
                 ClosureStyle::WithId => hir::ClosureStyle::ClosureWithId,
                 ClosureStyle::Hide => hir::ClosureStyle::Hide,
             },
-            closure_capture_hints: self
-                .inlayHints_closureCaptureHints_enable(source_root)
-                .to_owned(),
-            adjustment_hints: match self.inlayHints_expressionAdjustmentHints_enable(source_root) {
+            closure_capture_hints: self.inlayHints_closureCaptureHints_enable().to_owned(),
+            adjustment_hints: match self.inlayHints_expressionAdjustmentHints_enable() {
                 AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
-                AdjustmentHintsDef::Never => {
-                    match self.inlayHints_reborrowHints_enable(source_root) {
-                        ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
-                            ide::AdjustmentHints::ReborrowOnly
-                        }
-                        ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
+                AdjustmentHintsDef::Never => match self.inlayHints_reborrowHints_enable() {
+                    ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
+                        ide::AdjustmentHints::ReborrowOnly
                     }
-                }
+                    ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
+                },
                 AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
             },
-            adjustment_hints_mode: match self.inlayHints_expressionAdjustmentHints_mode(source_root)
-            {
+            adjustment_hints_mode: match self.inlayHints_expressionAdjustmentHints_mode() {
                 AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
                 AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
                 AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
                 AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
             },
             adjustment_hints_hide_outside_unsafe: self
-                .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe(source_root)
+                .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe()
                 .to_owned(),
-            binding_mode_hints: self.inlayHints_bindingModeHints_enable(source_root).to_owned(),
+            binding_mode_hints: self.inlayHints_bindingModeHints_enable().to_owned(),
             param_names_for_lifetime_elision_hints: self
-                .inlayHints_lifetimeElisionHints_useParameterNames(source_root)
+                .inlayHints_lifetimeElisionHints_useParameterNames()
                 .to_owned(),
-            max_length: self.inlayHints_maxLength(source_root).to_owned(),
-            closing_brace_hints_min_lines: if self
-                .inlayHints_closingBraceHints_enable(source_root)
-                .to_owned()
+            max_length: self.inlayHints_maxLength().to_owned(),
+            closing_brace_hints_min_lines: if self.inlayHints_closingBraceHints_enable().to_owned()
             {
-                Some(self.inlayHints_closingBraceHints_minLines(source_root).to_owned())
+                Some(self.inlayHints_closingBraceHints_minLines().to_owned())
             } else {
                 None
             },
@@ -1233,10 +1474,8 @@ impl Config {
                 resolve_label_location: client_capability_fields.contains("label.location"),
                 resolve_label_command: client_capability_fields.contains("label.command"),
             },
-            implicit_drop_hints: self.inlayHints_implicitDrops_enable(source_root).to_owned(),
-            range_exclusive_hints: self
-                .inlayHints_rangeExclusiveHints_enable(source_root)
-                .to_owned(),
+            implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
+            range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
         }
     }
 
@@ -1260,36 +1499,32 @@ impl Config {
         }
     }
 
-    pub fn join_lines(&self, source_root: Option<SourceRootId>) -> JoinLinesConfig {
+    pub fn join_lines(&self) -> JoinLinesConfig {
         JoinLinesConfig {
-            join_else_if: self.joinLines_joinElseIf(source_root).to_owned(),
-            remove_trailing_comma: self.joinLines_removeTrailingComma(source_root).to_owned(),
-            unwrap_trivial_blocks: self.joinLines_unwrapTrivialBlock(source_root).to_owned(),
-            join_assignments: self.joinLines_joinAssignments(source_root).to_owned(),
+            join_else_if: self.joinLines_joinElseIf().to_owned(),
+            remove_trailing_comma: self.joinLines_removeTrailingComma().to_owned(),
+            unwrap_trivial_blocks: self.joinLines_unwrapTrivialBlock().to_owned(),
+            join_assignments: self.joinLines_joinAssignments().to_owned(),
         }
     }
 
-    pub fn highlighting_non_standard_tokens(&self, source_root: Option<SourceRootId>) -> bool {
-        self.semanticHighlighting_nonStandardTokens(source_root).to_owned()
+    pub fn highlighting_non_standard_tokens(&self) -> bool {
+        self.semanticHighlighting_nonStandardTokens().to_owned()
     }
 
-    pub fn highlighting_config(&self, source_root: Option<SourceRootId>) -> HighlightConfig {
+    pub fn highlighting_config(&self) -> HighlightConfig {
         HighlightConfig {
-            strings: self.semanticHighlighting_strings_enable(source_root).to_owned(),
-            punctuation: self.semanticHighlighting_punctuation_enable(source_root).to_owned(),
+            strings: self.semanticHighlighting_strings_enable().to_owned(),
+            punctuation: self.semanticHighlighting_punctuation_enable().to_owned(),
             specialize_punctuation: self
-                .semanticHighlighting_punctuation_specialization_enable(source_root)
+                .semanticHighlighting_punctuation_specialization_enable()
                 .to_owned(),
-            macro_bang: self
-                .semanticHighlighting_punctuation_separate_macro_bang(source_root)
-                .to_owned(),
-            operator: self.semanticHighlighting_operator_enable(source_root).to_owned(),
+            macro_bang: self.semanticHighlighting_punctuation_separate_macro_bang().to_owned(),
+            operator: self.semanticHighlighting_operator_enable().to_owned(),
             specialize_operator: self
-                .semanticHighlighting_operator_specialization_enable(source_root)
-                .to_owned(),
-            inject_doc_comment: self
-                .semanticHighlighting_doc_comment_inject_enable(source_root)
+                .semanticHighlighting_operator_specialization_enable()
                 .to_owned(),
+            inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
         }
     }
@@ -1771,8 +2006,10 @@ impl Config {
         *self.references_excludeTests()
     }
 
-    pub fn snippet_cap(&self) -> bool {
-        self.experimental("snippetTextEdit")
+    pub fn snippet_cap(&self) -> Option<SnippetCap> {
+        // FIXME: Also detect the proposed lsp version at caps.workspace.workspaceEdit.snippetEditSupport
+        // once lsp-types has it.
+        SnippetCap::new(self.experimental("snippetTextEdit"))
     }
 
     pub fn call_info(&self) -> CallInfoConfig {
@@ -1856,15 +2093,22 @@ impl Config {
         }
     }
 
-    pub fn prime_caches_num_threads(&self) -> u8 {
-        match *self.cachePriming_numThreads() {
-            0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX),
-            n => n,
+    pub fn prime_caches_num_threads(&self) -> usize {
+        match self.cachePriming_numThreads() {
+            NumThreads::Concrete(0) | NumThreads::Physical => num_cpus::get_physical(),
+            &NumThreads::Concrete(n) => n,
+            NumThreads::Logical => num_cpus::get(),
         }
     }
 
     pub fn main_loop_num_threads(&self) -> usize {
-        self.numThreads().unwrap_or(num_cpus::get_physical())
+        match self.numThreads() {
+            Some(NumThreads::Concrete(0)) | None | Some(NumThreads::Physical) => {
+                num_cpus::get_physical()
+            }
+            &Some(NumThreads::Concrete(n)) => n,
+            Some(NumThreads::Logical) => num_cpus::get(),
+        }
     }
 
     pub fn typing_autoclose_angle(&self) -> bool {
@@ -1959,51 +2203,6 @@ macro_rules! create_bool_or_string_serde {
 create_bool_or_string_serde!(true_or_always<true, "always">);
 create_bool_or_string_serde!(false_or_never<false, "never">);
 
-macro_rules! named_unit_variant {
-    ($variant:ident) => {
-        pub(super) mod $variant {
-            pub(in super::super) fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                struct V;
-                impl<'de> serde::de::Visitor<'de> for V {
-                    type Value = ();
-                    fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                        f.write_str(concat!("\"", stringify!($variant), "\""))
-                    }
-                    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
-                        if value == stringify!($variant) {
-                            Ok(())
-                        } else {
-                            Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
-                        }
-                    }
-                }
-                deserializer.deserialize_str(V)
-            }
-            pub(in super::super) fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
-            where
-                S: serde::Serializer,
-            {
-                serializer.serialize_str(stringify!($variant))
-            }
-        }
-    };
-}
-
-mod unit_v {
-    named_unit_variant!(all);
-    named_unit_variant!(skip_trivial);
-    named_unit_variant!(mutable);
-    named_unit_variant!(reborrow);
-    named_unit_variant!(fieldless);
-    named_unit_variant!(with_block);
-    named_unit_variant!(decimal);
-    named_unit_variant!(hexadecimal);
-    named_unit_variant!(both);
-}
-
 #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[derive(Default)]
@@ -2016,7 +2215,7 @@ enum SnippetScopeDef {
 
 #[derive(Serialize, Deserialize, Debug, Clone, Default)]
 #[serde(default)]
-struct SnippetDef {
+pub(crate) struct SnippetDef {
     #[serde(with = "single_or_array")]
     #[serde(skip_serializing_if = "Vec::is_empty")]
     prefix: Vec<String>,
@@ -2111,17 +2310,17 @@ enum ImportGranularityDef {
 
 #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
 #[serde(rename_all = "snake_case")]
-enum CallableCompletionDef {
+pub(crate) enum CallableCompletionDef {
     FillArguments,
     AddParentheses,
     None,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum CargoFeaturesDef {
-    #[serde(with = "unit_v::all")]
     All,
+    #[serde(untagged)]
     Selected(Vec<String>),
 }
 
@@ -2143,25 +2342,27 @@ enum InvocationLocation {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum LifetimeElisionDef {
+    SkipTrivial,
     #[serde(with = "true_or_always")]
+    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
+    #[serde(untagged)]
     Never,
-    #[serde(with = "unit_v::skip_trivial")]
-    SkipTrivial,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum ClosureReturnTypeHintsDef {
+    WithBlock,
     #[serde(with = "true_or_always")]
+    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
+    #[serde(untagged)]
     Never,
-    #[serde(with = "unit_v::with_block")]
-    WithBlock,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -2174,36 +2375,39 @@ enum ClosureStyle {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum ReborrowHintsDef {
+    Mutable,
     #[serde(with = "true_or_always")]
+    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
+    #[serde(untagged)]
     Never,
-    #[serde(with = "unit_v::mutable")]
-    Mutable,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum AdjustmentHintsDef {
+    Reborrow,
     #[serde(with = "true_or_always")]
+    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
+    #[serde(untagged)]
     Never,
-    #[serde(with = "unit_v::reborrow")]
-    Reborrow,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(untagged)]
+#[serde(rename_all = "snake_case")]
 enum DiscriminantHintsDef {
+    Fieldless,
     #[serde(with = "true_or_always")]
+    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
+    #[serde(untagged)]
     Never,
-    #[serde(with = "unit_v::fieldless")]
-    Fieldless,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -2227,9 +2431,11 @@ enum FilesWatcherDef {
 #[serde(rename_all = "snake_case")]
 enum ImportPrefixDef {
     Plain,
-    #[serde(alias = "self")]
+    #[serde(rename = "self")]
+    #[serde(alias = "by_self")]
     BySelf,
-    #[serde(alias = "crate")]
+    #[serde(rename = "crate")]
+    #[serde(alias = "by_crate")]
     ByCrate,
 }
 
@@ -2256,13 +2462,9 @@ enum WorkspaceSymbolSearchKindDef {
 
 #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
 #[serde(rename_all = "snake_case")]
-#[serde(untagged)]
 enum MemoryLayoutHoverRenderKindDef {
-    #[serde(with = "unit_v::decimal")]
     Decimal,
-    #[serde(with = "unit_v::hexadecimal")]
     Hexadecimal,
-    #[serde(with = "unit_v::both")]
     Both,
 }
 
@@ -2285,6 +2487,15 @@ pub enum TargetDirectory {
     Directory(Utf8PathBuf),
 }
 
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum NumThreads {
+    Physical,
+    Logical,
+    #[serde(untagged)]
+    Concrete(usize),
+}
+
 macro_rules! _default_val {
     (@verbatim: $s:literal, $ty:ty) => {{
         let default_: $ty = serde_json::from_str(&$s).unwrap();
@@ -2318,54 +2529,81 @@ macro_rules! _impl_for_config_data {
             $(
                 $($doc)*
                 #[allow(non_snake_case)]
-                $vis fn $field(&self, _source_root: Option<SourceRootId>) -> &$ty {
-                    if let Some(v) = self.client_config.local.$field.as_ref() {
-                        return &v;
+                $vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty {
+                    let mut par: Option<SourceRootId> = source_root;
+                    while let Some(source_root_id) = par {
+                        par = self.source_root_parent_map.get(&source_root_id).copied();
+                        if let Some((config, _)) = self.ratoml_files.get(&source_root_id) {
+                            if let Some(value) = config.$field.as_ref() {
+                                return value;
+                            }
+                        }
+                    }
+
+                    if let Some((root_path_ratoml, _)) = self.root_ratoml.as_ref() {
+                        if let Some(v) = root_path_ratoml.local.$field.as_ref() {
+                            return &v;
+                        }
                     }
 
-                    if let Some(v) = self.user_config.local.$field.as_ref() {
+                    if let Some(v) = self.client_config.0.local.$field.as_ref() {
                         return &v;
                     }
 
+                    if let Some((user_config, _)) = self.user_config.as_ref() {
+                        if let Some(v) = user_config.local.$field.as_ref() {
+                            return &v;
+                        }
+                    }
+
                     &self.default_config.local.$field
                 }
             )*
         }
     };
     (global, $(
-                $(#[doc=$doc:literal])*
-                $vis:vis $field:ident : $ty:ty = $default:expr,
-            )*
-        ) => {
+            $(#[doc=$doc:literal])*
+            $vis:vis $field:ident : $ty:ty = $default:expr,
+        )*
+    ) => {
         impl Config {
             $(
                 $($doc)*
                 #[allow(non_snake_case)]
                 $vis fn $field(&self) -> &$ty {
-                    if let Some(v) = self.client_config.global.$field.as_ref() {
-                        return &v;
+
+                    if let Some((root_path_ratoml, _)) = self.root_ratoml.as_ref() {
+                        if let Some(v) = root_path_ratoml.global.$field.as_ref() {
+                            return &v;
+                        }
                     }
 
-                    if let Some(v) = self.user_config.global.$field.as_ref() {
+                    if let Some(v) = self.client_config.0.global.$field.as_ref() {
                         return &v;
                     }
 
+                    if let Some((user_config, _)) = self.user_config.as_ref() {
+                        if let Some(v) = user_config.global.$field.as_ref() {
+                            return &v;
+                        }
+                    }
+
                     &self.default_config.global.$field
                 }
             )*
         }
     };
     (client, $(
-        $(#[doc=$doc:literal])*
-        $vis:vis $field:ident : $ty:ty = $default:expr,
-    )*
+            $(#[doc=$doc:literal])*
+            $vis:vis $field:ident : $ty:ty = $default:expr,
+       )*
     ) => {
         impl Config {
             $(
                 $($doc)*
                 #[allow(non_snake_case)]
                 $vis fn $field(&self) -> &$ty {
-                    if let Some(v) = self.client_config.global.$field.as_ref() {
+                    if let Some(v) = self.client_config.0.client.$field.as_ref() {
                         return &v;
                     }
 
@@ -2387,7 +2625,7 @@ macro_rules! _config_data {
     }) => {
         /// Default config values for this grouping.
         #[allow(non_snake_case)]
-        #[derive(Debug, Clone, Serialize)]
+        #[derive(Debug, Clone )]
         struct $name { $($field: $ty,)* }
 
         impl_for_config_data!{
@@ -2425,26 +2663,10 @@ macro_rules! _config_data {
             }
         }
 
-        #[allow(unused)]
-        impl $name {
-            /// Applies overrides from some more local config blob, to self.
-            fn apply_input(&mut self, input: $input) {
-                $(
-                    if let Some(value) = input.$field {
-                        self.$field = value;
-                    }
-                )*
-            }
-
-            fn clone_with_overrides(&self, input: $input) -> Self {
-                Self {$(
-                    $field: input.$field.unwrap_or_else(|| self.$field.clone()),
-                )*}
-            }
-        }
-
         #[allow(unused, clippy::ptr_arg)]
         impl $input {
+            const FIELDS: &'static [&'static str] = &[$(stringify!($field)),*];
+
             fn from_json(json: &mut serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> Self {
                 Self {$(
                     $field: get_field(
@@ -2456,7 +2678,7 @@ macro_rules! _config_data {
                 )*}
             }
 
-            fn from_toml(toml: &mut toml::Table, error_sink: &mut Vec<(String, toml::de::Error)>) -> Self {
+            fn from_toml(toml: &toml::Table, error_sink: &mut Vec<(String, toml::de::Error)>) -> Self {
                 Self {$(
                     $field: get_field_toml::<$ty>(
                         toml,
@@ -2483,8 +2705,7 @@ macro_rules! _config_data {
         mod $modname {
             #[test]
             fn fields_are_sorted() {
-                let field_names: &'static [&'static str] = &[$(stringify!($field)),*];
-                field_names.windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
+                super::$input::FIELDS.windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
             }
         }
     };
@@ -2495,18 +2716,16 @@ use _config_data as config_data;
 struct DefaultConfigData {
     global: GlobalDefaultConfigData,
     local: LocalDefaultConfigData,
-    #[allow(dead_code)]
     client: ClientDefaultConfigData,
 }
 
 /// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by
 /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
 /// all fields being None.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, Serialize)]
 struct FullConfigInput {
     global: GlobalConfigInput,
     local: LocalConfigInput,
-    #[allow(dead_code)]
     client: ClientConfigInput,
 }
 
@@ -2527,9 +2746,12 @@ impl FullConfigInput {
         GlobalConfigInput::schema_fields(&mut fields);
         LocalConfigInput::schema_fields(&mut fields);
         ClientConfigInput::schema_fields(&mut fields);
-        // HACK: sort the fields, so the diffs on the generated docs/schema are smaller
         fields.sort_by_key(|&(x, ..)| x);
         fields
+            .iter()
+            .tuple_windows()
+            .for_each(|(a, b)| assert!(a.0 != b.0, "{a:?} duplicate field"));
+        fields
     }
 
     fn json_schema() -> serde_json::Value {
@@ -2545,63 +2767,57 @@ impl FullConfigInput {
 /// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by
 /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
 /// all fields being None.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, Serialize)]
 struct GlobalLocalConfigInput {
     global: GlobalConfigInput,
     local: LocalConfigInput,
 }
 
 impl GlobalLocalConfigInput {
-    #[allow(dead_code)]
+    const FIELDS: &'static [&'static [&'static str]] =
+        &[GlobalConfigInput::FIELDS, LocalConfigInput::FIELDS];
     fn from_toml(
-        mut toml: toml::Table,
+        toml: toml::Table,
         error_sink: &mut Vec<(String, toml::de::Error)>,
     ) -> GlobalLocalConfigInput {
         GlobalLocalConfigInput {
-            global: GlobalConfigInput::from_toml(&mut toml, error_sink),
-            local: LocalConfigInput::from_toml(&mut toml, error_sink),
+            global: GlobalConfigInput::from_toml(&toml, error_sink),
+            local: LocalConfigInput::from_toml(&toml, error_sink),
         }
     }
 }
 
-fn get_field_toml<T: DeserializeOwned>(
-    val: &toml::Table,
-    error_sink: &mut Vec<(String, toml::de::Error)>,
+fn get_field<T: DeserializeOwned>(
+    json: &mut serde_json::Value,
+    error_sink: &mut Vec<(String, serde_json::Error)>,
     field: &'static str,
     alias: Option<&'static str>,
 ) -> Option<T> {
+    // XXX: check alias first, to work around the VS Code where it pre-fills the
+    // defaults instead of sending an empty object.
     alias
         .into_iter()
         .chain(iter::once(field))
         .filter_map(move |field| {
-            let subkeys = field.split('_');
-            let mut v = val;
-            for subkey in subkeys {
-                if let Some(val) = v.get(subkey) {
-                    if let Some(map) = val.as_table() {
-                        v = map;
-                    } else {
-                        return Some(toml::Value::try_into(val.clone()).map_err(|e| (e, v)));
-                    }
-                } else {
-                    return None;
-                }
-            }
-            None
+            let mut pointer = field.replace('_', "/");
+            pointer.insert(0, '/');
+            json.pointer_mut(&pointer)
+                .map(|it| serde_json::from_value(it.take()).map_err(|e| (e, pointer)))
         })
         .find(Result::is_ok)
         .and_then(|res| match res {
             Ok(it) => Some(it),
             Err((e, pointer)) => {
-                error_sink.push((pointer.to_string(), e));
+                tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
+                error_sink.push((pointer, e));
                 None
             }
         })
 }
 
-fn get_field<T: DeserializeOwned>(
-    json: &mut serde_json::Value,
-    error_sink: &mut Vec<(String, serde_json::Error)>,
+fn get_field_toml<T: DeserializeOwned>(
+    toml: &toml::Table,
+    error_sink: &mut Vec<(String, toml::de::Error)>,
     field: &'static str,
     alias: Option<&'static str>,
 ) -> Option<T> {
@@ -2613,8 +2829,8 @@ fn get_field<T: DeserializeOwned>(
         .filter_map(move |field| {
             let mut pointer = field.replace('_', "/");
             pointer.insert(0, '/');
-            json.pointer_mut(&pointer)
-                .map(|it| serde_json::from_value(it.take()).map_err(|e| (e, pointer)))
+            toml_pointer(toml, &pointer)
+                .map(|it| <_>::deserialize(it.clone()).map_err(|e| (e, pointer)))
         })
         .find(Result::is_ok)
         .and_then(|res| match res {
@@ -2627,6 +2843,32 @@ fn get_field<T: DeserializeOwned>(
         })
 }
 
+fn toml_pointer<'a>(toml: &'a toml::Table, pointer: &str) -> Option<&'a toml::Value> {
+    fn parse_index(s: &str) -> Option<usize> {
+        if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
+            return None;
+        }
+        s.parse().ok()
+    }
+
+    if pointer.is_empty() {
+        return None;
+    }
+    if !pointer.starts_with('/') {
+        return None;
+    }
+    let mut parts = pointer.split('/').skip(1);
+    let first = parts.next()?;
+    let init = toml.get(first)?;
+    parts.map(|x| x.replace("~1", "/").replace("~0", "~")).try_fold(init, |target, token| {
+        match target {
+            toml::Value::Table(table) => table.get(&token),
+            toml::Value::Array(list) => parse_index(&token).and_then(move |x| list.get(x)),
+            _ => None,
+        }
+    })
+}
+
 type SchemaField = (&'static str, &'static str, &'static [&'static str], String);
 
 fn schema(fields: &[SchemaField]) -> serde_json::Value {
@@ -2634,11 +2876,18 @@ fn schema(fields: &[SchemaField]) -> serde_json::Value {
         .iter()
         .map(|(field, ty, doc, default)| {
             let name = field.replace('_', ".");
+            let category =
+                name.find('.').map(|end| String::from(&name[..end])).unwrap_or("general".into());
             let name = format!("rust-analyzer.{name}");
             let props = field_props(field, ty, doc, default);
-            (name, props)
+            serde_json::json!({
+                "title": category,
+                "properties": {
+                    name: props
+                }
+            })
         })
-        .collect::<serde_json::Map<_, _>>();
+        .collect::<Vec<_>>();
     map.into()
 }
 
@@ -2761,11 +3010,6 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Search for all symbols kinds."
             ],
         },
-        "ParallelCachePrimingNumThreads" => set! {
-            "type": "number",
-            "minimum": 0,
-            "maximum": 255
-        },
         "LifetimeElisionDef" => set! {
             "type": "string",
             "enum": [
@@ -2987,12 +3231,77 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 },
             ],
         },
-        _ => panic!("missing entry for {ty}: {default}"),
+        "NumThreads" => set! {
+            "anyOf": [
+                {
+                    "type": "number",
+                    "minimum": 0,
+                    "maximum": 255
+                },
+                {
+                    "type": "string",
+                    "enum": ["physical", "logical", ],
+                    "enumDescriptions": [
+                        "Use the number of physical cores",
+                        "Use the number of logical cores",
+                    ],
+                },
+            ],
+        },
+        "Option<NumThreads>" => set! {
+            "anyOf": [
+                {
+                    "type": "null"
+                },
+                {
+                    "type": "number",
+                    "minimum": 0,
+                    "maximum": 255
+                },
+                {
+                    "type": "string",
+                    "enum": ["physical", "logical", ],
+                    "enumDescriptions": [
+                        "Use the number of physical cores",
+                        "Use the number of logical cores",
+                    ],
+                },
+            ],
+        },
+        _ => panic!("missing entry for {ty}: {default} (field {field})"),
     }
 
     map.into()
 }
 
+fn validate_toml_table(
+    known_ptrs: &[&[&'static str]],
+    toml: &toml::Table,
+    ptr: &mut String,
+    error_sink: &mut Vec<(String, toml::de::Error)>,
+) {
+    let verify = |ptr: &String| known_ptrs.iter().any(|ptrs| ptrs.contains(&ptr.as_str()));
+
+    let l = ptr.len();
+    for (k, v) in toml {
+        if !ptr.is_empty() {
+            ptr.push('_');
+        }
+        ptr.push_str(k);
+
+        match v {
+            // This is a table config, any entry in it is therefor valid
+            toml::Value::Table(_) if verify(ptr) => (),
+            toml::Value::Table(table) => validate_toml_table(known_ptrs, table, ptr, error_sink),
+            _ if !verify(ptr) => error_sink
+                .push((ptr.replace('_', "/"), toml::de::Error::custom("unexpected field"))),
+            _ => (),
+        }
+
+        ptr.truncate(l);
+    }
+}
+
 #[cfg(test)]
 fn manual(fields: &[SchemaField]) -> String {
     fields.iter().fold(String::new(), |mut acc, (field, _ty, doc, default)| {
@@ -3037,10 +3346,10 @@ mod tests {
         let s = Config::json_schema();
         let schema = format!("{s:#}");
         let mut schema = schema
-            .trim_start_matches('{')
-            .trim_end_matches('}')
+            .trim_start_matches('[')
+            .trim_end_matches(']')
             .replace("  ", "    ")
-            .replace('\n', "\n            ")
+            .replace('\n', "\n        ")
             .trim_start_matches('\n')
             .trim_end()
             .to_owned();
@@ -3072,8 +3381,10 @@ mod tests {
         let package_json_path = project_root().join("editors/code/package.json");
         let mut package_json = fs::read_to_string(&package_json_path).unwrap();
 
-        let start_marker = "                \"$generated-start\": {},\n";
-        let end_marker = "                \"$generated-end\": {}\n";
+        let start_marker =
+            "            {\n                \"title\": \"$generated-start\"\n            },\n";
+        let end_marker =
+            "            {\n                \"title\": \"$generated-end\"\n            }\n";
 
         let start = package_json.find(start_marker).unwrap() + start_marker.len();
         let end = package_json.find(end_marker).unwrap();
@@ -3104,12 +3415,16 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "procMacro_server": null,
-            }))
-            .unwrap();
+
+        let mut change = ConfigChange::default();
+        change.change_client_config(serde_json::json!({
+            "procMacro" : {
+                "server": null,
+        }}));
+
+        (config, _, _) = config.apply_change(change);
         assert_eq!(config.proc_macro_srv(), None);
     }
 
@@ -3120,12 +3435,15 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "procMacro": {"server": project_root().display().to_string()}
-            }))
-            .unwrap();
+        let mut change = ConfigChange::default();
+        change.change_client_config(serde_json::json!({
+        "procMacro" : {
+            "server": project_root().display().to_string(),
+        }}));
+
+        (config, _, _) = config.apply_change(change);
         assert_eq!(config.proc_macro_srv(), Some(AbsPathBuf::try_from(project_root()).unwrap()));
     }
 
@@ -3136,12 +3454,18 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "procMacro": {"server": "./server"}
-            }))
-            .unwrap();
+
+        let mut change = ConfigChange::default();
+
+        change.change_client_config(serde_json::json!({
+        "procMacro" : {
+            "server": "./server"
+        }}));
+
+        (config, _, _) = config.apply_change(change);
+
         assert_eq!(
             config.proc_macro_srv(),
             Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap())
@@ -3155,12 +3479,16 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "rust": { "analyzerTargetDir": null }
-            }))
-            .unwrap();
+
+        let mut change = ConfigChange::default();
+
+        change.change_client_config(serde_json::json!({
+            "rust" : { "analyzerTargetDir" : null }
+        }));
+
+        (config, _, _) = config.apply_change(change);
         assert_eq!(config.cargo_targetDir(), &None);
         assert!(
             matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
@@ -3174,12 +3502,16 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "rust": { "analyzerTargetDir": true }
-            }))
-            .unwrap();
+
+        let mut change = ConfigChange::default();
+        change.change_client_config(serde_json::json!({
+            "rust" : { "analyzerTargetDir" : true }
+        }));
+
+        (config, _, _) = config.apply_change(change);
+
         assert_eq!(config.cargo_targetDir(), &Some(TargetDirectory::UseSubdirectory(true)));
         assert!(
             matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
@@ -3193,12 +3525,16 @@ mod tests {
             Default::default(),
             vec![],
             None,
+            None,
         );
-        config
-            .update(serde_json::json!({
-                "rust": { "analyzerTargetDir": "other_folder" }
-            }))
-            .unwrap();
+
+        let mut change = ConfigChange::default();
+        change.change_client_config(serde_json::json!({
+            "rust" : { "analyzerTargetDir" : "other_folder" }
+        }));
+
+        (config, _, _) = config.apply_change(change);
+
         assert_eq!(
             config.cargo_targetDir(),
             &Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
@@ -3207,4 +3543,95 @@ mod tests {
             matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
         );
     }
+
+    #[test]
+    fn toml_unknown_key() {
+        let config = Config::new(
+            AbsPathBuf::try_from(project_root()).unwrap(),
+            Default::default(),
+            vec![],
+            None,
+            None,
+        );
+
+        let mut change = ConfigChange::default();
+
+        change.change_root_ratoml(Some(
+            toml::toml! {
+                [cargo.cfgs]
+                these = "these"
+                should = "should"
+                be = "be"
+                valid = "valid"
+
+                [invalid.config]
+                err = "error"
+
+                [cargo]
+                target = "ok"
+
+                // FIXME: This should be an error
+                [cargo.sysroot]
+                non-table = "expected"
+            }
+            .to_string()
+            .into(),
+        ));
+
+        let (config, e, _) = config.apply_change(change);
+        expect_test::expect![[r#"
+            ConfigErrors(
+                [
+                    Toml {
+                        config_key: "invalid/config/err",
+                        error: Error {
+                            inner: Error {
+                                inner: TomlError {
+                                    message: "unexpected field",
+                                    raw: None,
+                                    keys: [],
+                                    span: None,
+                                },
+                            },
+                        },
+                    },
+                ],
+            )
+        "#]]
+        .assert_debug_eq(&e);
+        let mut change = ConfigChange::default();
+
+        change.change_user_config(Some(
+            toml::toml! {
+                [cargo.cfgs]
+                these = "these"
+                should = "should"
+                be = "be"
+                valid = "valid"
+            }
+            .to_string()
+            .into(),
+        ));
+        let (_, e, _) = config.apply_change(change);
+        expect_test::expect![[r#"
+            ConfigErrors(
+                [
+                    Toml {
+                        config_key: "invalid/config/err",
+                        error: Error {
+                            inner: Error {
+                                inner: TomlError {
+                                    message: "unexpected field",
+                                    raw: None,
+                                    keys: [],
+                                    span: None,
+                                },
+                            },
+                        },
+                    },
+                ],
+            )
+        "#]]
+        .assert_debug_eq(&e);
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index 65a9a491493..b23e7b7e98c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -8,6 +8,7 @@ use ide_db::FxHashMap;
 use itertools::Itertools;
 use nohash_hasher::{IntMap, IntSet};
 use rustc_hash::FxHashSet;
+use stdx::iter_eq_by;
 use triomphe::Arc;
 
 use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext};
@@ -22,14 +23,21 @@ pub struct DiagnosticsMapConfig {
     pub check_ignore: FxHashSet<String>,
 }
 
+pub(crate) type DiagnosticsGeneration = usize;
+
 #[derive(Debug, Default, Clone)]
 pub(crate) struct DiagnosticCollection {
     // FIXME: should be IntMap<FileId, Vec<ra_id::Diagnostic>>
-    pub(crate) native: IntMap<FileId, Vec<lsp_types::Diagnostic>>,
+    pub(crate) native: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
     // FIXME: should be Vec<flycheck::Diagnostic>
     pub(crate) check: IntMap<usize, IntMap<FileId, Vec<lsp_types::Diagnostic>>>,
     pub(crate) check_fixes: CheckFixes,
     changes: IntSet<FileId>,
+    /// Counter for supplying a new generation number for diagnostics.
+    /// This is used to keep track of when to clear the diagnostics for a given file as we compute
+    /// diagnostics on multiple worker threads simultaneously which may result in multiple diagnostics
+    /// updates for the same file in a single generation update (due to macros affecting multiple files).
+    generation: DiagnosticsGeneration,
 }
 
 #[derive(Debug, Clone)]
@@ -82,21 +90,31 @@ impl DiagnosticCollection {
 
     pub(crate) fn set_native_diagnostics(
         &mut self,
+        generation: DiagnosticsGeneration,
         file_id: FileId,
-        diagnostics: Vec<lsp_types::Diagnostic>,
+        mut diagnostics: Vec<lsp_types::Diagnostic>,
     ) {
-        if let Some(existing_diagnostics) = self.native.get(&file_id) {
+        diagnostics.sort_by_key(|it| (it.range.start, it.range.end));
+        if let Some((old_gen, existing_diagnostics)) = self.native.get_mut(&file_id) {
             if existing_diagnostics.len() == diagnostics.len()
-                && diagnostics
-                    .iter()
-                    .zip(existing_diagnostics)
-                    .all(|(new, existing)| are_diagnostics_equal(new, existing))
+                && iter_eq_by(&diagnostics, &*existing_diagnostics, |new, existing| {
+                    are_diagnostics_equal(new, existing)
+                })
             {
+                // don't signal an update if the diagnostics are the same
                 return;
             }
+            if *old_gen < generation || generation == 0 {
+                self.native.insert(file_id, (generation, diagnostics));
+            } else {
+                existing_diagnostics.extend(diagnostics);
+                // FIXME: Doing the merge step of a merge sort here would be a bit more performant
+                // but eh
+                existing_diagnostics.sort_by_key(|it| (it.range.start, it.range.end))
+            }
+        } else {
+            self.native.insert(file_id, (generation, diagnostics));
         }
-
-        self.native.insert(file_id, diagnostics);
         self.changes.insert(file_id);
     }
 
@@ -104,7 +122,7 @@ impl DiagnosticCollection {
         &self,
         file_id: FileId,
     ) -> impl Iterator<Item = &lsp_types::Diagnostic> {
-        let native = self.native.get(&file_id).into_iter().flatten();
+        let native = self.native.get(&file_id).into_iter().flat_map(|(_, d)| d);
         let check = self.check.values().filter_map(move |it| it.get(&file_id)).flatten();
         native.chain(check)
     }
@@ -115,6 +133,11 @@ impl DiagnosticCollection {
         }
         Some(mem::take(&mut self.changes))
     }
+
+    pub(crate) fn next_generation(&mut self) -> usize {
+        self.generation += 1;
+        self.generation
+    }
 }
 
 fn are_diagnostics_equal(left: &lsp_types::Diagnostic, right: &lsp_types::Diagnostic) -> bool {
@@ -126,9 +149,10 @@ fn are_diagnostics_equal(left: &lsp_types::Diagnostic, right: &lsp_types::Diagno
 
 pub(crate) fn fetch_native_diagnostics(
     snapshot: GlobalStateSnapshot,
-    subscriptions: Vec<FileId>,
+    subscriptions: std::sync::Arc<[FileId]>,
+    slice: std::ops::Range<usize>,
 ) -> Vec<(FileId, Vec<lsp_types::Diagnostic>)> {
-    let _p = tracing::span!(tracing::Level::INFO, "fetch_native_diagnostics").entered();
+    let _p = tracing::info_span!("fetch_native_diagnostics").entered();
     let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());
 
     let convert_diagnostic =
@@ -149,12 +173,12 @@ pub(crate) fn fetch_native_diagnostics(
     // the diagnostics produced may point to different files not requested by the concrete request,
     // put those into here and filter later
     let mut odd_ones = Vec::new();
-    let mut diagnostics = subscriptions
+    let mut diagnostics = subscriptions[slice]
         .iter()
         .copied()
         .filter_map(|file_id| {
             let line_index = snapshot.file_line_index(file_id).ok()?;
-            let source_root = snapshot.analysis.source_root(file_id).ok()?;
+            let source_root = snapshot.analysis.source_root_id(file_id).ok()?;
 
             let diagnostics = snapshot
                 .analysis
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 3d3f9440199..4832e8cab43 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -547,6 +547,7 @@ mod tests {
                 ClientCapabilities::default(),
                 Vec::new(),
                 None,
+                None,
             ),
         );
         let snap = state.snapshot();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index cf3b8d331de..ebdc196a658 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -52,7 +52,8 @@ impl RequestDispatcher<'_> {
             Some(it) => it,
             None => return self,
         };
-        let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered();
+        let _guard =
+            tracing::info_span!("request", method = ?req.method, "request_id" = ?req.id).entered();
         tracing::debug!(?params);
         let result = {
             let _pctx = stdx::panic_context::enter(panic_context);
@@ -79,7 +80,8 @@ impl RequestDispatcher<'_> {
             Some(it) => it,
             None => return self,
         };
-        let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered();
+        let _guard =
+            tracing::info_span!("request", method = ?req.method, "request_id" = ?req.id).entered();
         tracing::debug!(?params);
         let global_state_snapshot = self.global_state.snapshot();
 
@@ -162,7 +164,8 @@ impl RequestDispatcher<'_> {
             Some(it) => it,
             None => return self,
         };
-        let _guard = tracing::span!(tracing::Level::INFO, "request", method = ?req.method, "request_id" = ?req.id).entered();
+        let _guard =
+            tracing::info_span!("request", method = ?req.method, "request_id" = ?req.id).entered();
         tracing::debug!(?params);
 
         let world = self.global_state.snapshot();
@@ -297,8 +300,7 @@ impl NotificationDispatcher<'_> {
             None => return Ok(self),
         };
 
-        let _guard =
-            tracing::span!(tracing::Level::INFO, "notification", method = ?not.method).entered();
+        let _guard = tracing::info_span!("notification", method = ?not.method).entered();
 
         let params = match not.extract::<N::Params>(N::METHOD) {
             Ok(it) => it,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index f64e66183d1..717d8a632c3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -3,13 +3,13 @@
 //!
 //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 
-use std::time::Instant;
+use std::{ops::Not as _, time::Instant};
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
-use ide_db::base_db::{CrateId, ProcMacroPaths};
+use ide_db::base_db::{CrateId, ProcMacroPaths, SourceDatabaseExt};
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
 use nohash_hasher::IntMap;
@@ -18,25 +18,26 @@ use parking_lot::{
     RwLockWriteGuard,
 };
 use proc_macro_api::ProcMacroServer;
-use project_model::{
-    CargoWorkspace, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, Target,
-    WorkspaceBuildScripts,
-};
+use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use rustc_hash::{FxHashMap, FxHashSet};
 use tracing::{span, Level};
 use triomphe::Arc;
-use vfs::{AnchoredPathBuf, Vfs};
+use vfs::{AnchoredPathBuf, ChangeKind, Vfs};
 
 use crate::{
-    config::{Config, ConfigError},
+    config::{Config, ConfigChange, ConfigErrors},
     diagnostics::{CheckFixes, DiagnosticCollection},
     line_index::{LineEndings, LineIndex},
-    lsp::{from_proto, to_proto::url_from_abs_path},
+    lsp::{
+        from_proto::{self},
+        to_proto::url_from_abs_path,
+    },
     lsp_ext,
     main_loop::Task,
     mem_docs::MemDocs,
     op_queue::OpQueue,
     reload,
+    target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec},
     task_pool::{TaskPool, TaskQueue},
 };
 
@@ -65,13 +66,13 @@ pub(crate) struct GlobalState {
     pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
 
     pub(crate) config: Arc<Config>,
-    pub(crate) config_errors: Option<ConfigError>,
+    pub(crate) config_errors: Option<ConfigErrors>,
     pub(crate) analysis_host: AnalysisHost,
     pub(crate) diagnostics: DiagnosticCollection,
     pub(crate) mem_docs: MemDocs,
     pub(crate) source_root_config: SourceRootConfig,
     /// A mapping that maps a local source root's `SourceRootId` to it parent's `SourceRootId`, if it has one.
-    pub(crate) local_roots_parent_map: FxHashMap<SourceRootId, SourceRootId>,
+    pub(crate) local_roots_parent_map: Arc<FxHashMap<SourceRootId, SourceRootId>>,
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 
     // status
@@ -160,7 +161,9 @@ pub(crate) struct GlobalStateSnapshot {
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
     vfs: Arc<RwLock<(vfs::Vfs, IntMap<FileId, LineEndings>)>>,
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
-    // used to signal semantic highlighting to fall back to syntax based highlighting until proc-macros have been loaded
+    // used to signal semantic highlighting to fall back to syntax based highlighting until
+    // proc-macros have been loaded
+    // FIXME: Can we derive this from somewhere else?
     pub(crate) proc_macros_loaded: bool,
     pub(crate) flycheck: Arc<[FlycheckHandle]>,
 }
@@ -213,7 +216,7 @@ impl GlobalState {
             shutdown_requested: false,
             last_reported_status: None,
             source_root_config: SourceRootConfig::default(),
-            local_roots_parent_map: FxHashMap::default(),
+            local_roots_parent_map: Arc::new(FxHashMap::default()),
             config_errors: Default::default(),
 
             proc_macro_clients: Arc::from_iter([]),
@@ -254,6 +257,14 @@ impl GlobalState {
 
     pub(crate) fn process_changes(&mut self) -> bool {
         let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
+
+        // We cannot directly resolve a change in a ratoml file to a format
+        // that can be used by the config module because config talks
+        // in `SourceRootId`s instead of `FileId`s and `FileId` -> `SourceRootId`
+        // mapping is not ready until `AnalysisHost::apply_changes` has been called.
+        let mut modified_ratoml_files: FxHashMap<FileId, (ChangeKind, vfs::VfsPath)> =
+            FxHashMap::default();
+
         let (change, modified_rust_files, workspace_structure_change) = {
             let mut change = ChangeWithProcMacros::new();
             let mut guard = self.vfs.write();
@@ -273,6 +284,11 @@ impl GlobalState {
             let mut modified_rust_files = vec![];
             for file in changed_files.into_values() {
                 let vfs_path = vfs.file_path(file.file_id);
+                if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
+                    // Remember ids to use them after `apply_changes`
+                    modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
+                }
+
                 if let Some(path) = vfs_path.as_path() {
                     has_structure_changes |= file.is_created_or_deleted();
 
@@ -310,12 +326,15 @@ impl GlobalState {
                 bytes.push((file.file_id, text));
             }
             let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
-            bytes.into_iter().for_each(|(file_id, text)| match text {
-                None => change.change_file(file_id, None),
-                Some((text, line_endings)) => {
-                    line_endings_map.insert(file_id, line_endings);
-                    change.change_file(file_id, Some(text));
-                }
+            bytes.into_iter().for_each(|(file_id, text)| {
+                let text = match text {
+                    None => None,
+                    Some((text, line_endings)) => {
+                        line_endings_map.insert(file_id, line_endings);
+                        Some(text)
+                    }
+                };
+                change.change_file(file_id, text);
             });
             if has_structure_changes {
                 let roots = self.source_root_config.partition(vfs);
@@ -326,6 +345,63 @@ impl GlobalState {
 
         let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
         self.analysis_host.apply_change(change);
+        if !modified_ratoml_files.is_empty()
+            || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
+        {
+            let config_change = {
+                let user_config_path = self.config.user_config_path();
+                let root_ratoml_path = self.config.root_ratoml_path();
+                let mut change = ConfigChange::default();
+                let db = self.analysis_host.raw_database();
+
+                for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
+                    if vfs_path == *user_config_path {
+                        change.change_user_config(Some(db.file_text(file_id)));
+                        continue;
+                    }
+
+                    if vfs_path == *root_ratoml_path {
+                        change.change_root_ratoml(Some(db.file_text(file_id)));
+                        continue;
+                    }
+
+                    // If change has been made to a ratoml file that
+                    // belongs to a non-local source root, we will ignore it.
+                    // As it doesn't make sense a users to use external config files.
+                    let sr_id = db.file_source_root(file_id);
+                    let sr = db.source_root(sr_id);
+                    if !sr.is_library {
+                        if let Some((old_path, old_text)) = change.change_ratoml(
+                            sr_id,
+                            vfs_path.clone(),
+                            Some(db.file_text(file_id)),
+                        ) {
+                            // SourceRoot has more than 1 RATOML files. In this case lexicographically smaller wins.
+                            if old_path < vfs_path {
+                                span!(Level::ERROR, "Two `rust-analyzer.toml` files were found inside the same crate. {vfs_path} has no effect.");
+                                // Put the old one back in.
+                                change.change_ratoml(sr_id, old_path, old_text);
+                            }
+                        }
+                    } else {
+                        // Mapping to a SourceRoot should always end up in `Ok`
+                        span!(Level::ERROR, "Mapping to SourceRootId failed.");
+                    }
+                }
+                change.change_source_root_parent_map(self.local_roots_parent_map.clone());
+                change
+            };
+
+            let (config, e, should_update) = self.config.apply_change(config_change);
+            self.config_errors = e.is_empty().not().then_some(e);
+
+            if should_update {
+                self.update_configuration(config);
+            } else {
+                // No global or client level config was changed. So we can just naively replace config.
+                self.config = Arc::new(config);
+            }
+        }
 
         {
             if !matches!(&workspace_structure_change, Some((.., true))) {
@@ -478,21 +554,52 @@ impl GlobalStateSnapshot {
         self.vfs_read().file_path(file_id).clone()
     }
 
-    pub(crate) fn cargo_target_for_crate_root(
-        &self,
-        crate_id: CrateId,
-    ) -> Option<(&CargoWorkspace, Target)> {
+    pub(crate) fn target_spec_for_crate(&self, crate_id: CrateId) -> Option<TargetSpec> {
         let file_id = self.analysis.crate_root(crate_id).ok()?;
         let path = self.vfs_read().file_path(file_id).clone();
         let path = path.as_path()?;
-        self.workspaces.iter().find_map(|ws| match &ws.kind {
-            ProjectWorkspaceKind::Cargo { cargo, .. }
-            | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
-                cargo.target_by_root(path).map(|it| (cargo, it))
-            }
-            ProjectWorkspaceKind::Json { .. } => None,
-            ProjectWorkspaceKind::DetachedFile { .. } => None,
-        })
+
+        for workspace in self.workspaces.iter() {
+            match &workspace.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. }
+                | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+                    let Some(target_idx) = cargo.target_by_root(path) else {
+                        continue;
+                    };
+
+                    let target_data = &cargo[target_idx];
+                    let package_data = &cargo[target_data.package];
+
+                    return Some(TargetSpec::Cargo(CargoTargetSpec {
+                        workspace_root: cargo.workspace_root().to_path_buf(),
+                        cargo_toml: package_data.manifest.clone(),
+                        crate_id,
+                        package: cargo.package_flag(package_data),
+                        target: target_data.name.clone(),
+                        target_kind: target_data.kind,
+                        required_features: target_data.required_features.clone(),
+                        features: package_data.features.keys().cloned().collect(),
+                    }));
+                }
+                ProjectWorkspaceKind::Json(project) => {
+                    let Some(krate) = project.crate_by_root(path) else {
+                        continue;
+                    };
+                    let Some(build) = krate.build else {
+                        continue;
+                    };
+
+                    return Some(TargetSpec::ProjectJson(ProjectJsonTargetSpec {
+                        label: build.label,
+                        target_kind: build.target_kind,
+                        shell_runnables: project.runnables().to_owned(),
+                    }));
+                }
+                ProjectWorkspaceKind::DetachedFile { .. } => {}
+            };
+        }
+
+        None
     }
 
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 9d30063ccc8..2dbc297ea6c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -1,7 +1,7 @@
 //! This module is responsible for implementing handlers for Language Server
 //! Protocol. This module specifically handles notifications.
 
-use std::ops::Deref;
+use std::ops::{Deref, Not as _};
 
 use itertools::Itertools;
 use lsp_types::{
@@ -13,7 +13,7 @@ use triomphe::Arc;
 use vfs::{AbsPathBuf, ChangeKind, VfsPath};
 
 use crate::{
-    config::Config,
+    config::{Config, ConfigChange},
     global_state::GlobalState,
     lsp::{from_proto, utils::apply_document_changes},
     lsp_ext::{self, RunFlycheckParams},
@@ -54,7 +54,7 @@ pub(crate) fn handle_did_open_text_document(
     state: &mut GlobalState,
     params: DidOpenTextDocumentParams,
 ) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_did_open_text_document").entered();
+    let _p = tracing::info_span!("handle_did_open_text_document").entered();
 
     if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
         let already_exists = state
@@ -71,6 +71,7 @@ pub(crate) fn handle_did_open_text_document(
             tracing::error!("duplicate DidOpenTextDocument: {}", path);
         }
 
+        tracing::info!("New file content set {:?}", params.text_document.text);
         state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes()));
         if state.config.notifications().unindexed_project {
             tracing::debug!("queuing task");
@@ -87,7 +88,7 @@ pub(crate) fn handle_did_change_text_document(
     state: &mut GlobalState,
     params: DidChangeTextDocumentParams,
 ) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_did_change_text_document").entered();
+    let _p = tracing::info_span!("handle_did_change_text_document").entered();
 
     if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
         let Some(DocumentData { version, data }) = state.mem_docs.get_mut(&path) else {
@@ -116,7 +117,7 @@ pub(crate) fn handle_did_close_text_document(
     state: &mut GlobalState,
     params: DidCloseTextDocumentParams,
 ) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_did_close_text_document").entered();
+    let _p = tracing::info_span!("handle_did_close_text_document").entered();
 
     if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
         if state.mem_docs.remove(&path).is_err() {
@@ -196,10 +197,14 @@ pub(crate) fn handle_did_change_configuration(
                 }
                 (None, Some(mut configs)) => {
                     if let Some(json) = configs.get_mut(0) {
-                        // Note that json can be null according to the spec if the client can't
-                        // provide a configuration. This is handled in Config::update below.
-                        let mut config = Config::clone(&*this.config);
-                        this.config_errors = config.update(json.take()).err();
+                        let config = Config::clone(&*this.config);
+                        let mut change = ConfigChange::default();
+                        change.change_client_config(json.take());
+
+                        let (config, e, _) = config.apply_change(change);
+                        this.config_errors = e.is_empty().not().then_some(e);
+
+                        // Client config changes neccesitates .update_config method to be called.
                         this.update_configuration(config);
                     }
                 }
@@ -254,7 +259,7 @@ pub(crate) fn handle_did_change_watched_files(
 }
 
 fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
-    let _p = tracing::span!(tracing::Level::INFO, "run_flycheck").entered();
+    let _p = tracing::info_span!("run_flycheck").entered();
 
     let file_id = state.vfs.read().0.file_id(&vfs_path);
     if let Some(file_id) = file_id {
@@ -349,13 +354,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
 }
 
 pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_cancel_flycheck").entered();
+    let _p = tracing::info_span!("handle_cancel_flycheck").entered();
     state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
     Ok(())
 }
 
 pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_clear_flycheck").entered();
+    let _p = tracing::info_span!("handle_clear_flycheck").entered();
     state.diagnostics.clear_check_all();
     Ok(())
 }
@@ -364,7 +369,7 @@ pub(crate) fn handle_run_flycheck(
     state: &mut GlobalState,
     params: RunFlycheckParams,
 ) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_run_flycheck").entered();
+    let _p = tracing::info_span!("handle_run_flycheck").entered();
     if let Some(text_document) = params.text_document {
         if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) {
             if run_flycheck(state, vfs_path) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 1e24bf3aae3..8e39b15da3d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -35,13 +35,13 @@ use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
-    cargo_target_spec::CargoTargetSpec,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diff::diff,
     global_state::{GlobalState, GlobalStateSnapshot},
     hack_recover_crate_name,
     line_index::LineEndings,
     lsp::{
+        ext::InternalTestingFetchConfigParams,
         from_proto, to_proto,
         utils::{all_edits_are_disjoint, invalid_params_error},
         LspError,
@@ -50,6 +50,7 @@ use crate::{
         self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
         FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
     },
+    target_spec::TargetSpec,
 };
 
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -72,7 +73,7 @@ pub(crate) fn handle_analyzer_status(
     snap: GlobalStateSnapshot,
     params: lsp_ext::AnalyzerStatusParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_analyzer_status").entered();
+    let _p = tracing::info_span!("handle_analyzer_status").entered();
 
     let mut buf = String::new();
 
@@ -113,7 +114,7 @@ pub(crate) fn handle_analyzer_status(
 }
 
 pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_memory_usage").entered();
+    let _p = tracing::info_span!("handle_memory_usage").entered();
     let mem = state.analysis_host.per_query_memory_usage();
 
     let mut out = String::new();
@@ -134,7 +135,7 @@ pub(crate) fn handle_syntax_tree(
     snap: GlobalStateSnapshot,
     params: lsp_ext::SyntaxTreeParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_syntax_tree").entered();
+    let _p = tracing::info_span!("handle_syntax_tree").entered();
     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());
@@ -146,7 +147,7 @@ pub(crate) fn handle_view_hir(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_view_hir").entered();
+    let _p = tracing::info_span!("handle_view_hir").entered();
     let position = from_proto::file_position(&snap, params)?;
     let res = snap.analysis.view_hir(position)?;
     Ok(res)
@@ -156,7 +157,7 @@ pub(crate) fn handle_view_mir(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_view_mir").entered();
+    let _p = tracing::info_span!("handle_view_mir").entered();
     let position = from_proto::file_position(&snap, params)?;
     let res = snap.analysis.view_mir(position)?;
     Ok(res)
@@ -166,7 +167,7 @@ pub(crate) fn handle_interpret_function(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_interpret_function").entered();
+    let _p = tracing::info_span!("handle_interpret_function").entered();
     let position = from_proto::file_position(&snap, params)?;
     let res = snap.analysis.interpret_function(position)?;
     Ok(res)
@@ -184,7 +185,7 @@ pub(crate) fn handle_view_item_tree(
     snap: GlobalStateSnapshot,
     params: lsp_ext::ViewItemTreeParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_view_item_tree").entered();
+    let _p = tracing::info_span!("handle_view_item_tree").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let res = snap.analysis.view_item_tree(file_id)?;
     Ok(res)
@@ -245,7 +246,7 @@ pub(crate) fn handle_discover_test(
     snap: GlobalStateSnapshot,
     params: lsp_ext::DiscoverTestParams,
 ) -> anyhow::Result<lsp_ext::DiscoverTestResults> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_discover_test").entered();
+    let _p = tracing::info_span!("handle_discover_test").entered();
     let (tests, scope) = match params.test_id {
         Some(id) => {
             let crate_id = id.split_once("::").map(|it| it.0).unwrap_or(&id);
@@ -276,7 +277,7 @@ pub(crate) fn handle_view_crate_graph(
     snap: GlobalStateSnapshot,
     params: ViewCrateGraphParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_view_crate_graph").entered();
+    let _p = tracing::info_span!("handle_view_crate_graph").entered();
     let dot = snap.analysis.view_crate_graph(params.full)?.map_err(anyhow::Error::msg)?;
     Ok(dot)
 }
@@ -285,7 +286,7 @@ pub(crate) fn handle_expand_macro(
     snap: GlobalStateSnapshot,
     params: lsp_ext::ExpandMacroParams,
 ) -> anyhow::Result<Option<lsp_ext::ExpandedMacro>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_expand_macro").entered();
+    let _p = tracing::info_span!("handle_expand_macro").entered();
     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)?;
@@ -298,7 +299,7 @@ pub(crate) fn handle_selection_range(
     snap: GlobalStateSnapshot,
     params: lsp_types::SelectionRangeParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::SelectionRange>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_selection_range").entered();
+    let _p = tracing::info_span!("handle_selection_range").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     let res: anyhow::Result<Vec<lsp_types::SelectionRange>> = params
@@ -341,7 +342,7 @@ pub(crate) fn handle_matching_brace(
     snap: GlobalStateSnapshot,
     params: lsp_ext::MatchingBraceParams,
 ) -> anyhow::Result<Vec<Position>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_matching_brace").entered();
+    let _p = tracing::info_span!("handle_matching_brace").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     params
@@ -364,11 +365,10 @@ pub(crate) fn handle_join_lines(
     snap: GlobalStateSnapshot,
     params: lsp_ext::JoinLinesParams,
 ) -> anyhow::Result<Vec<lsp_types::TextEdit>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_join_lines").entered();
+    let _p = tracing::info_span!("handle_join_lines").entered();
 
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let source_root = snap.analysis.source_root(file_id)?;
-    let config = snap.config.join_lines(Some(source_root));
+    let config = snap.config.join_lines();
     let line_index = snap.file_line_index(file_id)?;
 
     let mut res = TextEdit::default();
@@ -390,7 +390,7 @@ pub(crate) fn handle_on_enter(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_on_enter").entered();
+    let _p = tracing::info_span!("handle_on_enter").entered();
     let position = from_proto::file_position(&snap, params)?;
     let edit = match snap.analysis.on_enter(position)? {
         None => return Ok(None),
@@ -405,7 +405,7 @@ pub(crate) fn handle_on_type_formatting(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentOnTypeFormattingParams,
 ) -> anyhow::Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_on_type_formatting").entered();
+    let _p = tracing::info_span!("handle_on_type_formatting").entered();
     let mut position = from_proto::file_position(&snap, params.text_document_position)?;
     let line_index = snap.file_line_index(position.file_id)?;
 
@@ -446,7 +446,7 @@ pub(crate) fn handle_document_symbol(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentSymbolParams,
 ) -> anyhow::Result<Option<lsp_types::DocumentSymbolResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_document_symbol").entered();
+    let _p = tracing::info_span!("handle_document_symbol").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
 
@@ -535,7 +535,7 @@ pub(crate) fn handle_workspace_symbol(
     snap: GlobalStateSnapshot,
     params: WorkspaceSymbolParams,
 ) -> anyhow::Result<Option<lsp_types::WorkspaceSymbolResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_workspace_symbol").entered();
+    let _p = tracing::info_span!("handle_workspace_symbol").entered();
 
     let config = snap.config.workspace_symbol();
     let (all_symbols, libs) = decide_search_scope_and_kind(&params, &config);
@@ -627,7 +627,7 @@ pub(crate) fn handle_will_rename_files(
     snap: GlobalStateSnapshot,
     params: lsp_types::RenameFilesParams,
 ) -> anyhow::Result<Option<lsp_types::WorkspaceEdit>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_will_rename_files").entered();
+    let _p = tracing::info_span!("handle_will_rename_files").entered();
 
     let source_changes: Vec<SourceChange> = params
         .files
@@ -689,7 +689,7 @@ pub(crate) fn handle_goto_definition(
     snap: GlobalStateSnapshot,
     params: lsp_types::GotoDefinitionParams,
 ) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_goto_definition").entered();
+    let _p = tracing::info_span!("handle_goto_definition").entered();
     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),
@@ -704,7 +704,7 @@ pub(crate) fn handle_goto_declaration(
     snap: GlobalStateSnapshot,
     params: lsp_types::request::GotoDeclarationParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoDeclarationResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_goto_declaration").entered();
+    let _p = tracing::info_span!("handle_goto_declaration").entered();
     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),
@@ -719,7 +719,7 @@ pub(crate) fn handle_goto_implementation(
     snap: GlobalStateSnapshot,
     params: lsp_types::request::GotoImplementationParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoImplementationResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_goto_implementation").entered();
+    let _p = tracing::info_span!("handle_goto_implementation").entered();
     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),
@@ -734,7 +734,7 @@ pub(crate) fn handle_goto_type_definition(
     snap: GlobalStateSnapshot,
     params: lsp_types::request::GotoTypeDefinitionParams,
 ) -> anyhow::Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_goto_type_definition").entered();
+    let _p = tracing::info_span!("handle_goto_type_definition").entered();
     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),
@@ -749,7 +749,7 @@ pub(crate) fn handle_parent_module(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_parent_module").entered();
+    let _p = tracing::info_span!("handle_parent_module").entered();
     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
@@ -790,9 +790,9 @@ pub(crate) fn handle_parent_module(
             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),
+        let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
+            Some(TargetSpec::Cargo(it)) => it,
+            Some(TargetSpec::ProjectJson(_)) | None => return Ok(None),
         };
 
         if snap.analysis.crate_root(crate_id)? == file_id {
@@ -819,11 +819,11 @@ pub(crate) fn handle_runnables(
     snap: GlobalStateSnapshot,
     params: lsp_ext::RunnablesParams,
 ) -> anyhow::Result<Vec<lsp_ext::Runnable>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_runnables").entered();
+    let _p = tracing::info_span!("handle_runnables").entered();
     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 target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let expect_test = match offset {
         Some(offset) => {
@@ -840,21 +840,24 @@ pub(crate) fn handle_runnables(
         if should_skip_for_offset(&runnable, offset) {
             continue;
         }
-        if should_skip_target(&runnable, cargo_spec.as_ref()) {
+        if should_skip_target(&runnable, target_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);
+        if let Some(mut runnable) = to_proto::runnable(&snap, runnable)? {
+            if expect_test {
+                if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args {
+                    runnable.label = format!("{} + expect", runnable.label);
+                    r.expect_test = Some(true);
+                }
+            }
+            res.push(runnable);
         }
-        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) => {
+    match target_spec {
+        Some(TargetSpec::Cargo(spec)) => {
             let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?;
             for cmd in ["check", "run", "test"] {
                 if cmd == "run" && spec.target_kind != TargetKind::Bin {
@@ -879,7 +882,7 @@ pub(crate) fn handle_runnables(
                     ),
                     location: None,
                     kind: lsp_ext::RunnableKind::Cargo,
-                    args: lsp_ext::CargoRunnable {
+                    args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
                         workspace_root: Some(spec.workspace_root.clone().into()),
                         cwd: Some(cwd.into()),
                         override_cargo: config.override_cargo.clone(),
@@ -887,17 +890,18 @@ pub(crate) fn handle_runnables(
                         cargo_extra_args: config.cargo_extra_args.clone(),
                         executable_args: Vec::new(),
                         expect_test: None,
-                    },
+                    }),
                 })
             }
         }
+        Some(TargetSpec::ProjectJson(_)) => {}
         None => {
             if !snap.config.linked_or_discovered_projects().is_empty() {
                 res.push(lsp_ext::Runnable {
                     label: "cargo check --workspace".to_owned(),
                     location: None,
                     kind: lsp_ext::RunnableKind::Cargo,
-                    args: lsp_ext::CargoRunnable {
+                    args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
                         workspace_root: None,
                         cwd: None,
                         override_cargo: config.override_cargo,
@@ -905,7 +909,7 @@ pub(crate) fn handle_runnables(
                         cargo_extra_args: config.cargo_extra_args,
                         executable_args: Vec::new(),
                         expect_test: None,
-                    },
+                    }),
                 });
             }
         }
@@ -925,13 +929,13 @@ pub(crate) fn handle_related_tests(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Vec<lsp_ext::TestInfo>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_related_tests").entered();
+    let _p = tracing::info_span!("handle_related_tests").entered();
     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) {
+        if let Ok(Some(runnable)) = to_proto::runnable(&snap, it) {
             res.push(lsp_ext::TestInfo { runnable })
         }
     }
@@ -943,13 +947,13 @@ pub(crate) fn handle_completion(
     snap: GlobalStateSnapshot,
     lsp_types::CompletionParams { text_document_position, context,.. }: lsp_types::CompletionParams,
 ) -> anyhow::Result<Option<lsp_types::CompletionResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_completion").entered();
+    let _p = tracing::info_span!("handle_completion").entered();
     let mut position = from_proto::file_position(&snap, text_document_position.clone())?;
     let line_index = snap.file_line_index(position.file_id)?;
     let completion_trigger_character =
         context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
-    let source_root = snap.analysis.source_root(position.file_id)?;
+    let source_root = snap.analysis.source_root_id(position.file_id)?;
     let completion_config = &snap.config.completion(Some(source_root));
     // FIXME: We should fix up the position when retrying the cancelled request instead
     position.offset = position.offset.min(line_index.index.len());
@@ -978,7 +982,7 @@ pub(crate) fn handle_completion_resolve(
     snap: GlobalStateSnapshot,
     mut original_completion: CompletionItem,
 ) -> anyhow::Result<CompletionItem> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_completion_resolve").entered();
+    let _p = tracing::info_span!("handle_completion_resolve").entered();
 
     if !all_edits_are_disjoint(&original_completion, &[]) {
         return Err(invalid_params_error(
@@ -997,7 +1001,7 @@ pub(crate) fn handle_completion_resolve(
     let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else {
         return Ok(original_completion);
     };
-    let source_root = snap.analysis.source_root(file_id)?;
+    let source_root = snap.analysis.source_root_id(file_id)?;
 
     let additional_edits = snap
         .analysis
@@ -1035,7 +1039,7 @@ pub(crate) fn handle_folding_range(
     snap: GlobalStateSnapshot,
     params: FoldingRangeParams,
 ) -> anyhow::Result<Option<Vec<FoldingRange>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_folding_range").entered();
+    let _p = tracing::info_span!("handle_folding_range").entered();
     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)?;
@@ -1052,7 +1056,7 @@ pub(crate) fn handle_signature_help(
     snap: GlobalStateSnapshot,
     params: lsp_types::SignatureHelpParams,
 ) -> anyhow::Result<Option<lsp_types::SignatureHelp>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_signature_help").entered();
+    let _p = tracing::info_span!("handle_signature_help").entered();
     let position = from_proto::file_position(&snap, params.text_document_position_params)?;
     let help = match snap.analysis.signature_help(position)? {
         Some(it) => it,
@@ -1067,7 +1071,7 @@ pub(crate) fn handle_hover(
     snap: GlobalStateSnapshot,
     params: lsp_ext::HoverParams,
 ) -> anyhow::Result<Option<lsp_ext::Hover>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_hover").entered();
+    let _p = tracing::info_span!("handle_hover").entered();
     let range = match params.position {
         PositionOrRange::Position(position) => Range::new(position, position),
         PositionOrRange::Range(range) => range,
@@ -1105,7 +1109,7 @@ pub(crate) fn handle_prepare_rename(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<PrepareRenameResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_prepare_rename").entered();
+    let _p = tracing::info_span!("handle_prepare_rename").entered();
     let position = from_proto::file_position(&snap, params)?;
 
     let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
@@ -1119,7 +1123,7 @@ pub(crate) fn handle_rename(
     snap: GlobalStateSnapshot,
     params: RenameParams,
 ) -> anyhow::Result<Option<WorkspaceEdit>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_rename").entered();
+    let _p = tracing::info_span!("handle_rename").entered();
     let position = from_proto::file_position(&snap, params.text_document_position)?;
 
     let mut change =
@@ -1154,7 +1158,7 @@ pub(crate) fn handle_references(
     snap: GlobalStateSnapshot,
     params: lsp_types::ReferenceParams,
 ) -> anyhow::Result<Option<Vec<Location>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_references").entered();
+    let _p = tracing::info_span!("handle_references").entered();
     let position = from_proto::file_position(&snap, params.text_document_position)?;
 
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
@@ -1199,7 +1203,7 @@ pub(crate) fn handle_formatting(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentFormattingParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::TextEdit>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_formatting").entered();
+    let _p = tracing::info_span!("handle_formatting").entered();
 
     run_rustfmt(&snap, params.text_document, None)
 }
@@ -1208,7 +1212,7 @@ pub(crate) fn handle_range_formatting(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentRangeFormattingParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::TextEdit>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_range_formatting").entered();
+    let _p = tracing::info_span!("handle_range_formatting").entered();
 
     run_rustfmt(&snap, params.text_document, Some(params.range))
 }
@@ -1217,7 +1221,7 @@ pub(crate) fn handle_code_action(
     snap: GlobalStateSnapshot,
     params: lsp_types::CodeActionParams,
 ) -> anyhow::Result<Option<Vec<lsp_ext::CodeAction>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_code_action").entered();
+    let _p = tracing::info_span!("handle_code_action").entered();
 
     if !snap.config.code_action_literals() {
         // We intentionally don't support command-based actions, as those either
@@ -1229,7 +1233,7 @@ pub(crate) fn handle_code_action(
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
-    let source_root = snap.analysis.source_root(file_id)?;
+    let source_root = snap.analysis.source_root_id(file_id)?;
 
     let mut assists_config = snap.config.assist(Some(source_root));
     assists_config.allowed = params
@@ -1295,7 +1299,7 @@ pub(crate) fn handle_code_action_resolve(
     snap: GlobalStateSnapshot,
     mut code_action: lsp_ext::CodeAction,
 ) -> anyhow::Result<lsp_ext::CodeAction> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_code_action_resolve").entered();
+    let _p = tracing::info_span!("handle_code_action_resolve").entered();
     let Some(params) = code_action.data.take() else {
         return Err(invalid_params_error("code action without data".to_owned()).into());
     };
@@ -1307,7 +1311,7 @@ pub(crate) fn handle_code_action_resolve(
     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 source_root = snap.analysis.source_root(file_id)?;
+    let source_root = snap.analysis.source_root_id(file_id)?;
 
     let mut assists_config = snap.config.assist(Some(source_root));
     assists_config.allowed = params
@@ -1388,7 +1392,7 @@ pub(crate) fn handle_code_lens(
     snap: GlobalStateSnapshot,
     params: lsp_types::CodeLensParams,
 ) -> anyhow::Result<Option<Vec<CodeLens>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_code_lens").entered();
+    let _p = tracing::info_span!("handle_code_lens").entered();
 
     let lens_config = snap.config.lens();
     if lens_config.none() {
@@ -1397,14 +1401,14 @@ pub(crate) fn handle_code_lens(
     }
 
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
+    let target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
         &AnnotationConfig {
-            binary_target: cargo_target_spec
+            binary_target: target_spec
                 .map(|spec| {
                     matches!(
-                        spec.target_kind,
+                        spec.target_kind(),
                         TargetKind::Bin | TargetKind::Example | TargetKind::Test
                     )
                 })
@@ -1457,10 +1461,10 @@ pub(crate) fn handle_document_highlight(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentHighlightParams,
 ) -> anyhow::Result<Option<Vec<lsp_types::DocumentHighlight>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_document_highlight").entered();
+    let _p = tracing::info_span!("handle_document_highlight").entered();
     let position = from_proto::file_position(&snap, params.text_document_position_params)?;
     let line_index = snap.file_line_index(position.file_id)?;
-    let source_root = snap.analysis.source_root(position.file_id)?;
+    let source_root = snap.analysis.source_root_id(position.file_id)?;
 
     let refs = match snap
         .analysis
@@ -1483,7 +1487,7 @@ pub(crate) fn handle_ssr(
     snap: GlobalStateSnapshot,
     params: lsp_ext::SsrParams,
 ) -> anyhow::Result<lsp_types::WorkspaceEdit> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_ssr").entered();
+    let _p = tracing::info_span!("handle_ssr").entered();
     let selections = params
         .selections
         .iter()
@@ -1503,7 +1507,7 @@ pub(crate) fn handle_inlay_hints(
     snap: GlobalStateSnapshot,
     params: InlayHintParams,
 ) -> anyhow::Result<Option<Vec<InlayHint>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_inlay_hints").entered();
+    let _p = tracing::info_span!("handle_inlay_hints").entered();
     let document_uri = &params.text_document.uri;
     let FileRange { file_id, range } = from_proto::file_range(
         &snap,
@@ -1511,13 +1515,12 @@ pub(crate) fn handle_inlay_hints(
         params.range,
     )?;
     let line_index = snap.file_line_index(file_id)?;
-    let source_root = snap.analysis.source_root(file_id)?;
     let range = TextRange::new(
         range.start().min(line_index.index.len()),
         range.end().min(line_index.index.len()),
     );
 
-    let inlay_hints_config = snap.config.inlay_hints(Some(source_root));
+    let inlay_hints_config = snap.config.inlay_hints();
     Ok(Some(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1539,7 +1542,7 @@ pub(crate) fn handle_inlay_hints_resolve(
     snap: GlobalStateSnapshot,
     mut original_hint: InlayHint,
 ) -> anyhow::Result<InlayHint> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_inlay_hints_resolve").entered();
+    let _p = tracing::info_span!("handle_inlay_hints_resolve").entered();
 
     let Some(data) = original_hint.data.take() else { return Ok(original_hint) };
     let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
@@ -1553,9 +1556,8 @@ pub(crate) fn handle_inlay_hints_resolve(
 
     let line_index = snap.file_line_index(file_id)?;
     let hint_position = from_proto::offset(&line_index, original_hint.position)?;
-    let source_root = snap.analysis.source_root(file_id)?;
 
-    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(Some(source_root));
+    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
     forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
     let resolve_hints = snap.analysis.inlay_hints_resolve(
         &forced_resolve_inlay_hints_config,
@@ -1590,7 +1592,7 @@ pub(crate) fn handle_call_hierarchy_prepare(
     snap: GlobalStateSnapshot,
     params: CallHierarchyPrepareParams,
 ) -> anyhow::Result<Option<Vec<CallHierarchyItem>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_prepare").entered();
+    let _p = tracing::info_span!("handle_call_hierarchy_prepare").entered();
     let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 
     let nav_info = match snap.analysis.call_hierarchy(position)? {
@@ -1612,7 +1614,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
     snap: GlobalStateSnapshot,
     params: CallHierarchyIncomingCallsParams,
 ) -> anyhow::Result<Option<Vec<CallHierarchyIncomingCall>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_incoming").entered();
+    let _p = tracing::info_span!("handle_call_hierarchy_incoming").entered();
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
@@ -1647,7 +1649,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     snap: GlobalStateSnapshot,
     params: CallHierarchyOutgoingCallsParams,
 ) -> anyhow::Result<Option<Vec<CallHierarchyOutgoingCall>>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_call_hierarchy_outgoing").entered();
+    let _p = tracing::info_span!("handle_call_hierarchy_outgoing").entered();
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
@@ -1682,14 +1684,13 @@ pub(crate) fn handle_semantic_tokens_full(
     snap: GlobalStateSnapshot,
     params: SemanticTokensParams,
 ) -> anyhow::Result<Option<SemanticTokensResult>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_full").entered();
+    let _p = tracing::info_span!("handle_semantic_tokens_full").entered();
 
     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 source_root = snap.analysis.source_root(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config(Some(source_root));
+    let mut highlight_config = snap.config.highlighting_config();
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1700,7 +1701,7 @@ pub(crate) fn handle_semantic_tokens_full(
         &line_index,
         highlights,
         snap.config.semantics_tokens_augments_syntax_tokens(),
-        snap.config.highlighting_non_standard_tokens(Some(source_root)),
+        snap.config.highlighting_non_standard_tokens(),
     );
 
     // Unconditionally cache the tokens
@@ -1713,14 +1714,13 @@ pub(crate) fn handle_semantic_tokens_full_delta(
     snap: GlobalStateSnapshot,
     params: SemanticTokensDeltaParams,
 ) -> anyhow::Result<Option<SemanticTokensFullDeltaResult>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_full_delta").entered();
+    let _p = tracing::info_span!("handle_semantic_tokens_full_delta").entered();
 
     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 source_root = snap.analysis.source_root(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config(Some(source_root));
+    let mut highlight_config = snap.config.highlighting_config();
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1731,7 +1731,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
         &line_index,
         highlights,
         snap.config.semantics_tokens_augments_syntax_tokens(),
-        snap.config.highlighting_non_standard_tokens(Some(source_root)),
+        snap.config.highlighting_non_standard_tokens(),
     );
 
     let cached_tokens = snap.semantic_tokens_cache.lock().remove(&params.text_document.uri);
@@ -1757,14 +1757,13 @@ pub(crate) fn handle_semantic_tokens_range(
     snap: GlobalStateSnapshot,
     params: SemanticTokensRangeParams,
 ) -> anyhow::Result<Option<SemanticTokensRangeResult>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_semantic_tokens_range").entered();
+    let _p = tracing::info_span!("handle_semantic_tokens_range").entered();
 
     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 source_root = snap.analysis.source_root(frange.file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config(Some(source_root));
+    let mut highlight_config = snap.config.highlighting_config();
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1775,7 +1774,7 @@ pub(crate) fn handle_semantic_tokens_range(
         &line_index,
         highlights,
         snap.config.semantics_tokens_augments_syntax_tokens(),
-        snap.config.highlighting_non_standard_tokens(Some(source_root)),
+        snap.config.highlighting_non_standard_tokens(),
     );
     Ok(Some(semantic_tokens.into()))
 }
@@ -1784,7 +1783,7 @@ pub(crate) fn handle_open_docs(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<ExternalDocsResponse> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_open_docs").entered();
+    let _p = tracing::info_span!("handle_open_docs").entered();
     let position = from_proto::file_position(&snap, params)?;
 
     let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind {
@@ -1826,12 +1825,12 @@ pub(crate) fn handle_open_cargo_toml(
     snap: GlobalStateSnapshot,
     params: lsp_ext::OpenCargoTomlParams,
 ) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_open_cargo_toml").entered();
+    let _p = tracing::info_span!("handle_open_cargo_toml").entered();
     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_spec = match TargetSpec::for_file(&snap, file_id)? {
+        Some(TargetSpec::Cargo(it)) => it,
+        Some(TargetSpec::ProjectJson(_)) | None => return Ok(None),
     };
 
     let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
@@ -1844,7 +1843,7 @@ pub(crate) fn handle_move_item(
     snap: GlobalStateSnapshot,
     params: lsp_ext::MoveItemParams,
 ) -> anyhow::Result<Vec<lsp_ext::SnippetTextEdit>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_move_item").entered();
+    let _p = tracing::info_span!("handle_move_item").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let range = from_proto::file_range(&snap, &params.text_document, params.range)?;
 
@@ -1866,7 +1865,7 @@ pub(crate) fn handle_view_recursive_memory_layout(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<lsp_ext::RecursiveMemoryLayout>> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_view_recursive_memory_layout").entered();
+    let _p = tracing::info_span!("handle_view_recursive_memory_layout").entered();
     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)?;
@@ -1959,8 +1958,8 @@ fn runnable_action_links(
         return None;
     }
 
-    let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
-    if should_skip_target(&runnable, cargo_spec.as_ref()) {
+    let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
+    if should_skip_target(&runnable, target_spec.as_ref()) {
         return None;
     }
 
@@ -1970,7 +1969,7 @@ fn runnable_action_links(
     }
 
     let title = runnable.title();
-    let r = to_proto::runnable(snap, runnable).ok()?;
+    let r = to_proto::runnable(snap, runnable).ok()??;
 
     let mut group = lsp_ext::CommandLinkGroup::default();
 
@@ -1991,8 +1990,8 @@ fn goto_type_action_links(
     snap: &GlobalStateSnapshot,
     nav_targets: &[HoverGotoTypeData],
 ) -> Option<lsp_ext::CommandLinkGroup> {
-    if nav_targets.is_empty()
-        || !snap.config.hover_actions().goto_type_def
+    if !snap.config.hover_actions().goto_type_def
+        || nav_targets.is_empty()
         || !snap.config.client_commands().goto_location
     {
         return None;
@@ -2025,13 +2024,13 @@ fn prepare_hover_actions(
         .collect()
 }
 
-fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
+fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&TargetSpec>) -> 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,
+                    spec.target_kind(),
                     TargetKind::Bin | TargetKind::Example | TargetKind::Test
                 ),
                 None => true,
@@ -2108,9 +2107,9 @@ fn run_rustfmt(
         }
         RustfmtConfig::CustomCommand { command, args } => {
             let cmd = Utf8PathBuf::from(&command);
-            let workspace = CargoTargetSpec::for_file(snap, file_id)?;
-            let mut cmd = match workspace {
-                Some(spec) => {
+            let target_spec = TargetSpec::for_file(snap, file_id)?;
+            let mut cmd = match target_spec {
+                Some(TargetSpec::Cargo(spec)) => {
                     // approach: if the command name contains a path separator, join it with the workspace root.
                     // however, if the path is absolute, joining will result in the absolute path being preserved.
                     // as a fallback, rely on $PATH-based discovery.
@@ -2123,7 +2122,7 @@ fn run_rustfmt(
                     };
                     process::Command::new(cmd_path)
                 }
-                None => process::Command::new(cmd),
+                _ => process::Command::new(cmd),
             };
 
             cmd.envs(snap.config.extra_env());
@@ -2237,6 +2236,30 @@ pub(crate) fn fetch_dependency_list(
     Ok(FetchDependencyListResult { crates: crate_infos })
 }
 
+pub(crate) fn internal_testing_fetch_config(
+    state: GlobalStateSnapshot,
+    params: InternalTestingFetchConfigParams,
+) -> anyhow::Result<serde_json::Value> {
+    let source_root = params
+        .text_document
+        .map(|it| {
+            state
+                .analysis
+                .source_root_id(from_proto::file_id(&state, &it.uri)?)
+                .map_err(anyhow::Error::from)
+        })
+        .transpose()?;
+    serde_json::to_value(match &*params.config {
+        "local" => state.config.assist(source_root).assist_emit_must_use,
+        "global" => matches!(
+            state.config.rustfmt(),
+            RustfmtConfig::Rustfmt { enable_range_formatting: true, .. }
+        ),
+        _ => return Err(anyhow::anyhow!("Unknown test config key: {}", params.config)),
+    })
+    .map_err(Into::into)
+}
+
 /// Searches for the directory of a Rust crate given this crate's root file path.
 ///
 /// # Arguments
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 5d617780b6d..1e2cd4339b3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -74,7 +74,7 @@ fn integrated_highlighting_benchmark() {
         host.apply_change(change);
     }
 
-    let _g = crate::tracing::hprof::init("*>20");
+    let _g = crate::tracing::hprof::init("*>10");
 
     {
         let _it = stdx::timeit("after change");
@@ -160,7 +160,7 @@ fn integrated_completion_benchmark() {
         analysis.completions(&config, position, None).unwrap();
     }
 
-    let _g = crate::tracing::hprof::init("*");
+    let _g = crate::tracing::hprof::init("*>10");
 
     let completion_offset = {
         let _it = stdx::timeit("change");
@@ -175,7 +175,7 @@ fn integrated_completion_benchmark() {
     };
 
     {
-        let _p = tracing::span!(tracing::Level::INFO, "unqualified path completion").entered();
+        let _p = tracing::info_span!("unqualified path completion").entered();
         let _span = profile::cpu_span();
         let analysis = host.analysis();
         let config = CompletionConfig {
@@ -218,7 +218,7 @@ fn integrated_completion_benchmark() {
     };
 
     {
-        let _p = tracing::span!(tracing::Level::INFO, "dot completion").entered();
+        let _p = tracing::info_span!("dot completion").entered();
         let _span = profile::cpu_span();
         let analysis = host.analysis();
         let config = CompletionConfig {
@@ -289,6 +289,7 @@ fn integrated_diagnostics_benchmark() {
         disabled: Default::default(),
         expr_fill_default: Default::default(),
         style_lints: false,
+        snippet_cap: SnippetCap::new(true),
         insert_use: InsertUseConfig {
             granularity: ImportGranularity::Crate,
             enforce_granularity: false,
@@ -316,7 +317,7 @@ fn integrated_diagnostics_benchmark() {
     };
 
     {
-        let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered();
+        let _p = tracing::info_span!("diagnostics").entered();
         let _span = profile::cpu_span();
         host.analysis()
             .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 175ffa622ff..a398e98f093 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -14,17 +14,16 @@
 pub mod cli;
 
 mod caps;
-mod cargo_target_spec;
 mod diagnostics;
 mod diff;
 mod dispatch;
-mod global_state;
 mod hack_recover_crate_name;
 mod line_index;
 mod main_loop;
 mod mem_docs;
 mod op_queue;
 mod reload;
+mod target_spec;
 mod task_pool;
 mod version;
 
@@ -40,6 +39,7 @@ pub mod tracing {
 }
 
 pub mod config;
+mod global_state;
 pub mod lsp;
 use self::lsp::ext as lsp_ext;
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index aa75633ac35..b82ba441904 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -3,7 +3,6 @@
 #![allow(clippy::disallowed_types)]
 
 use std::ops;
-use std::path::PathBuf;
 
 use ide_db::line_index::WideEncoding;
 use lsp_types::request::Request;
@@ -12,11 +11,26 @@ use lsp_types::{
     PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
 };
 use lsp_types::{PositionEncodingKind, Url};
+use paths::Utf8PathBuf;
 use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 
 use crate::line_index::PositionEncoding;
 
+pub enum InternalTestingFetchConfig {}
+
+impl Request for InternalTestingFetchConfig {
+    type Params = InternalTestingFetchConfigParams;
+    type Result = serde_json::Value;
+    const METHOD: &'static str = "rust-analyzer-internal/internalTestingFetchConfig";
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct InternalTestingFetchConfigParams {
+    pub text_document: Option<TextDocumentIdentifier>,
+    pub config: String,
+}
 pub enum AnalyzerStatus {}
 
 impl Request for AnalyzerStatus {
@@ -425,24 +439,33 @@ pub struct Runnable {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub location: Option<lsp_types::LocationLink>,
     pub kind: RunnableKind,
-    pub args: CargoRunnable,
+    pub args: RunnableArgs,
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+#[serde(untagged)]
+pub enum RunnableArgs {
+    Cargo(CargoRunnableArgs),
+    Shell(ShellRunnableArgs),
 }
 
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(rename_all = "lowercase")]
 pub enum RunnableKind {
     Cargo,
+    Shell,
 }
 
 #[derive(Deserialize, Serialize, Debug)]
 #[serde(rename_all = "camelCase")]
-pub struct CargoRunnable {
+pub struct CargoRunnableArgs {
     // command to be executed instead of cargo
     pub override_cargo: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub workspace_root: Option<PathBuf>,
+    pub workspace_root: Option<Utf8PathBuf>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub cwd: Option<PathBuf>,
+    pub cwd: Option<Utf8PathBuf>,
     // command, --package and --lib stuff
     pub cargo_args: Vec<String>,
     // user-specified additional cargo args, like `--release`.
@@ -453,6 +476,14 @@ pub struct CargoRunnable {
     pub expect_test: Option<bool>,
 }
 
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct ShellRunnableArgs {
+    pub program: String,
+    pub args: Vec<String>,
+    pub cwd: Utf8PathBuf,
+}
+
 pub enum RelatedTests {}
 
 impl Request for RelatedTests {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index b6b20296d80..60fe847bb7d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -37,8 +37,9 @@ pub(crate) fn offset(
                 .ok_or_else(|| format_err!("Invalid wide col offset"))?
         }
     };
-    let text_size =
-        line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?;
+    let text_size = line_index.index.offset(line_col).ok_or_else(|| {
+        format_err!("Invalid offset {line_col:?} (line index length: {:?})", line_index.index.len())
+    })?;
     Ok(text_size)
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 86368c9eea8..db5f666a5b9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -21,16 +21,17 @@ use serde_json::to_value;
 use vfs::AbsPath;
 
 use crate::{
-    cargo_target_spec::CargoTargetSpec,
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
     lsp::{
+        ext::ShellRunnableArgs,
         semantic_tokens::{self, standard_fallback_type},
         utils::invalid_params_error,
         LspError,
     },
     lsp_ext::{self, SnippetTextEdit},
+    target_spec::{CargoTargetSpec, TargetSpec},
 };
 
 pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@@ -1356,34 +1357,90 @@ pub(crate) fn code_action(
 pub(crate) fn runnable(
     snap: &GlobalStateSnapshot,
     runnable: Runnable,
-) -> Cancellable<lsp_ext::Runnable> {
+) -> Cancellable<Option<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 cwd = match runnable.kind {
-        ide::RunnableKind::Bin { .. } => workspace_root.clone().map(|it| it.into()),
-        _ => spec.as_ref().map(|it| it.cargo_toml.parent().into()),
-    };
-    let target = spec.as_ref().map(|s| s.target.as_str());
-    let label = runnable.label(target);
-    let (cargo_args, executable_args) =
-        CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg);
-    let location = location_link(snap, None, runnable.nav)?;
+    let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?;
 
-    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()),
-            cwd,
-            override_cargo: config.override_cargo,
-            cargo_args,
-            cargo_extra_args: config.cargo_extra_args,
-            executable_args,
-            expect_test: None,
-        },
-    })
+    match target_spec {
+        Some(TargetSpec::Cargo(spec)) => {
+            let workspace_root = spec.workspace_root.clone();
+
+            let target = spec.target.clone();
+
+            let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(
+                snap,
+                Some(spec.clone()),
+                &runnable.kind,
+                &runnable.cfg,
+            );
+
+            let cwd = match runnable.kind {
+                ide::RunnableKind::Bin { .. } => workspace_root.clone(),
+                _ => spec.cargo_toml.parent().to_owned(),
+            };
+
+            let label = runnable.label(Some(&target));
+            let location = location_link(snap, None, runnable.nav)?;
+
+            Ok(Some(lsp_ext::Runnable {
+                label,
+                location: Some(location),
+                kind: lsp_ext::RunnableKind::Cargo,
+                args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
+                    workspace_root: Some(workspace_root.into()),
+                    override_cargo: config.override_cargo,
+                    cargo_args,
+                    cwd: Some(cwd.into()),
+                    cargo_extra_args: config.cargo_extra_args,
+                    executable_args,
+                    expect_test: None,
+                }),
+            }))
+        }
+        Some(TargetSpec::ProjectJson(spec)) => {
+            let label = runnable.label(Some(&spec.label));
+            let location = location_link(snap, None, runnable.nav)?;
+
+            match spec.runnable_args(&runnable.kind) {
+                Some(json_shell_runnable_args) => {
+                    let runnable_args = ShellRunnableArgs {
+                        program: json_shell_runnable_args.program,
+                        args: json_shell_runnable_args.args,
+                        cwd: json_shell_runnable_args.cwd,
+                    };
+                    Ok(Some(lsp_ext::Runnable {
+                        label,
+                        location: Some(location),
+                        kind: lsp_ext::RunnableKind::Shell,
+                        args: lsp_ext::RunnableArgs::Shell(runnable_args),
+                    }))
+                }
+                None => Ok(None),
+            }
+        }
+        None => {
+            let (cargo_args, executable_args) =
+                CargoTargetSpec::runnable_args(snap, None, &runnable.kind, &runnable.cfg);
+
+            let label = runnable.label(None);
+            let location = location_link(snap, None, runnable.nav)?;
+
+            Ok(Some(lsp_ext::Runnable {
+                label,
+                location: Some(location),
+                kind: lsp_ext::RunnableKind::Cargo,
+                args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
+                    workspace_root: None,
+                    override_cargo: config.override_cargo,
+                    cargo_args,
+                    cwd: None,
+                    cargo_extra_args: config.cargo_extra_args,
+                    executable_args,
+                    expect_test: None,
+                }),
+            }))
+        }
+    }
 }
 
 pub(crate) fn code_lens(
@@ -1407,33 +1464,37 @@ pub(crate) fn code_lens(
             };
             let r = runnable(snap, run)?;
 
-            let lens_config = snap.config.lens();
-            if lens_config.run
-                && client_commands_config.run_single
-                && r.args.workspace_root.is_some()
-            {
-                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,
-                })
-            }
-            if lens_config.interpret {
-                let command = command::interpret_single(&r);
-                acc.push(lsp_types::CodeLens {
-                    range: annotation_range,
-                    command: Some(command),
-                    data: None,
-                })
+            if let Some(r) = r {
+                let has_root = match &r.args {
+                    lsp_ext::RunnableArgs::Cargo(c) => c.workspace_root.is_some(),
+                    lsp_ext::RunnableArgs::Shell(_) => true,
+                };
+
+                let lens_config = snap.config.lens();
+                if lens_config.run && client_commands_config.run_single && has_root {
+                    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,
+                    })
+                }
+                if lens_config.interpret {
+                    let command = command::interpret_single(&r);
+                    acc.push(lsp_types::CodeLens {
+                        range: annotation_range,
+                        command: Some(command),
+                        data: None,
+                    })
+                }
             }
         }
         AnnotationKind::HasImpls { pos, data } => {
@@ -1538,12 +1599,8 @@ pub(crate) fn test_item(
         id: test_item.id,
         label: test_item.label,
         kind: match test_item.kind {
-            ide::TestItemKind::Crate(id) => 'b: {
-                let Some((cargo_ws, target)) = snap.cargo_target_for_crate_root(id) else {
-                    break 'b lsp_ext::TestItemKind::Package;
-                };
-                let target = &cargo_ws[target];
-                match target.kind {
+            ide::TestItemKind::Crate(id) => match snap.target_spec_for_crate(id) {
+                Some(target_spec) => match target_spec.target_kind() {
                     project_model::TargetKind::Bin
                     | project_model::TargetKind::Lib { .. }
                     | project_model::TargetKind::Example
@@ -1552,8 +1609,9 @@ pub(crate) fn test_item(
                     project_model::TargetKind::Test => lsp_ext::TestItemKind::Test,
                     // benches are not tests needed to be shown in the test explorer
                     project_model::TargetKind::Bench => return None,
-                }
-            }
+                },
+                None => lsp_ext::TestItemKind::Package,
+            },
             ide::TestItemKind::Module => lsp_ext::TestItemKind::Module,
             ide::TestItemKind::Function => lsp_ext::TestItemKind::Test,
         },
@@ -1566,7 +1624,7 @@ pub(crate) fn test_item(
             .file
             .map(|f| lsp_types::TextDocumentIdentifier { uri: url(snap, f) }),
         range: line_index.and_then(|l| Some(range(l, test_item.text_range?))),
-        runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()),
+        runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()).flatten(),
     })
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 193b3fdd4a8..07414a6e49c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -3,6 +3,7 @@
 
 use std::{
     fmt,
+    ops::Div as _,
     time::{Duration, Instant},
 };
 
@@ -17,7 +18,7 @@ use vfs::FileId;
 
 use crate::{
     config::Config,
-    diagnostics::fetch_native_diagnostics,
+    diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration},
     dispatch::{NotificationDispatcher, RequestDispatcher},
     global_state::{file_id_to_url, url_to_file_id, GlobalState},
     hack_recover_crate_name,
@@ -87,7 +88,7 @@ pub(crate) enum Task {
     Response(lsp_server::Response),
     ClientNotification(lsp_ext::UnindexedProjectParams),
     Retry(lsp_server::Request),
-    Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
+    Diagnostics(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
     DiscoverTest(lsp_ext::DiscoverTestResults),
     PrimeCaches(PrimeCachesProgress),
     FetchWorkspace(ProjectWorkspaceProgress),
@@ -186,6 +187,11 @@ impl GlobalState {
                         scheme: None,
                         pattern: Some("**/Cargo.lock".into()),
                     },
+                    lsp_types::DocumentFilter {
+                        language: None,
+                        scheme: None,
+                        pattern: Some("**/rust-analyzer.toml".into()),
+                    },
                 ]),
             },
         };
@@ -230,7 +236,7 @@ impl GlobalState {
     fn handle_event(&mut self, event: Event) -> anyhow::Result<()> {
         let loop_start = Instant::now();
         // NOTE: don't count blocking select! call as a loop-turn time
-        let _p = tracing::span!(Level::INFO, "GlobalState::handle_event", event = %event).entered();
+        let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered();
 
         let event_dbg_msg = format!("{event:?}");
         tracing::debug!(?loop_start, ?event, "handle_event");
@@ -249,9 +255,7 @@ impl GlobalState {
                 lsp_server::Message::Response(resp) => self.complete_request(resp),
             },
             Event::QueuedTask(task) => {
-                let _p =
-                    tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/queued_task")
-                        .entered();
+                let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered();
                 self.handle_queued_task(task);
                 // Coalesce multiple task events into one loop turn
                 while let Ok(task) = self.deferred_task_queue.receiver.try_recv() {
@@ -259,8 +263,7 @@ impl GlobalState {
                 }
             }
             Event::Task(task) => {
-                let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/task")
-                    .entered();
+                let _p = tracing::info_span!("GlobalState::handle_event/task").entered();
                 let mut prime_caches_progress = Vec::new();
 
                 self.handle_task(&mut prime_caches_progress, task);
@@ -314,8 +317,7 @@ impl GlobalState {
                 }
             }
             Event::Vfs(message) => {
-                let _p =
-                    tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/vfs").entered();
+                let _p = tracing::info_span!("GlobalState::handle_event/vfs").entered();
                 self.handle_vfs_msg(message);
                 // Coalesce many VFS event into a single loop turn
                 while let Ok(message) = self.loader.receiver.try_recv() {
@@ -323,8 +325,7 @@ impl GlobalState {
                 }
             }
             Event::Flycheck(message) => {
-                let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/flycheck")
-                    .entered();
+                let _p = tracing::info_span!("GlobalState::handle_event/flycheck").entered();
                 self.handle_flycheck_msg(message);
                 // Coalesce many flycheck updates into a single loop turn
                 while let Ok(message) = self.flycheck_receiver.try_recv() {
@@ -332,9 +333,7 @@ impl GlobalState {
                 }
             }
             Event::TestResult(message) => {
-                let _p =
-                    tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/test_result")
-                        .entered();
+                let _p = tracing::info_span!("GlobalState::handle_event/test_result").entered();
                 self.handle_cargo_test_msg(message);
                 // Coalesce many test result event into a single loop turn
                 while let Ok(message) = self.test_run_receiver.try_recv() {
@@ -481,6 +480,7 @@ impl GlobalState {
 
     fn update_diagnostics(&mut self) {
         let db = self.analysis_host.raw_database();
+        let generation = self.diagnostics.next_generation();
         let subscriptions = {
             let vfs = &self.vfs.read().0;
             self.mem_docs
@@ -495,16 +495,37 @@ impl GlobalState {
                     // forever if we emitted them here.
                     !db.source_root(source_root).is_library
                 })
-                .collect::<Vec<_>>()
+                .collect::<std::sync::Arc<_>>()
         };
         tracing::trace!("updating notifications for {:?}", subscriptions);
-
-        // Diagnostics are triggered by the user typing
-        // so we run them on a latency sensitive thread.
-        self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
-            let snapshot = self.snapshot();
-            move || Task::Diagnostics(fetch_native_diagnostics(snapshot, subscriptions))
-        });
+        // Split up the work on multiple threads, but we don't wanna fill the entire task pool with
+        // diagnostic tasks, so we limit the number of tasks to a quarter of the total thread pool.
+        let max_tasks = self.config.main_loop_num_threads().div(4).max(1);
+        let chunk_length = subscriptions.len() / max_tasks;
+        let remainder = subscriptions.len() % max_tasks;
+
+        let mut start = 0;
+        for task_idx in 0..max_tasks {
+            let extra = if task_idx < remainder { 1 } else { 0 };
+            let end = start + chunk_length + extra;
+            let slice = start..end;
+            if slice.is_empty() {
+                break;
+            }
+            // Diagnostics are triggered by the user typing
+            // so we run them on a latency sensitive thread.
+            self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
+                let snapshot = self.snapshot();
+                let subscriptions = subscriptions.clone();
+                move || {
+                    Task::Diagnostics(
+                        generation,
+                        fetch_native_diagnostics(snapshot, subscriptions, slice),
+                    )
+                }
+            });
+            start = end;
+        }
     }
 
     fn update_tests(&mut self) {
@@ -591,9 +612,9 @@ impl GlobalState {
             // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
             Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
             Task::Retry(_) => (),
-            Task::Diagnostics(diagnostics_per_file) => {
+            Task::Diagnostics(generation, diagnostics_per_file) => {
                 for (file_id, diagnostics) in diagnostics_per_file {
-                    self.diagnostics.set_native_diagnostics(file_id, diagnostics)
+                    self.diagnostics.set_native_diagnostics(generation, file_id, diagnostics)
                 }
             }
             Task::PrimeCaches(progress) => match progress {
@@ -669,12 +690,11 @@ impl GlobalState {
     }
 
     fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
-        let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg").entered();
+        let _p = tracing::info_span!("GlobalState::handle_vfs_msg").entered();
         let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
         match message {
             vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
-                let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg{changed/load}")
-                    .entered();
+                let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
                     let path = VfsPath::from(path);
@@ -688,8 +708,7 @@ impl GlobalState {
                 }
             }
             vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => {
-                let _p =
-                    tracing::span!(Level::INFO, "GlobalState::handle_vfs_mgs/progress").entered();
+                let _p = tracing::info_span!("GlobalState::handle_vfs_mgs/progress").entered();
                 always!(config_version <= self.vfs_config_version);
 
                 let state = match n_done {
@@ -731,8 +750,7 @@ impl GlobalState {
                 let snap = self.snapshot();
 
                 self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
-                    let _p = tracing::span!(tracing::Level::INFO, "GlobalState::check_if_indexed")
-                        .entered();
+                    let _p = tracing::info_span!("GlobalState::check_if_indexed").entered();
                     tracing::debug!(?uri, "handling uri");
                     let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId");
                     if let Ok(crates) = &snap.analysis.crates_for(id) {
@@ -981,6 +999,8 @@ impl GlobalState {
             .on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
             .on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
             .on::<NO_RETRY, lsp_ext::MoveItem>(handlers::handle_move_item)
+            //
+            .on::<NO_RETRY, lsp_ext::InternalTestingFetchConfig>(handlers::internal_testing_fetch_config)
             .finish();
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 627be7e951a..bd0f733ef39 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -24,6 +24,7 @@ use ide_db::{
 };
 use itertools::Itertools;
 use load_cargo::{load_proc_macro, ProjectFolders};
+use lsp_types::FileSystemWatcher;
 use proc_macro_api::ProcMacroServer;
 use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use stdx::{format_to, thread::ThreadIntent};
@@ -70,8 +71,7 @@ impl GlobalState {
     }
 
     pub(crate) fn update_configuration(&mut self, config: Config) {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "GlobalState::update_configuration").entered();
+        let _p = tracing::info_span!("GlobalState::update_configuration").entered();
         let old_config = mem::replace(&mut self.config, Arc::new(config));
         if self.config.lru_parse_query_capacity() != old_config.lru_parse_query_capacity() {
             self.analysis_host.update_lru_capacity(self.config.lru_parse_query_capacity());
@@ -372,7 +372,7 @@ impl GlobalState {
     }
 
     pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::switch_workspaces").entered();
+        let _p = tracing::info_span!("GlobalState::switch_workspaces").entered();
         tracing::info!(%cause, "will switch workspaces");
 
         let Some((workspaces, force_reload_crate_graph)) =
@@ -440,43 +440,67 @@ impl GlobalState {
         }
 
         if let FilesWatcher::Client = self.config.files().watcher {
-            let filter =
-                self.workspaces.iter().flat_map(|ws| ws.to_roots()).filter(|it| it.is_local);
-
-            let watchers = if self.config.did_change_watched_files_relative_pattern_support() {
-                // When relative patterns are supported by the client, prefer using them
-                filter
-                    .flat_map(|root| {
-                        root.include.into_iter().flat_map(|base| {
-                            [(base.clone(), "**/*.rs"), (base, "**/Cargo.{lock,toml}")]
+            let filter = self
+                .workspaces
+                .iter()
+                .flat_map(|ws| ws.to_roots())
+                .filter(|it| it.is_local)
+                .map(|it| it.include);
+
+            let mut watchers: Vec<FileSystemWatcher> =
+                if self.config.did_change_watched_files_relative_pattern_support() {
+                    // When relative patterns are supported by the client, prefer using them
+                    filter
+                        .flat_map(|include| {
+                            include.into_iter().flat_map(|base| {
+                                [
+                                    (base.clone(), "**/*.rs"),
+                                    (base.clone(), "**/Cargo.{lock,toml}"),
+                                    (base, "**/rust-analyzer.toml"),
+                                ]
+                            })
                         })
-                    })
-                    .map(|(base, pat)| lsp_types::FileSystemWatcher {
-                        glob_pattern: lsp_types::GlobPattern::Relative(
-                            lsp_types::RelativePattern {
-                                base_uri: lsp_types::OneOf::Right(
-                                    lsp_types::Url::from_file_path(base).unwrap(),
-                                ),
-                                pattern: pat.to_owned(),
-                            },
-                        ),
-                        kind: None,
-                    })
-                    .collect()
-            } else {
-                // When they're not, integrate the base to make them into absolute patterns
-                filter
-                    .flat_map(|root| {
-                        root.include.into_iter().flat_map(|base| {
-                            [format!("{base}/**/*.rs"), format!("{base}/**/Cargo.{{lock,toml}}")]
+                        .map(|(base, pat)| lsp_types::FileSystemWatcher {
+                            glob_pattern: lsp_types::GlobPattern::Relative(
+                                lsp_types::RelativePattern {
+                                    base_uri: lsp_types::OneOf::Right(
+                                        lsp_types::Url::from_file_path(base).unwrap(),
+                                    ),
+                                    pattern: pat.to_owned(),
+                                },
+                            ),
+                            kind: None,
                         })
-                    })
+                        .collect()
+                } else {
+                    // When they're not, integrate the base to make them into absolute patterns
+                    filter
+                        .flat_map(|include| {
+                            include.into_iter().flat_map(|base| {
+                                [
+                                    format!("{base}/**/*.rs"),
+                                    format!("{base}/**/Cargo.{{toml,lock}}"),
+                                    format!("{base}/**/rust-analyzer.toml"),
+                                ]
+                            })
+                        })
+                        .map(|glob_pattern| lsp_types::FileSystemWatcher {
+                            glob_pattern: lsp_types::GlobPattern::String(glob_pattern),
+                            kind: None,
+                        })
+                        .collect()
+                };
+
+            watchers.extend(
+                iter::once(self.config.user_config_path().as_path())
+                    .chain(iter::once(self.config.root_ratoml_path().as_path()))
+                    .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
+                    .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
-                        glob_pattern: lsp_types::GlobPattern::String(glob_pattern),
+                        glob_pattern: lsp_types::GlobPattern::String(glob_pattern.to_string()),
                         kind: None,
-                    })
-                    .collect()
-            };
+                    }),
+            );
 
             let registration_options =
                 lsp_types::DidChangeWatchedFilesRegistrationOptions { watchers };
@@ -548,7 +572,7 @@ impl GlobalState {
             version: self.vfs_config_version,
         });
         self.source_root_config = project_folders.source_root_config;
-        self.local_roots_parent_map = self.source_root_config.source_root_parent_map();
+        self.local_roots_parent_map = Arc::new(self.source_root_config.source_root_parent_map());
 
         self.recreate_crate_graph(cause);
 
@@ -660,7 +684,7 @@ impl GlobalState {
     }
 
     fn reload_flycheck(&mut self) {
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::reload_flycheck").entered();
+        let _p = tracing::info_span!("GlobalState::reload_flycheck").entered();
         let config = self.config.flycheck();
         let sender = self.flycheck_sender.clone();
         let invocation_strategy = match config {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 693a35b91e6..6145f7e05f9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -1,20 +1,52 @@
-//! See `CargoTargetSpec`
+//! See `TargetSpec`
 
 use std::mem;
 
 use cfg::{CfgAtom, CfgExpr};
 use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId};
+use project_model::project_json::Runnable;
 use project_model::{CargoFeatures, ManifestPath, TargetKind};
 use rustc_hash::FxHashSet;
 use vfs::AbsPathBuf;
 
 use crate::global_state::GlobalStateSnapshot;
 
+/// A target represents a thing we can build or test.
+///
+/// We use it to calculate the CLI arguments required to build, run or
+/// test the target.
+#[derive(Clone, Debug)]
+pub(crate) enum TargetSpec {
+    Cargo(CargoTargetSpec),
+    ProjectJson(ProjectJsonTargetSpec),
+}
+
+impl TargetSpec {
+    pub(crate) fn for_file(
+        global_state_snapshot: &GlobalStateSnapshot,
+        file_id: FileId,
+    ) -> Cancellable<Option<Self>> {
+        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
+            &[crate_id, ..] => crate_id,
+            _ => return Ok(None),
+        };
+
+        Ok(global_state_snapshot.target_spec_for_crate(crate_id))
+    }
+
+    pub(crate) fn target_kind(&self) -> TargetKind {
+        match self {
+            TargetSpec::Cargo(cargo) => cargo.target_kind,
+            TargetSpec::ProjectJson(project_json) => project_json.target_kind,
+        }
+    }
+}
+
 /// Abstract representation of Cargo target.
 ///
 /// We use it to cook up the set of cli args we need to pass to Cargo to
 /// build/test/run the target.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub(crate) struct CargoTargetSpec {
     pub(crate) workspace_root: AbsPathBuf,
     pub(crate) cargo_toml: ManifestPath,
@@ -26,6 +58,51 @@ pub(crate) struct CargoTargetSpec {
     pub(crate) features: FxHashSet<String>,
 }
 
+#[derive(Clone, Debug)]
+pub(crate) struct ProjectJsonTargetSpec {
+    pub(crate) label: String,
+    pub(crate) target_kind: TargetKind,
+    pub(crate) shell_runnables: Vec<Runnable>,
+}
+
+impl ProjectJsonTargetSpec {
+    pub(crate) fn runnable_args(&self, kind: &RunnableKind) -> Option<Runnable> {
+        match kind {
+            RunnableKind::Bin => {
+                for runnable in &self.shell_runnables {
+                    if matches!(runnable.kind, project_model::project_json::RunnableKind::Run) {
+                        return Some(runnable.clone());
+                    }
+                }
+
+                None
+            }
+            RunnableKind::Test { test_id, .. } => {
+                for runnable in &self.shell_runnables {
+                    if matches!(runnable.kind, project_model::project_json::RunnableKind::TestOne) {
+                        let mut runnable = runnable.clone();
+
+                        let replaced_args: Vec<_> = runnable
+                            .args
+                            .iter()
+                            .map(|arg| arg.replace("{test_id}", &test_id.to_string()))
+                            .map(|arg| arg.replace("{label}", &self.label))
+                            .collect();
+                        runnable.args = replaced_args;
+
+                        return Some(runnable);
+                    }
+                }
+
+                None
+            }
+            RunnableKind::TestMod { .. } => None,
+            RunnableKind::Bench { .. } => None,
+            RunnableKind::DocTest { .. } => None,
+        }
+    }
+}
+
 impl CargoTargetSpec {
     pub(crate) fn runnable_args(
         snap: &GlobalStateSnapshot,
@@ -122,35 +199,6 @@ impl CargoTargetSpec {
         (cargo_args, executable_args)
     }
 
-    pub(crate) fn for_file(
-        global_state_snapshot: &GlobalStateSnapshot,
-        file_id: FileId,
-    ) -> Cancellable<Option<CargoTargetSpec>> {
-        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
-            &[crate_id, ..] => crate_id,
-            _ => return Ok(None),
-        };
-        let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) {
-            Some(it) => it,
-            None => return Ok(None),
-        };
-
-        let target_data = &cargo_ws[target];
-        let package_data = &cargo_ws[target_data.package];
-        let res = CargoTargetSpec {
-            workspace_root: cargo_ws.workspace_root().to_path_buf(),
-            cargo_toml: package_data.manifest.clone(),
-            package: cargo_ws.package_flag(package_data),
-            target: target_data.name.clone(),
-            target_kind: target_data.kind,
-            required_features: target_data.required_features.clone(),
-            features: package_data.features.keys().cloned().collect(),
-            crate_id,
-        };
-
-        Ok(Some(res))
-    }
-
     pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
         buf.push("--package".to_owned());
         buf.push(self.package);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
index f77d9893304..fcdbf6c6949 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
@@ -13,6 +13,7 @@ use tracing_tree::HierarchicalLayer;
 
 use crate::tracing::hprof;
 
+#[derive(Debug)]
 pub struct Config<T> {
     pub writer: T,
     pub filter: String,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
index 73f94671f2d..2d1604e70be 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
@@ -1,8 +1,8 @@
 //! Consumer of `tracing` data, which prints a hierarchical profile.
 //!
-//! Based on https://github.com/davidbarsky/tracing-tree, but does less, while
+//! Based on <https://github.com/davidbarsky/tracing-tree>, but does less, while
 //! actually printing timings for spans by default. The code here is vendored from
-//! https://github.com/matklad/tracing-span-tree.
+//! <https://github.com/matklad/tracing-span-tree>.
 //!
 //! Usage:
 //!
@@ -199,7 +199,7 @@ impl Node {
                 let _ = write!(out, " ({} calls)", self.count);
             }
 
-            eprintln!("{}", out);
+            eprintln!("{out}");
 
             for child in &self.children {
                 child.go(level + 1, filter)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 43a83050105..f886df60e68 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -11,6 +11,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::disallowed_types)]
 
+mod ratoml;
 #[cfg(not(feature = "in-rust-tree"))]
 mod sourcegen;
 mod support;
@@ -30,15 +31,15 @@ use lsp_types::{
     InlayHint, InlayHintLabel, InlayHintParams, PartialResultParams, Position, Range,
     RenameFilesParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams,
 };
+
 use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams, UnindexedProject};
 use serde_json::json;
 use stdx::format_to_acc;
+
 use test_utils::skip_slow_tests;
+use testdir::TestDir;
 
-use crate::{
-    support::{project, Project},
-    testdir::TestDir,
-};
+use crate::support::{project, Project};
 
 #[test]
 fn completes_items_from_standard_library() {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
new file mode 100644
index 00000000000..218a9a32adb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -0,0 +1,947 @@
+use crate::support::{Project, Server};
+use crate::testdir::TestDir;
+use lsp_types::{
+    notification::{DidChangeTextDocument, DidOpenTextDocument, DidSaveTextDocument},
+    DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
+    TextDocumentContentChangeEvent, TextDocumentIdentifier, TextDocumentItem, Url,
+    VersionedTextDocumentIdentifier,
+};
+use paths::Utf8PathBuf;
+
+use rust_analyzer::lsp::ext::{InternalTestingFetchConfig, InternalTestingFetchConfigParams};
+use serde_json::json;
+
+enum QueryType {
+    Local,
+    /// A query whose config key is a part of the global configs, so that
+    /// testing for changes to this config means testing if global changes
+    /// take affect.
+    Global,
+}
+
+struct RatomlTest {
+    urls: Vec<Url>,
+    server: Server,
+    tmp_path: Utf8PathBuf,
+    user_config_dir: Utf8PathBuf,
+}
+
+impl RatomlTest {
+    const EMIT_MUST_USE: &'static str = r#"assist.emitMustUse = true"#;
+    const EMIT_MUST_NOT_USE: &'static str = r#"assist.emitMustUse = false"#;
+
+    const GLOBAL_TRAIT_ASSOC_ITEMS_ZERO: &'static str = r#"hover.show.traitAssocItems = 0"#;
+
+    fn new(
+        fixtures: Vec<&str>,
+        roots: Vec<&str>,
+        client_config: Option<serde_json::Value>,
+    ) -> Self {
+        let tmp_dir = TestDir::new();
+        let tmp_path = tmp_dir.path().to_owned();
+
+        let full_fixture = fixtures.join("\n");
+
+        let user_cnf_dir = TestDir::new();
+        let user_config_dir = user_cnf_dir.path().to_owned();
+
+        let mut project =
+            Project::with_fixture(&full_fixture).tmp_dir(tmp_dir).user_config_dir(user_cnf_dir);
+
+        for root in roots {
+            project = project.root(root);
+        }
+
+        if let Some(client_config) = client_config {
+            project = project.with_config(client_config);
+        }
+
+        let server = project.server().wait_until_workspace_is_loaded();
+
+        let mut case = Self { urls: vec![], server, tmp_path, user_config_dir };
+        let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>();
+        case.urls = urls;
+        case
+    }
+
+    fn fixture_path(&self, fixture: &str) -> Url {
+        let mut lines = fixture.trim().split('\n');
+
+        let mut path =
+            lines.next().expect("All files in a fixture are expected to have at least one line.");
+
+        if path.starts_with("//- minicore") {
+            path = lines.next().expect("A minicore line must be followed by a path.")
+        }
+
+        path = path.strip_prefix("//- ").expect("Path must be preceded by a //- prefix ");
+
+        let spl = path[1..].split('/');
+        let mut path = self.tmp_path.clone();
+
+        let mut spl = spl.into_iter();
+        if let Some(first) = spl.next() {
+            if first == "$$CONFIG_DIR$$" {
+                path = self.user_config_dir.clone();
+            } else {
+                path = path.join(first);
+            }
+        }
+        for piece in spl {
+            path = path.join(piece);
+        }
+
+        Url::parse(
+            format!(
+                "file://{}",
+                path.into_string().to_owned().replace("C:\\", "/c:/").replace('\\', "/")
+            )
+            .as_str(),
+        )
+        .unwrap()
+    }
+
+    fn create(&mut self, fixture_path: &str, text: String) {
+        let url = self.fixture_path(fixture_path);
+
+        self.server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+            text_document: TextDocumentItem {
+                uri: url.clone(),
+                language_id: "rust".to_owned(),
+                version: 0,
+                text: String::new(),
+            },
+        });
+
+        self.server.notification::<DidChangeTextDocument>(DidChangeTextDocumentParams {
+            text_document: VersionedTextDocumentIdentifier { uri: url, version: 0 },
+            content_changes: vec![TextDocumentContentChangeEvent {
+                range: None,
+                range_length: None,
+                text,
+            }],
+        });
+    }
+
+    fn delete(&mut self, file_idx: usize) {
+        self.server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+            text_document: TextDocumentItem {
+                uri: self.urls[file_idx].clone(),
+                language_id: "rust".to_owned(),
+                version: 0,
+                text: "".to_owned(),
+            },
+        });
+
+        // See if deleting ratoml file will make the config of interest to return to its default value.
+        self.server.notification::<DidSaveTextDocument>(DidSaveTextDocumentParams {
+            text_document: TextDocumentIdentifier { uri: self.urls[file_idx].clone() },
+            text: Some("".to_owned()),
+        });
+    }
+
+    fn edit(&mut self, file_idx: usize, text: String) {
+        self.server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+            text_document: TextDocumentItem {
+                uri: self.urls[file_idx].clone(),
+                language_id: "rust".to_owned(),
+                version: 0,
+                text: String::new(),
+            },
+        });
+
+        self.server.notification::<DidChangeTextDocument>(DidChangeTextDocumentParams {
+            text_document: VersionedTextDocumentIdentifier {
+                uri: self.urls[file_idx].clone(),
+                version: 0,
+            },
+            content_changes: vec![TextDocumentContentChangeEvent {
+                range: None,
+                range_length: None,
+                text,
+            }],
+        });
+    }
+
+    fn query(&self, query: QueryType, source_file_idx: usize) -> bool {
+        let config = match query {
+            QueryType::Local => "local".to_owned(),
+            QueryType::Global => "global".to_owned(),
+        };
+        let res = self.server.send_request::<InternalTestingFetchConfig>(
+            InternalTestingFetchConfigParams {
+                text_document: Some(TextDocumentIdentifier {
+                    uri: self.urls[source_file_idx].clone(),
+                }),
+                config,
+            },
+        );
+        res.as_bool().unwrap()
+    }
+}
+
+// /// Check if we are listening for changes in user's config file ( e.g on Linux `~/.config/rust-analyzer/.rust-analyzer.toml`)
+// #[test]
+// #[cfg(target_os = "windows")]
+// fn listen_to_user_config_scenario_windows() {
+//     todo!()
+// }
+
+// #[test]
+// #[cfg(target_os = "linux")]
+// fn listen_to_user_config_scenario_linux() {
+//     todo!()
+// }
+
+// #[test]
+// #[cfg(target_os = "macos")]
+// fn listen_to_user_config_scenario_macos() {
+//     todo!()
+// }
+
+/// Check if made changes have had any effect on
+/// the client config.
+#[test]
+fn ratoml_client_config_basic() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+        ],
+        vec!["p1"],
+        Some(json!({
+            "assist" : {
+                "emitMustUse" : true
+            }
+        })),
+    );
+
+    assert!(server.query(QueryType::Local, 1));
+}
+
+/// Checks if client config can be modified.
+/// FIXME @alibektas : This test is atm not valid.
+/// Asking for client config from the client is a 2 way communication
+/// which we cannot imitate with the current slow-tests infrastructure.
+/// See rust-analyzer::handlers::notifications#197
+//     #[test]
+//     fn client_config_update() {
+//         setup();
+
+//         let server = RatomlTest::new(
+//             vec![
+//                 r#"
+// //- /p1/Cargo.toml
+// [package]
+// name = "p1"
+// version = "0.1.0"
+// edition = "2021"
+// "#,
+//                 r#"
+// //- /p1/src/lib.rs
+// enum Value {
+//     Number(i32),
+//     Text(String),
+// }"#,
+//             ],
+//             vec!["p1"],
+//             None,
+//         );
+
+//         assert!(!server.query(QueryType::AssistEmitMustUse, 1));
+
+//         // a.notification::<DidChangeConfiguration>(DidChangeConfigurationParams {
+//         //     settings: json!({
+//         //         "assists" : {
+//         //             "emitMustUse" : true
+//         //         }
+//         //     }),
+//         // });
+
+//         assert!(server.query(QueryType::AssistEmitMustUse, 1));
+//     }
+
+//     #[test]
+//     fn ratoml_create_ratoml_basic() {
+//         let server = RatomlTest::new(
+//             vec![
+//                 r#"
+// //- /p1/Cargo.toml
+// [package]
+// name = "p1"
+// version = "0.1.0"
+// edition = "2021"
+// "#,
+//                 r#"
+// //- /p1/rust-analyzer.toml
+// assist.emitMustUse = true
+// "#,
+//                 r#"
+// //- /p1/src/lib.rs
+// enum Value {
+//     Number(i32),
+//     Text(String),
+// }
+// "#,
+//             ],
+//             vec!["p1"],
+//             None,
+//         );
+
+//         assert!(server.query(QueryType::AssistEmitMustUse, 2));
+//     }
+
+#[test]
+#[ignore = "the user config is currently not being watched on startup, fix this"]
+fn ratoml_user_config_detected() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 2));
+}
+
+#[test]
+#[ignore = "the user config is currently not being watched on startup, fix this"]
+fn ratoml_create_user_config() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(!server.query(QueryType::Local, 1));
+    server.create(
+        "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
+        RatomlTest::EMIT_MUST_USE.to_owned(),
+    );
+    assert!(server.query(QueryType::Local, 1));
+}
+
+#[test]
+#[ignore = "the user config is currently not being watched on startup, fix this"]
+fn ratoml_modify_user_config() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021""#,
+            r#"
+//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+assist.emitMustUse = true"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 1));
+    server.edit(2, String::new());
+    assert!(!server.query(QueryType::Local, 1));
+}
+
+#[test]
+#[ignore = "the user config is currently not being watched on startup, fix this"]
+fn ratoml_delete_user_config() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021""#,
+            r#"
+//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+assist.emitMustUse = true"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 1));
+    server.delete(2);
+    assert!(!server.query(QueryType::Local, 1));
+}
+// #[test]
+// fn delete_user_config() {
+//     todo!()
+// }
+
+// #[test]
+// fn modify_client_config() {
+//     todo!()
+// }
+
+#[test]
+fn ratoml_inherit_config_from_ws_root() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+}
+
+#[test]
+fn ratoml_modify_ratoml_at_ws_root() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = false
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(!server.query(QueryType::Local, 3));
+    server.edit(1, "assist.emitMustUse = true".to_owned());
+    assert!(server.query(QueryType::Local, 3));
+}
+
+#[test]
+fn ratoml_delete_ratoml_at_ws_root() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+    server.delete(1);
+    assert!(!server.query(QueryType::Local, 3));
+}
+
+#[test]
+fn ratoml_add_immediate_child_to_ws_root() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+    server.create("//- /p1/p2/rust-analyzer.toml", RatomlTest::EMIT_MUST_NOT_USE.to_owned());
+    assert!(!server.query(QueryType::Local, 3));
+}
+
+#[test]
+fn ratoml_rm_ws_root_ratoml_child_has_client_as_parent_now() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+    server.delete(1);
+    assert!(!server.query(QueryType::Local, 3));
+}
+
+#[test]
+fn ratoml_crates_both_roots() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+workspace = { members = ["p2"] }
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/p2/Cargo.toml
+[package]
+name = "p2"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/p2/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+            r#"
+//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}"#,
+        ],
+        vec!["p1", "p2"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+    assert!(server.query(QueryType::Local, 4));
+}
+
+#[test]
+fn ratoml_multiple_ratoml_in_single_source_root() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+        //- /p1/Cargo.toml
+        [package]
+        name = "p1"
+        version = "0.1.0"
+        edition = "2021"
+        "#,
+            r#"
+        //- /p1/rust-analyzer.toml
+        assist.emitMustUse = true
+        "#,
+            r#"
+        //- /p1/src/rust-analyzer.toml
+        assist.emitMustUse = false
+        "#,
+            r#"
+        //- /p1/src/lib.rs
+        enum Value {
+            Number(i32),
+            Text(String),
+        }
+        "#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/src/rust-analyzer.toml
+assist.emitMustUse = false
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/src/lib.rs
+enum Value {
+    Number(i32),
+    Text(String),
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    assert!(server.query(QueryType::Local, 3));
+}
+
+/// If a root is non-local, so we cannot find what its parent is
+/// in our `config.local_root_parent_map`. So if any config should
+/// apply, it must be looked for starting from the client level.
+/// FIXME @alibektas : "locality" is according to ra that, which is simply in the file system.
+/// This doesn't really help us with what we want to achieve here.
+//     #[test]
+//     fn ratoml_non_local_crates_start_inheriting_from_client() {
+//         let server = RatomlTest::new(
+//             vec![
+//                 r#"
+// //- /p1/Cargo.toml
+// [package]
+// name = "p1"
+// version = "0.1.0"
+// edition = "2021"
+
+// [dependencies]
+// p2 = { path = "../p2" }
+// #,
+//                 r#"
+// //- /p1/src/lib.rs
+// enum Value {
+//     Number(i32),
+//     Text(String),
+// }
+
+// use p2;
+
+// pub fn add(left: usize, right: usize) -> usize {
+//     p2::add(left, right)
+// }
+
+// #[cfg(test)]
+// mod tests {
+//     use super::*;
+
+//     #[test]
+//     fn it_works() {
+//         let result = add(2, 2);
+//         assert_eq!(result, 4);
+//     }
+// }"#,
+//                 r#"
+// //- /p2/Cargo.toml
+// [package]
+// name = "p2"
+// version = "0.1.0"
+// edition = "2021"
+
+// # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+// [dependencies]
+// "#,
+//                 r#"
+// //- /p2/rust-analyzer.toml
+// # DEF
+// assist.emitMustUse = true
+// "#,
+//                 r#"
+// //- /p2/src/lib.rs
+// enum Value {
+//     Number(i32),
+//     Text(String),
+// }"#,
+//             ],
+//             vec!["p1", "p2"],
+//             None,
+//         );
+
+//         assert!(!server.query(QueryType::AssistEmitMustUse, 5));
+//     }
+
+/// Having a ratoml file at the root of a project enables
+/// configuring global level configurations as well.
+#[test]
+fn ratoml_in_root_is_global() {
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+        "#,
+            r#"
+//- /rust-analyzer.toml
+hover.show.traitAssocItems = 4
+        "#,
+            r#"
+//- /p1/src/lib.rs
+trait RandomTrait {
+    type B;
+    fn abc() -> i32;
+    fn def() -> i64;
+}
+
+fn main() {
+    let a = RandomTrait;
+}"#,
+        ],
+        vec![],
+        None,
+    );
+
+    server.query(QueryType::Global, 2);
+}
+
+#[allow(unused)]
+// #[test]
+// FIXME: Re-enable this test when we have a global config we can check again
+fn ratoml_root_is_updateable() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+        "#,
+            r#"
+//- /rust-analyzer.toml
+hover.show.traitAssocItems = 4
+        "#,
+            r#"
+//- /p1/src/lib.rs
+trait RandomTrait {
+    type B;
+    fn abc() -> i32;
+    fn def() -> i64;
+}
+
+fn main() {
+    let a = RandomTrait;
+}"#,
+        ],
+        vec![],
+        None,
+    );
+
+    assert!(server.query(QueryType::Global, 2));
+    server.edit(1, RatomlTest::GLOBAL_TRAIT_ASSOC_ITEMS_ZERO.to_owned());
+    assert!(!server.query(QueryType::Global, 2));
+}
+
+#[allow(unused)]
+// #[test]
+// FIXME: Re-enable this test when we have a global config we can check again
+fn ratoml_root_is_deletable() {
+    let mut server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[package]
+name = "p1"
+version = "0.1.0"
+edition = "2021"
+        "#,
+            r#"
+//- /rust-analyzer.toml
+hover.show.traitAssocItems = 4
+        "#,
+            r#"
+//- /p1/src/lib.rs
+trait RandomTrait {
+    type B;
+    fn abc() -> i32;
+    fn def() -> i64;
+}
+
+fn main() {
+    let a = RandomTrait;
+}"#,
+        ],
+        vec![],
+        None,
+    );
+
+    assert!(server.query(QueryType::Global, 2));
+    server.delete(1);
+    assert!(!server.query(QueryType::Global, 2));
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index cf27cc7eeff..c4383255323 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -9,7 +9,10 @@ use crossbeam_channel::{after, select, Receiver};
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
 use paths::{Utf8Path, Utf8PathBuf};
-use rust_analyzer::{config::Config, lsp, main_loop};
+use rust_analyzer::{
+    config::{Config, ConfigChange, ConfigErrors},
+    lsp, main_loop,
+};
 use serde::Serialize;
 use serde_json::{json, to_string_pretty, Value};
 use test_utils::FixtureWithProjectMeta;
@@ -24,6 +27,7 @@ pub(crate) struct Project<'a> {
     roots: Vec<Utf8PathBuf>,
     config: serde_json::Value,
     root_dir_contains_symlink: bool,
+    user_config_path: Option<Utf8PathBuf>,
 }
 
 impl Project<'_> {
@@ -47,9 +51,15 @@ impl Project<'_> {
                 }
             }),
             root_dir_contains_symlink: false,
+            user_config_path: None,
         }
     }
 
+    pub(crate) fn user_config_dir(mut self, config_path_dir: TestDir) -> Self {
+        self.user_config_path = Some(config_path_dir.path().to_owned());
+        self
+    }
+
     pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Self {
         self.tmp_dir = Some(tmp_dir);
         self
@@ -111,10 +121,17 @@ impl Project<'_> {
         assert!(proc_macro_names.is_empty());
         assert!(mini_core.is_none());
         assert!(toolchain.is_none());
+
         for entry in fixture {
-            let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
-            fs::create_dir_all(path.parent().unwrap()).unwrap();
-            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
+            if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
+                let path = self.user_config_path.clone().unwrap().join(&pth['/'.len_utf8()..]);
+                fs::create_dir_all(path.parent().unwrap()).unwrap();
+                fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
+            } else {
+                let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
+                fs::create_dir_all(path.parent().unwrap()).unwrap();
+                fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
+            }
         }
 
         let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf());
@@ -184,8 +201,16 @@ impl Project<'_> {
             },
             roots,
             None,
+            self.user_config_path,
         );
-        config.update(self.config).expect("invalid config");
+        let mut change = ConfigChange::default();
+
+        change.change_client_config(self.config);
+
+        let error_sink: ConfigErrors;
+        (config, error_sink, _) = config.apply_change(change);
+        assert!(error_sink.is_empty(), "{error_sink:?}");
+
         config.rediscover_workspaces();
 
         Server::new(tmp_dir.keep(), config)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 4a7415b016d..7dd6382cfac 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -185,27 +185,6 @@ Zlib OR Apache-2.0 OR MIT
 }
 
 fn check_test_attrs(path: &Path, text: &str) {
-    let ignore_rule =
-        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#ignore";
-    let need_ignore: &[&str] = &[
-        // This file.
-        "slow-tests/tidy.rs",
-        // Special case to run `#[ignore]` tests.
-        "ide/src/runnables.rs",
-        // A legit test which needs to be ignored, as it takes too long to run
-        // :(
-        "hir-def/src/nameres/collector.rs",
-        // Long sourcegen test to generate lint completions.
-        "ide-db/src/tests/sourcegen_lints.rs",
-        // Obviously needs ignore.
-        "ide-assists/src/handlers/toggle_ignore.rs",
-        // See above.
-        "ide-assists/src/tests/generated.rs",
-    ];
-    if text.contains("#[ignore") && !need_ignore.iter().any(|p| path.ends_with(p)) {
-        panic!("\ndon't `#[ignore]` tests, see:\n\n    {ignore_rule}\n\n   {}\n", path.display(),)
-    }
-
     let panic_rule =
         "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#should_panic";
     let need_panic: &[&str] = &[
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
index 659797d6d4a..4e707412397 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
@@ -20,7 +20,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
     let input_span = input.span();
     let (trait_attrs, salsa_attrs) = filter_attrs(input.attrs);
     if !salsa_attrs.is_empty() {
-        return Error::new(input_span, format!("unsupported attributes: {:?}", salsa_attrs))
+        return Error::new(input_span, format!("unsupported attributes: {salsa_attrs:?}"))
             .to_compile_error()
             .into();
     }
@@ -78,7 +78,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                         num_storages += 1;
                     }
                     _ => {
-                        return Error::new(span, format!("unknown salsa attribute `{}`", name))
+                        return Error::new(span, format!("unknown salsa attribute `{name}`"))
                             .to_compile_error()
                             .into();
                     }
@@ -111,7 +111,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                 _ => {
                     return Error::new(
                         sig_span,
-                        format!("first argument of query `{}` must be `&self`", query_name),
+                        format!("first argument of query `{query_name}` must be `&self`"),
                     )
                     .to_compile_error()
                     .into();
@@ -130,7 +130,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                     arg => {
                         return Error::new(
                             arg.span(),
-                            format!("unsupported argument `{:?}` of `{}`", arg, query_name,),
+                            format!("unsupported argument `{arg:?}` of `{query_name}`",),
                         )
                         .to_compile_error()
                         .into();
@@ -144,7 +144,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                 ref ret => {
                     return Error::new(
                         ret.span(),
-                        format!("unsupported return type `{:?}` of `{}`", ret, query_name),
+                        format!("unsupported return type `{ret:?}` of `{query_name}`"),
                     )
                     .to_compile_error()
                     .into();
@@ -169,7 +169,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                 let lookup_keys = vec![(parse_quote! { key }, value.clone())];
                 Some(Query {
                     query_type: lookup_query_type,
-                    query_name: format!("{}", lookup_fn_name),
+                    query_name: format!("{lookup_fn_name}"),
                     fn_name: lookup_fn_name,
                     receiver: self_receiver.clone(),
                     attrs: vec![], // FIXME -- some automatically generated docs on this method?
@@ -238,7 +238,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
         let tracing = if let QueryStorage::Memoized = query.storage {
             let s = format!("{trait_name}::{fn_name}");
             Some(quote! {
-                let _p = tracing::span!(tracing::Level::DEBUG, #s, #(#key_names = tracing::field::debug(&#key_names)),*).entered();
+                let _p = tracing::debug_span!(#s, #(#key_names = tracing::field::debug(&#key_names)),*).entered();
             })
         } else {
             None
@@ -274,8 +274,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                 *Note:* Setting values will trigger cancellation
                 of any ongoing queries; this method blocks until
                 those queries have been cancelled.
-            ",
-                fn_name = fn_name
+            "
             );
 
             let set_constant_fn_docs = format!(
@@ -290,8 +289,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
                 *Note:* Setting values will trigger cancellation
                 of any ongoing queries; this method blocks until
                 those queries have been cancelled.
-            ",
-                fn_name = fn_name
+            "
             );
 
             query_fn_declarations.extend(quote! {
diff --git a/src/tools/rust-analyzer/crates/salsa/src/interned.rs b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
index bfa9cc0591a..eef8bcc814f 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/interned.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
@@ -98,26 +98,27 @@ impl<A: InternValue + Eq + Hash + Debug + Clone, B: InternValue + Eq + Hash + De
     }
 }
 
+pub trait InternValueTrivial
+where
+    Self: Eq + Hash + Debug + Clone,
+{
+}
+
 /// Implement [`InternValue`] trivially, that is without actually mapping at all.
-#[macro_export]
-macro_rules! impl_intern_value_trivial {
-    ($($ty:ty),*) => {
-        $(
-            impl $crate::InternValue for $ty {
-                type Key = $ty;
-                #[inline]
-                fn into_key(&self) -> Self::Key {
-                    self.clone()
-                }
-                #[inline]
-                fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
-                    f(self)
-                }
-            }
-        )*
-    };
+impl<V: InternValueTrivial> InternValue for V {
+    type Key = Self;
+    #[inline]
+    fn into_key(&self) -> Self::Key {
+        self.clone()
+    }
+    #[inline]
+    fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
+        f(self)
+    }
 }
-impl_intern_value_trivial!(String);
+
+impl InternValueTrivial for String {}
+
 #[derive(Debug)]
 struct Slot<V> {
     /// DatabaseKeyIndex for this slot.
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
index 5dde0d560f1..e11e6e2e19f 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -40,7 +40,7 @@ use std::panic::{self, UnwindSafe};
 
 pub use crate::durability::Durability;
 pub use crate::intern_id::InternId;
-pub use crate::interned::{InternKey, InternValue};
+pub use crate::interned::{InternKey, InternValue, InternValueTrivial};
 pub use crate::runtime::Runtime;
 pub use crate::runtime::RuntimeId;
 pub use crate::storage::Storage;
@@ -284,7 +284,7 @@ pub trait ParallelDatabase: Database + Send {
     /// series of queries in parallel and arranging the results. Using
     /// this method for that purpose ensures that those queries will
     /// see a consistent view of the database (it is also advisable
-    /// for those queries to use the [`Runtime::unwind_if_cancelled`]
+    /// for those queries to use the [`Database::unwind_if_cancelled`]
     /// method to check for cancellation).
     ///
     /// # Panics
@@ -513,6 +513,10 @@ where
     {
         self.storage.purge();
     }
+
+    pub fn storage(&self) -> &<Q as Query>::Storage {
+        self.storage
+    }
 }
 
 /// Return value from [the `query_mut` method] on `Database`.
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs
index ea5d15a250f..e9bddfc630e 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs
@@ -162,7 +162,7 @@ fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle {
             return cycle.clone();
         }
     }
-    panic!("unexpected value: {:?}", v)
+    panic!("unexpected value: {v:?}")
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs
index ea0eb819786..32bfbc4564b 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs
@@ -13,12 +13,12 @@ pub(crate) trait ConstantsDatabase: TestContext {
 }
 
 fn add(db: &dyn ConstantsDatabase, key1: char, key2: char) -> usize {
-    db.log().add(format!("add({}, {})", key1, key2));
+    db.log().add(format!("add({key1}, {key2})"));
     db.input(key1) + db.input(key2)
 }
 
 fn add3(db: &dyn ConstantsDatabase, key1: char, key2: char, key3: char) -> usize {
-    db.log().add(format!("add3({}, {}, {})", key1, key2, key3));
+    db.log().add(format!("add3({key1}, {key2}, {key3})"));
     db.add(key1, key2) + db.input(key3)
 }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs
index 19752bba005..84349134415 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs
@@ -26,7 +26,7 @@ pub(crate) struct TestContextImpl {
 impl TestContextImpl {
     #[track_caller]
     pub(crate) fn assert_log(&self, expected_log: &[&str]) {
-        let expected_text = &format!("{:#?}", expected_log);
+        let expected_text = &format!("{expected_log:#?}");
         let actual_text = &format!("{:#?}", self.log().take());
 
         if expected_text == actual_text {
@@ -36,9 +36,9 @@ impl TestContextImpl {
         #[allow(clippy::print_stdout)]
         for diff in dissimilar::diff(expected_text, actual_text) {
             match diff {
-                dissimilar::Chunk::Delete(l) => println!("-{}", l),
-                dissimilar::Chunk::Equal(l) => println!(" {}", l),
-                dissimilar::Chunk::Insert(r) => println!("+{}", r),
+                dissimilar::Chunk::Delete(l) => println!("-{l}"),
+                dissimilar::Chunk::Equal(l) => println!(" {l}"),
+                dissimilar::Chunk::Insert(r) => println!("+{r}"),
             }
         }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs
index 2930c4e379f..3c73852eafb 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs
@@ -33,7 +33,7 @@ fn parallel_cycle_none_recover() {
         "#]]
         .assert_debug_eq(&c.unexpected_participants(&db));
     } else {
-        panic!("b failed in an unexpected way: {:?}", err_b);
+        panic!("b failed in an unexpected way: {err_b:?}");
     }
 
     // We expect A to propagate a panic, which causes us to use the sentinel
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs
index e875de998f8..c53d4b464ea 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs
@@ -28,7 +28,7 @@ fn in_par_get_set_race() {
     // cancellation, it'll unwind.
     let result1 = thread1.join().unwrap();
     if let Ok(value1) = result1 {
-        assert!(value1 == 111 || value1 == 1011, "illegal result {}", value1);
+        assert!(value1 == 111 || value1 == 1011, "illegal result {value1}");
     }
 
     // thread2 can not observe a cancellation because it performs a
diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
index e4b0a26a6ff..e8c558355c9 100644
--- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
@@ -4,7 +4,7 @@
 //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
 //! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
 //!
-//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
+//! Also see <https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies>
 //!
 //! # The Expansion Order Hierarchy
 //!
diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs
index 8ca7bc2d38a..bbaf1b2a6d5 100644
--- a/src/tools/rust-analyzer/crates/span/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/span/src/lib.rs
@@ -86,15 +86,6 @@ impl<Ctx: Copy> SpanData<Ctx> {
     }
 }
 
-impl Span {
-    #[deprecated = "dummy spans will panic if surfaced incorrectly, as such they should be replaced appropriately"]
-    pub const DUMMY: Self = Self {
-        range: TextRange::empty(TextSize::new(0)),
-        anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID },
-        ctx: SyntaxContextId::ROOT,
-    };
-}
-
 impl fmt::Display for Span {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Debug::fmt(&self.anchor.file_id.index(), f)?;
@@ -178,6 +169,8 @@ impl salsa::InternKey for MacroCallId {
 }
 
 impl MacroCallId {
+    pub const MAX_ID: u32 = 0x7fff_ffff;
+
     pub fn as_file(self) -> HirFileId {
         MacroFileId { macro_call_id: self }.into()
     }
@@ -218,7 +211,7 @@ impl From<MacroFileId> for HirFileId {
     fn from(MacroFileId { macro_call_id: MacroCallId(id) }: MacroFileId) -> Self {
         _ = Self::ASSERT_MAX_FILE_ID_IS_SAME;
         let id = id.as_u32();
-        assert!(id <= Self::MAX_HIR_FILE_ID, "MacroCallId index {} is too large", id);
+        assert!(id <= Self::MAX_HIR_FILE_ID, "MacroCallId index {id} is too large");
         HirFileId(id | Self::MACRO_FILE_TAG_MASK)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
index d47b3d1647e..d189b56a468 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
@@ -1,6 +1,6 @@
-//! This file is a port of only the necessary features from https://github.com/chris-morgan/anymap version 1.0.0-beta.2 for use within rust-analyzer.
+//! This file is a port of only the necessary features from <https://github.com/chris-morgan/anymap> version 1.0.0-beta.2 for use within rust-analyzer.
 //! Copyright © 2014–2022 Chris Morgan.
-//! COPYING: https://github.com/chris-morgan/anymap/blob/master/COPYING
+//! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING>
 //! Note that the license is changed from Blue Oak Model 1.0.0 or MIT or Apache-2.0 to MIT OR Apache-2.0
 //!
 //! This implementation provides a safe and convenient store for one value of each type.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
index 0e62de5febb..9b43da83418 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
@@ -120,7 +120,7 @@ pub struct TreeDiff {
 
 impl TreeDiff {
     pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
-        let _p = tracing::span!(tracing::Level::INFO, "into_text_edit").entered();
+        let _p = tracing::info_span!("into_text_edit").entered();
 
         for (anchor, to) in &self.insertions {
             let offset = match anchor {
@@ -149,7 +149,7 @@ impl TreeDiff {
 ///
 /// This function tries to find a fine-grained diff.
 pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
-    let _p = tracing::span!(tracing::Level::INFO, "diff").entered();
+    let _p = tracing::info_span!("diff").entered();
 
     let mut diff = TreeDiff {
         replacements: FxHashMap::default(),
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 186f1b01da4..35ec9b1013d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -172,7 +172,7 @@ pub fn ty_alias(
     assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
 ) -> ast::TypeAlias {
     let mut s = String::new();
-    s.push_str(&format!("type {}", ident));
+    s.push_str(&format!("type {ident}"));
 
     if let Some(list) = generic_param_list {
         s.push_str(&list.to_string());
@@ -297,7 +297,7 @@ pub fn impl_trait(
         };
 
     let where_clause = merge_where_clause(ty_where_clause, trait_where_clause)
-        .map_or_else(|| " ".to_owned(), |wc| format!("\n{}\n", wc));
+        .map_or_else(|| " ".to_owned(), |wc| format!("\n{wc}\n"));
 
     let body = match body {
         Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
@@ -1159,7 +1159,7 @@ pub mod tokens {
 
     pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
         SourceFile::parse(
-            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let a @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT,
+            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let _ @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT,
         )
     });
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index 3a9ebafe87d..b5d816b0ce1 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -107,14 +107,22 @@ impl<T> Parse<T> {
 }
 
 impl<T: AstNode> Parse<T> {
+    /// Converts this parse result into a parse result for an untyped syntax tree.
     pub fn to_syntax(self) -> Parse<SyntaxNode> {
         Parse { green: self.green, errors: self.errors, _ty: PhantomData }
     }
 
+    /// Gets the parsed syntax tree as a typed ast node.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the root node cannot be casted into the typed ast node
+    /// (e.g. if it's an `ERROR` node).
     pub fn tree(&self) -> T {
         T::cast(self.syntax_node()).unwrap()
     }
 
+    /// Converts from `Parse<T>` to [`Result<T, Vec<SyntaxError>>`].
     pub fn ok(self) -> Result<T, Vec<SyntaxError>> {
         match self.errors() {
             errors if !errors.is_empty() => Err(errors),
@@ -167,21 +175,40 @@ impl Parse<SourceFile> {
     }
 }
 
+impl ast::Expr {
+    /// Parses an `ast::Expr` from `text`.
+    ///
+    /// Note that if the parsed root node is not a valid expression, [`Parse::tree`] will panic.
+    /// For example:
+    /// ```rust,should_panic
+    /// # use syntax::{ast, Edition};
+    /// ast::Expr::parse("let fail = true;", Edition::CURRENT).tree();
+    /// ```
+    pub fn parse(text: &str, edition: Edition) -> Parse<ast::Expr> {
+        let _p = tracing::info_span!("Expr::parse").entered();
+        let (green, errors) = parsing::parse_text_at(text, parser::TopEntryPoint::Expr, edition);
+        let root = SyntaxNode::new_root(green.clone());
+
+        assert!(
+            ast::Expr::can_cast(root.kind()) || root.kind() == SyntaxKind::ERROR,
+            "{:?} isn't an expression",
+            root.kind()
+        );
+        Parse::new(green, errors)
+    }
+}
+
 /// `SourceFile` represents a parse tree for a single Rust file.
 pub use crate::ast::SourceFile;
 
 impl SourceFile {
     pub fn parse(text: &str, edition: Edition) -> Parse<SourceFile> {
-        let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered();
+        let _p = tracing::info_span!("SourceFile::parse").entered();
         let (green, errors) = parsing::parse_text(text, edition);
         let root = SyntaxNode::new_root(green.clone());
 
         assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
-        Parse {
-            green,
-            errors: if errors.is_empty() { None } else { Some(errors.into()) },
-            _ty: PhantomData,
-        }
+        Parse::new(green, errors)
     }
 }
 
@@ -290,12 +317,7 @@ impl ast::TokenTree {
         }
 
         let (green, errors) = builder.finish_raw();
-
-        Parse {
-            green,
-            errors: if errors.is_empty() { None } else { Some(errors.into()) },
-            _ty: PhantomData,
-        }
+        Parse::new(green, errors)
     }
 }
 
@@ -420,7 +442,7 @@ fn api_walkthrough() {
     assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
     assert_eq!(
         expr_syntax.descendants_with_tokens().count(),
-        8, // 5 tokens `1`, ` `, `+`, ` `, `!`
+        8, // 5 tokens `1`, ` `, `+`, ` `, `1`
            // 2 child literal expressions: `1`, `1`
            // 1 the node itself: `1 + 1`
     );
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
index 420f4938e54..4bf2a032791 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
@@ -10,7 +10,7 @@ use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder};
 pub(crate) use crate::parsing::reparsing::incremental_reparse;
 
 pub(crate) fn parse_text(text: &str, edition: parser::Edition) -> (GreenNode, Vec<SyntaxError>) {
-    let _p = tracing::span!(tracing::Level::INFO, "parse_text").entered();
+    let _p = tracing::info_span!("parse_text").entered();
     let lexed = parser::LexedStr::new(text);
     let parser_input = lexed.to_input();
     let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input, edition);
@@ -18,11 +18,24 @@ pub(crate) fn parse_text(text: &str, edition: parser::Edition) -> (GreenNode, Ve
     (node, errors)
 }
 
+pub(crate) fn parse_text_at(
+    text: &str,
+    entry: parser::TopEntryPoint,
+    edition: parser::Edition,
+) -> (GreenNode, Vec<SyntaxError>) {
+    let _p = tracing::info_span!("parse_text_at").entered();
+    let lexed = parser::LexedStr::new(text);
+    let parser_input = lexed.to_input();
+    let parser_output = entry.parse(&parser_input, edition);
+    let (node, errors, _eof) = build_tree(lexed, parser_output);
+    (node, errors)
+}
+
 pub(crate) fn build_tree(
     lexed: parser::LexedStr<'_>,
     parser_output: parser::Output,
 ) -> (GreenNode, Vec<SyntaxError>, bool) {
-    let _p = tracing::span!(tracing::Level::INFO, "build_tree").entered();
+    let _p = tracing::info_span!("build_tree").entered();
     let mut builder = SyntaxTreeBuilder::default();
 
     let is_eof = lexed.intersperse_trivia(&parser_output, &mut |step| match step {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
index dbfab537fe5..13d352d3c69 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
@@ -16,7 +16,7 @@ use crate::{
 };
 
 pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
-    let _p = tracing::span!(tracing::Level::INFO, "parser::validate").entered();
+    let _p = tracing::info_span!("parser::validate").entered();
     // FIXME:
     // * Add unescape validation of raw string literals and raw byte string literals
     // * Add validation of doc comments are being attached to nodes
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index be9961120d5..e65186d3771 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -196,7 +196,7 @@ impl ChangeFixture {
                     origin,
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
-                assert!(prev.is_none(), "multiple crates with same name: {}", crate_name);
+                assert!(prev.is_none(), "multiple crates with same name: {crate_name}");
                 for dep in meta.deps {
                     let prelude = match &meta.extern_prelude {
                         Some(v) => v.contains(&dep),
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index aafe4fb5b10..54c9db7aacc 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -143,14 +143,14 @@ pub struct FixtureWithProjectMeta {
     /// Specifies LLVM data layout to be used.
     ///
     /// You probably don't want to manually specify this. See LLVM manual for the
-    /// syntax, if you must: https://llvm.org/docs/LangRef.html#data-layout
+    /// syntax, if you must: <https://llvm.org/docs/LangRef.html#data-layout>
     pub target_data_layout: String,
 }
 
 impl FixtureWithProjectMeta {
     /// Parses text which looks like this:
     ///
-    ///  ```not_rust
+    ///  ```text
     ///  //- some meta
     ///  line 1
     ///  line 2
@@ -159,7 +159,7 @@ impl FixtureWithProjectMeta {
     ///
     /// Fixture can also start with a proc_macros and minicore declaration (in that order):
     ///
-    /// ```
+    /// ```text
     /// //- toolchain: nightly
     /// //- proc_macros: identity
     /// //- minicore: sized
@@ -450,7 +450,7 @@ impl MiniCore {
         }
 
         if !active_regions.is_empty() {
-            panic!("unclosed regions: {:?} Add an `endregion` comment", active_regions);
+            panic!("unclosed regions: {active_regions:?} Add an `endregion` comment");
         }
 
         for flag in &self.valid_flags {
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
index b750107803a..43f62d0d1e0 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
@@ -224,7 +224,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
 /// Annotations point to the last line that actually was long enough for the
 /// range, not counting annotations themselves. So overlapping annotations are
 /// possible:
-/// ```no_run
+/// ```text
 /// // stuff        other stuff
 /// // ^^ 'st'
 /// // ^^^^^ 'stuff'
diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
index b577723612d..2591ed16916 100644
--- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
@@ -23,7 +23,7 @@ impl Tool {
     ///
     /// The current implementation checks three places for an executable to use:
     /// 1) `$CARGO_HOME/bin/<executable_name>`
-    ///      where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html)
+    ///      where $CARGO_HOME defaults to ~/.cargo (see <https://doc.rust-lang.org/cargo/guide/cargo-home.html>)
     ///      example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset.
     ///      It seems that this is a reasonable place to try for cargo, rustc, and rustup
     /// 2) Appropriate environment variable (erroring if this is set but not a usable executable)
@@ -45,7 +45,7 @@ impl Tool {
     ///      example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the
     ///      first that exists
     /// 3) `$CARGO_HOME/bin/<executable_name>`
-    ///      where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html)
+    ///      where $CARGO_HOME defaults to ~/.cargo (see <https://doc.rust-lang.org/cargo/guide/cargo-home.html>)
     ///      example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset.
     ///      It seems that this is a reasonable place to try for cargo, rustc, and rustup
     /// 4) If all else fails, we just try to use the executable name directly
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index ab0efff6512..e9de3f97b0e 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -147,7 +147,7 @@ pub struct Punct<S> {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Spacing {
     Alone,
-    /// Whether the following token is joint to the current one.
+    /// Whether the following token is joint to this one.
     Joint,
 }
 
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index b07e97cd6cd..18c8699dd4d 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -69,9 +69,6 @@ pub struct FileId(u32);
 // pub struct FileId(NonMaxU32);
 
 impl FileId {
-    /// Think twice about using this outside of tests. If this ends up in a wrong place it will cause panics!
-    // FIXME: To be removed once we get rid of all `SpanData::DUMMY` usages.
-    pub const BOGUS: FileId = FileId(0xe4e4e);
     pub const MAX_FILE_ID: u32 = 0x7fff_ffff;
 
     #[inline]
@@ -282,7 +279,7 @@ impl Vfs {
     /// Returns the id associated with `path`
     ///
     /// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a
-    /// deleted file;
+    ///   deleted file;
     /// - Else, returns `path`'s id.
     ///
     /// Does not record a change.
diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
index 2d3fb9d88c8..92a49e07936 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs
@@ -384,8 +384,7 @@ impl VirtualPath {
     ///
     /// # Returns
     /// - `None` if `self` ends with `"//"`.
-    /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at
-    /// the start.
+    /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at the start.
     /// - `Some((name, Some(extension))` else.
     ///
     /// # Note
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 8897f02e277..002b8ba2a66 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -145,7 +145,7 @@ To log all communication between the server and the client, there are two choice
   ```
   env RA_LOG=lsp_server=debug code .
   ```
-* You can log on the client side, by enabling `"rust-analyzer.trace.server": "verbose"` workspace setting.
+* You can log on the client side, by the `rust-analyzer: Toggle LSP Logs` command or enabling `"rust-analyzer.trace.server": "verbose"` workspace setting.
   These logs are shown in a separate tab in the output and could be used with LSP inspector.
   Kudos to [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up!
 
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 1c91e856e72..695fec7e8e0 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 1babf76a3c2cef3b
+lsp/ext.rs hash: 8e6e340f2899b5e9
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -372,7 +372,7 @@ interface Runnable {
 }
 ```
 
-rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this:
+rust-analyzer supports two `kind`s of runnables, `"cargo"` and `"shell"`. The `args` for `"cargo"` look like this:
 
 ```typescript
 {
@@ -386,6 +386,17 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look
 }
 ```
 
+The args for `"shell"` look like this:
+
+```typescript
+{
+    kind: string;
+    program: string;
+    args: string[];
+    cwd: string;
+}
+```
+
 ## Test explorer
 
 **Experimental Client Capability:** `{ "testExplorer": boolean }`
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 8993a46d2b8..14aae91741e 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -19,7 +19,7 @@ Term search fuel in "units of work" for assists (Defaults to 400).
 --
 Warm up caches on project load.
 --
-[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `0`)::
+[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `"physical"`)::
 +
 --
 How many worker threads to handle priming caches. The default `0` means to pick automatically.
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 8e6c53d0c5a..e1c1c54ec41 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -21,7 +21,7 @@ The LSP allows various code editors, like VS Code, Emacs or Vim, to implement se
 To improve this document, send a pull request: +
 https://github.com/rust-lang/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc]
 
-The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo test -p xtask` to create these and then `asciidoctor manual.adoc` to create an HTML copy.
+The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo xtask codegen` to create these and then `asciidoctor manual.adoc` to create an HTML copy.
 ====
 
 If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum.
@@ -591,7 +591,7 @@ The next thing to check would be panic messages in rust-analyzer's log.
 Log messages are printed to stderr, in VS Code you can see them in the `Output > Rust Analyzer Language Server` tab of the panel.
 To see more logs, set the `RA_LOG=info` environment variable, this can be done either by setting the environment variable manually or by using `rust-analyzer.server.extraEnv`, note that both of these approaches require the server to be restarted.
 
-To fully capture LSP messages between the editor and the server, set `"rust-analyzer.trace.server": "verbose"` config and check
+To fully capture LSP messages between the editor and the server, run the `rust-analyzer: Toggle LSP Logs` command and check
 `Output > Rust Analyzer Language Server Trace`.
 
 The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure.
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index bd8b0e9c4e0..7de75763177 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -1087,12 +1087,12 @@
             }
         },
         "node_modules/braces": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+            "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
             "dev": true,
             "dependencies": {
-                "fill-range": "^7.0.1"
+                "fill-range": "^7.1.1"
             },
             "engines": {
                 "node": ">=8"
@@ -2243,9 +2243,9 @@
             }
         },
         "node_modules/fill-range": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-            "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+            "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
             "dev": true,
             "dependencies": {
                 "to-regex-range": "^5.0.1"
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 6e4fedd992c..db2a989106f 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -300,6 +300,11 @@
                 "command": "rust-analyzer.toggleCheckOnSave",
                 "title": "Toggle Check on Save",
                 "category": "rust-analyzer"
+            },
+            {
+                "command": "rust-analyzer.toggleLSPLogs",
+                "title": "Toggle LSP Logs",
+                "category": "rust-analyzer"
             }
         ],
         "keybindings": [
@@ -314,1440 +319,2281 @@
                 "when": "editorTextFocus && editorLangId == rust"
             }
         ],
-        "configuration": {
-            "type": "object",
-            "title": "rust-analyzer",
-            "properties": {
-                "rust-analyzer.cargoRunner": {
-                    "type": [
-                        "null",
-                        "string"
-                    ],
-                    "default": null,
-                    "description": "Custom cargo runner extension ID."
-                },
-                "rust-analyzer.runnables.extraEnv": {
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
-                            "type": "array",
-                            "items": {
-                                "type": "object",
-                                "properties": {
-                                    "platform": {
-                                        "type": [
-                                            "null",
-                                            "string",
-                                            "array"
-                                        ],
-                                        "default": null,
-                                        "markdownDescription": "Platform(s) filter like \"win32\" or [\"linux\", \"win32\"]. See [process.platform](https://nodejs.org/api/process.html#processplatform) values."
-                                    },
-                                    "mask": {
-                                        "type": "string",
-                                        "description": "Runnable name mask"
-                                    },
-                                    "env": {
-                                        "type": "object",
-                                        "description": "Variables in form of { \"key\": \"value\"}"
+        "configuration": [
+            {
+                "title": "general",
+                "properties": {
+                    "rust-analyzer.cargoRunner": {
+                        "type": [
+                            "null",
+                            "string"
+                        ],
+                        "default": null,
+                        "description": "Custom cargo runner extension ID."
+                    },
+                    "rust-analyzer.restartServerOnConfigChange": {
+                        "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
+                        "default": false,
+                        "type": "boolean"
+                    },
+                    "rust-analyzer.discoverProjectRunner": {
+                        "markdownDescription": "Sets the extension responsible for determining which extension the rust-analyzer extension uses to generate `rust-project.json` files. This should should only be used\n if a build system like Buck or Bazel is also in use.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    },
+                    "rust-analyzer.showUnlinkedFileNotification": {
+                        "markdownDescription": "Whether to show a notification for unlinked files asking the user to add the corresponding Cargo.toml to the linked projects setting.",
+                        "default": true,
+                        "type": "boolean"
+                    },
+                    "rust-analyzer.showRequestFailedErrorNotification": {
+                        "markdownDescription": "Whether to show error notifications for failing requests.",
+                        "default": true,
+                        "type": "boolean"
+                    },
+                    "rust-analyzer.showDependenciesExplorer": {
+                        "markdownDescription": "Whether to show the dependencies view.",
+                        "default": true,
+                        "type": "boolean"
+                    },
+                    "rust-analyzer.testExplorer": {
+                        "markdownDescription": "Whether to show the test explorer.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "runnables",
+                "properties": {
+                    "rust-analyzer.runnables.extraEnv": {
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "array",
+                                "items": {
+                                    "type": "object",
+                                    "properties": {
+                                        "platform": {
+                                            "type": [
+                                                "null",
+                                                "string",
+                                                "array"
+                                            ],
+                                            "default": null,
+                                            "markdownDescription": "Platform(s) filter like \"win32\" or [\"linux\", \"win32\"]. See [process.platform](https://nodejs.org/api/process.html#processplatform) values."
+                                        },
+                                        "mask": {
+                                            "type": "string",
+                                            "description": "Runnable name mask"
+                                        },
+                                        "env": {
+                                            "type": "object",
+                                            "description": "Variables in form of { \"key\": \"value\"}"
+                                        }
                                     }
                                 }
+                            },
+                            {
+                                "type": "object",
+                                "description": "Variables in form of { \"key\": \"value\"}"
                             }
+                        ],
+                        "default": null,
+                        "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
+                    },
+                    "rust-analyzer.runnables.problemMatcher": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
                         },
-                        {
-                            "type": "object",
-                            "description": "Variables in form of { \"key\": \"value\"}"
-                        }
-                    ],
-                    "default": null,
-                    "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
-                },
-                "rust-analyzer.runnables.problemMatcher": {
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                        "default": [
+                            "$rustc"
+                        ],
+                        "markdownDescription": "Problem matchers to use for `rust-analyzer.run` command, eg `[\"$rustc\", \"$rust-panic\"]`."
+                    }
+                }
+            },
+            {
+                "title": "statusBar",
+                "properties": {
+                    "rust-analyzer.statusBar.clickAction": {
+                        "type": "string",
+                        "enum": [
+                            "stopServer",
+                            "openLogs"
+                        ],
+                        "enumDescriptions": [
+                            "Stop Server",
+                            "Open Logs"
+                        ],
+                        "default": "openLogs",
+                        "markdownDescription": "Action to run when clicking the extension status bar item."
+                    }
+                }
+            },
+            {
+                "title": "server",
+                "properties": {
+                    "rust-analyzer.server.path": {
+                        "type": [
+                            "null",
+                            "string"
+                        ],
+                        "scope": "machine-overridable",
+                        "default": null,
+                        "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)."
                     },
-                    "default": [
-                        "$rustc"
-                    ],
-                    "markdownDescription": "Problem matchers to use for `rust-analyzer.run` command, eg `[\"$rustc\", \"$rust-panic\"]`."
-                },
-                "rust-analyzer.statusBar.clickAction": {
-                    "type": "string",
-                    "enum": [
-                        "stopServer",
-                        "openLogs"
-                    ],
-                    "enumDescriptions": [
-                        "Stop Server",
-                        "Open Logs"
-                    ],
-                    "default": "openLogs",
-                    "markdownDescription": "Action to run when clicking the extension status bar item."
-                },
-                "rust-analyzer.server.path": {
-                    "type": [
-                        "null",
-                        "string"
-                    ],
-                    "scope": "machine-overridable",
-                    "default": null,
-                    "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)."
-                },
-                "rust-analyzer.server.extraEnv": {
-                    "type": [
-                        "null",
-                        "object"
-                    ],
-                    "additionalProperties": {
+                    "rust-analyzer.server.extraEnv": {
                         "type": [
-                            "string",
-                            "number"
+                            "null",
+                            "object"
+                        ],
+                        "additionalProperties": {
+                            "type": [
+                                "string",
+                                "number"
+                            ]
+                        },
+                        "default": null,
+                        "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
+                    }
+                }
+            },
+            {
+                "title": "trace",
+                "properties": {
+                    "rust-analyzer.trace.server": {
+                        "type": "string",
+                        "scope": "window",
+                        "enum": [
+                            "off",
+                            "messages",
+                            "verbose"
+                        ],
+                        "enumDescriptions": [
+                            "No traces",
+                            "Error only",
+                            "Full log"
+                        ],
+                        "default": "off",
+                        "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
+                    },
+                    "rust-analyzer.trace.extension": {
+                        "description": "Enable logging of VS Code extensions itself.",
+                        "type": "boolean",
+                        "default": false
+                    }
+                }
+            },
+            {
+                "title": "debug",
+                "properties": {
+                    "rust-analyzer.debug.engine": {
+                        "type": "string",
+                        "enum": [
+                            "auto",
+                            "vadimcn.vscode-lldb",
+                            "ms-vscode.cpptools"
+                        ],
+                        "default": "auto",
+                        "description": "Preferred debug engine.",
+                        "markdownEnumDescriptions": [
+                            "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
+                            "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
+                            "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
                         ]
                     },
-                    "default": null,
-                    "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
-                },
-                "rust-analyzer.trace.server": {
-                    "type": "string",
-                    "scope": "window",
-                    "enum": [
-                        "off",
-                        "messages",
-                        "verbose"
-                    ],
-                    "enumDescriptions": [
-                        "No traces",
-                        "Error only",
-                        "Full log"
-                    ],
-                    "default": "off",
-                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
-                },
-                "rust-analyzer.trace.extension": {
-                    "description": "Enable logging of VS Code extensions itself.",
-                    "type": "boolean",
-                    "default": false
-                },
-                "rust-analyzer.debug.engine": {
-                    "type": "string",
-                    "enum": [
-                        "auto",
-                        "vadimcn.vscode-lldb",
-                        "ms-vscode.cpptools"
-                    ],
-                    "default": "auto",
-                    "description": "Preferred debug engine.",
-                    "markdownEnumDescriptions": [
-                        "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
-                        "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
-                        "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
-                    ]
-                },
-                "rust-analyzer.debug.sourceFileMap": {
-                    "type": [
-                        "object",
-                        "string"
-                    ],
-                    "const": "auto",
-                    "description": "Optional source file mappings passed to the debug engine.",
-                    "default": {
-                        "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
+                    "rust-analyzer.debug.sourceFileMap": {
+                        "type": [
+                            "object",
+                            "string"
+                        ],
+                        "const": "auto",
+                        "description": "Optional source file mappings passed to the debug engine.",
+                        "default": {
+                            "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
+                        }
+                    },
+                    "rust-analyzer.debug.openDebugPane": {
+                        "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
+                        "type": "boolean",
+                        "default": false
+                    },
+                    "rust-analyzer.debug.engineSettings": {
+                        "type": "object",
+                        "default": {},
+                        "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
                     }
-                },
-                "rust-analyzer.debug.openDebugPane": {
-                    "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
-                    "type": "boolean",
-                    "default": false
-                },
-                "rust-analyzer.debug.engineSettings": {
-                    "type": "object",
-                    "default": {},
-                    "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
-                },
-                "rust-analyzer.restartServerOnConfigChange": {
-                    "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.typing.continueCommentsOnNewline": {
-                    "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.diagnostics.previewRustcOutput": {
-                    "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.diagnostics.useRustcErrorCode": {
-                    "markdownDescription": "Whether to show diagnostics using the original rustc error code. If this is false, all rustc diagnostics will have the code 'rustc(Click for full compiler diagnostics)'",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.discoverProjectRunner": {
-                    "markdownDescription": "Sets the extension responsible for determining which extension the rust-analyzer extension uses to generate `rust-project.json` files. This should should only be used\n if a build system like Buck or Bazel is also in use.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.showUnlinkedFileNotification": {
-                    "markdownDescription": "Whether to show a notification for unlinked files asking the user to add the corresponding Cargo.toml to the linked projects setting.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.showRequestFailedErrorNotification": {
-                    "markdownDescription": "Whether to show error notifications for failing requests.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.showDependenciesExplorer": {
-                    "markdownDescription": "Whether to show the dependencies view.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.testExplorer": {
-                    "markdownDescription": "Whether to show the test explorer.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "$generated-start": {},
-                "rust-analyzer.assist.emitMustUse": {
-                    "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.assist.expressionFillDefault": {
-                    "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
-                    "default": "todo",
-                    "type": "string",
-                    "enum": [
-                        "todo",
-                        "default"
-                    ],
-                    "enumDescriptions": [
-                        "Fill missing expressions with the `todo` macro",
-                        "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
-                    ]
-                },
-                "rust-analyzer.assist.termSearch.fuel": {
-                    "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).",
-                    "default": 400,
-                    "type": "integer",
-                    "minimum": 0
-                },
-                "rust-analyzer.cachePriming.enable": {
-                    "markdownDescription": "Warm up caches on project load.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cachePriming.numThreads": {
-                    "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
-                    "default": 0,
-                    "type": "number",
-                    "minimum": 0,
-                    "maximum": 255
-                },
-                "rust-analyzer.cargo.allTargets": {
-                    "markdownDescription": "Pass `--all-targets` to cargo invocation.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.autoreload": {
-                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.buildScripts.enable": {
-                    "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.buildScripts.invocationLocation": {
-                    "markdownDescription": "Specifies the working directory for running build scripts.\n- \"workspace\": run build scripts for a workspace in the workspace's root directory.\n    This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.\n- \"root\": run build scripts in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
-                    "default": "workspace",
-                    "type": "string",
-                    "enum": [
-                        "workspace",
-                        "root"
-                    ],
-                    "enumDescriptions": [
-                        "The command will be executed in the corresponding workspace root.",
-                        "The command will be executed in the project root."
-                    ]
-                },
-                "rust-analyzer.cargo.buildScripts.invocationStrategy": {
-                    "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
-                    "default": "per_workspace",
-                    "type": "string",
-                    "enum": [
-                        "per_workspace",
-                        "once"
-                    ],
-                    "enumDescriptions": [
-                        "The command will be executed for each workspace.",
-                        "The command will be executed once."
-                    ]
-                },
-                "rust-analyzer.cargo.buildScripts.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#` and\n`#rust-analyzer.cargo.buildScripts.invocationLocation#`.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "array"
-                    ],
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "typing",
+                "properties": {
+                    "rust-analyzer.typing.continueCommentsOnNewline": {
+                        "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
+                        "default": true,
+                        "type": "boolean"
                     }
-                },
-                "rust-analyzer.cargo.buildScripts.rebuildOnSave": {
-                    "markdownDescription": "Rerun proc-macros building/build-scripts running when proc-macro\nor build-script sources change and are saved.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
-                    "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.cfgs": {
-                    "markdownDescription": "List of cfg options to enable with the given values.",
-                    "default": {
-                        "debug_assertions": null,
-                        "miri": null
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.previewRustcOutput": {
+                        "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.",
+                        "default": false,
+                        "type": "boolean"
                     },
-                    "type": "object"
-                },
-                "rust-analyzer.cargo.extraArgs": {
-                    "markdownDescription": "Extra arguments that are passed to every cargo invocation.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                    "rust-analyzer.diagnostics.useRustcErrorCode": {
+                        "markdownDescription": "Whether to show diagnostics using the original rustc error code. If this is false, all rustc diagnostics will have the code 'rustc(Click for full compiler diagnostics)'",
+                        "default": false,
+                        "type": "boolean"
                     }
-                },
-                "rust-analyzer.cargo.extraEnv": {
-                    "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.",
-                    "default": {},
-                    "type": "object"
-                },
-                "rust-analyzer.cargo.features": {
-                    "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
-                    "default": [],
-                    "anyOf": [
-                        {
-                            "type": "string",
-                            "enum": [
-                                "all"
-                            ],
-                            "enumDescriptions": [
-                                "Pass `--all-features` to cargo"
-                            ]
-                        },
-                        {
-                            "type": "array",
-                            "items": {
-                                "type": "string"
+                }
+            },
+            {
+                "title": "$generated-start"
+            },
+            {
+                "title": "assist",
+                "properties": {
+                    "rust-analyzer.assist.emitMustUse": {
+                        "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "assist",
+                "properties": {
+                    "rust-analyzer.assist.expressionFillDefault": {
+                        "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
+                        "default": "todo",
+                        "type": "string",
+                        "enum": [
+                            "todo",
+                            "default"
+                        ],
+                        "enumDescriptions": [
+                            "Fill missing expressions with the `todo` macro",
+                            "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "assist",
+                "properties": {
+                    "rust-analyzer.assist.termSearch.fuel": {
+                        "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).",
+                        "default": 400,
+                        "type": "integer",
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "cachePriming",
+                "properties": {
+                    "rust-analyzer.cachePriming.enable": {
+                        "markdownDescription": "Warm up caches on project load.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cachePriming",
+                "properties": {
+                    "rust-analyzer.cachePriming.numThreads": {
+                        "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
+                        "default": "physical",
+                        "anyOf": [
+                            {
+                                "type": "number",
+                                "minimum": 0,
+                                "maximum": 255
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "physical",
+                                    "logical"
+                                ],
+                                "enumDescriptions": [
+                                    "Use the number of physical cores",
+                                    "Use the number of logical cores"
+                                ]
                             }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.allTargets": {
+                        "markdownDescription": "Pass `--all-targets` to cargo invocation.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.autoreload": {
+                        "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.enable": {
+                        "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.invocationLocation": {
+                        "markdownDescription": "Specifies the working directory for running build scripts.\n- \"workspace\": run build scripts for a workspace in the workspace's root directory.\n    This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.\n- \"root\": run build scripts in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                        "default": "workspace",
+                        "type": "string",
+                        "enum": [
+                            "workspace",
+                            "root"
+                        ],
+                        "enumDescriptions": [
+                            "The command will be executed in the corresponding workspace root.",
+                            "The command will be executed in the project root."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.invocationStrategy": {
+                        "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                        "default": "per_workspace",
+                        "type": "string",
+                        "enum": [
+                            "per_workspace",
+                            "once"
+                        ],
+                        "enumDescriptions": [
+                            "The command will be executed for each workspace.",
+                            "The command will be executed once."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.overrideCommand": {
+                        "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#` and\n`#rust-analyzer.cargo.buildScripts.invocationLocation#`.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "array"
+                        ],
+                        "items": {
+                            "type": "string"
                         }
-                    ]
-                },
-                "rust-analyzer.cargo.noDefaultFeatures": {
-                    "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.sysroot": {
-                    "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.",
-                    "default": "discover",
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.cargo.sysrootQueryMetadata": {
-                    "markdownDescription": "Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze\nthird-party dependencies of the standard libraries.\n\nThis will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer\nwill attempt to clean up afterwards, but nevertheless requires the location to be\nwritable to.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.cargo.sysrootSrc": {
-                    "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.cargo.target": {
-                    "markdownDescription": "Compilation target override (target triple).",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.cargo.targetDir": {
-                    "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` and initial build-script and proc-macro\nbuilding from locking the `Cargo.lock` at the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.",
-                    "default": null,
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
-                            "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.rebuildOnSave": {
+                        "markdownDescription": "Rerun proc-macros building/build-scripts running when proc-macro\nor build-script sources change and are saved.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
+                        "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.cfgs": {
+                        "markdownDescription": "List of cfg options to enable with the given values.",
+                        "default": {
+                            "debug_assertions": null,
+                            "miri": null
                         },
-                        {
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.extraArgs": {
+                        "markdownDescription": "Extra arguments that are passed to every cargo invocation.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
                             "type": "string"
                         }
-                    ]
-                },
-                "rust-analyzer.checkOnSave": {
-                    "markdownDescription": "Run the check command for diagnostics on save.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.check.allTargets": {
-                    "markdownDescription": "Check all targets and tests (`--all-targets`). Defaults to\n`#rust-analyzer.cargo.allTargets#`.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "boolean"
-                    ]
-                },
-                "rust-analyzer.check.command": {
-                    "markdownDescription": "Cargo command to use for `cargo check`.",
-                    "default": "check",
-                    "type": "string"
-                },
-                "rust-analyzer.check.extraArgs": {
-                    "markdownDescription": "Extra arguments for `cargo check`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
                     }
-                },
-                "rust-analyzer.check.extraEnv": {
-                    "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.",
-                    "default": {},
-                    "type": "object"
-                },
-                "rust-analyzer.check.features": {
-                    "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
-                    "default": null,
-                    "anyOf": [
-                        {
-                            "type": "string",
-                            "enum": [
-                                "all"
-                            ],
-                            "enumDescriptions": [
-                                "Pass `--all-features` to cargo"
-                            ]
-                        },
-                        {
-                            "type": "array",
-                            "items": {
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.extraEnv": {
+                        "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.",
+                        "default": {},
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.features": {
+                        "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
+                        "default": [],
+                        "anyOf": [
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "all"
+                                ],
+                                "enumDescriptions": [
+                                    "Pass `--all-features` to cargo"
+                                ]
+                            },
+                            {
+                                "type": "array",
+                                "items": {
+                                    "type": "string"
+                                }
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.noDefaultFeatures": {
+                        "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.sysroot": {
+                        "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                        "default": "discover",
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.sysrootQueryMetadata": {
+                        "markdownDescription": "Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze\nthird-party dependencies of the standard libraries.\n\nThis will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer\nwill attempt to clean up afterwards, but nevertheless requires the location to be\nwritable to.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.sysrootSrc": {
+                        "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.target": {
+                        "markdownDescription": "Compilation target override (target triple).",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "cargo",
+                "properties": {
+                    "rust-analyzer.cargo.targetDir": {
+                        "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` and initial build-script and proc-macro\nbuilding from locking the `Cargo.lock` at the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.",
+                        "default": null,
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "boolean"
+                            },
+                            {
                                 "type": "string"
                             }
-                        },
-                        {
-                            "type": "null"
-                        }
-                    ]
-                },
-                "rust-analyzer.check.ignore": {
-                    "markdownDescription": "List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore.\n\nFor example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,...",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
-                    },
-                    "uniqueItems": true
-                },
-                "rust-analyzer.check.invocationLocation": {
-                    "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n    This falls back to \"root\" if `#rust-analyzer.check.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.",
-                    "default": "workspace",
-                    "type": "string",
-                    "enum": [
-                        "workspace",
-                        "root"
-                    ],
-                    "enumDescriptions": [
-                        "The command will be executed in the corresponding workspace root.",
-                        "The command will be executed in the project root."
-                    ]
-                },
-                "rust-analyzer.check.invocationStrategy": {
-                    "markdownDescription": "Specifies the invocation strategy to use when running the check command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.",
-                    "default": "per_workspace",
-                    "type": "string",
-                    "enum": [
-                        "per_workspace",
-                        "once"
-                    ],
-                    "enumDescriptions": [
-                        "The command will be executed for each workspace.",
-                        "The command will be executed once."
-                    ]
-                },
-                "rust-analyzer.check.noDefaultFeatures": {
-                    "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "boolean"
-                    ]
-                },
-                "rust-analyzer.check.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "array"
-                    ],
-                    "items": {
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "general",
+                "properties": {
+                    "rust-analyzer.checkOnSave": {
+                        "markdownDescription": "Run the check command for diagnostics on save.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.allTargets": {
+                        "markdownDescription": "Check all targets and tests (`--all-targets`). Defaults to\n`#rust-analyzer.cargo.allTargets#`.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "boolean"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.command": {
+                        "markdownDescription": "Cargo command to use for `cargo check`.",
+                        "default": "check",
                         "type": "string"
                     }
-                },
-                "rust-analyzer.check.targets": {
-                    "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.",
-                    "default": null,
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.extraArgs": {
+                        "markdownDescription": "Extra arguments for `cargo check`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.extraEnv": {
+                        "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.",
+                        "default": {},
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.features": {
+                        "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
+                        "default": null,
+                        "anyOf": [
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "all"
+                                ],
+                                "enumDescriptions": [
+                                    "Pass `--all-features` to cargo"
+                                ]
+                            },
+                            {
+                                "type": "array",
+                                "items": {
+                                    "type": "string"
+                                }
+                            },
+                            {
+                                "type": "null"
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.ignore": {
+                        "markdownDescription": "List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore.\n\nFor example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,...",
+                        "default": [],
+                        "type": "array",
+                        "items": {
                             "type": "string"
                         },
-                        {
-                            "type": "array",
-                            "items": {
+                        "uniqueItems": true
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.invocationLocation": {
+                        "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n    This falls back to \"root\" if `#rust-analyzer.check.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.",
+                        "default": "workspace",
+                        "type": "string",
+                        "enum": [
+                            "workspace",
+                            "root"
+                        ],
+                        "enumDescriptions": [
+                            "The command will be executed in the corresponding workspace root.",
+                            "The command will be executed in the project root."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.invocationStrategy": {
+                        "markdownDescription": "Specifies the invocation strategy to use when running the check command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.",
+                        "default": "per_workspace",
+                        "type": "string",
+                        "enum": [
+                            "per_workspace",
+                            "once"
+                        ],
+                        "enumDescriptions": [
+                            "The command will be executed for each workspace.",
+                            "The command will be executed once."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.noDefaultFeatures": {
+                        "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "boolean"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.overrideCommand": {
+                        "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "array"
+                        ],
+                        "items": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.targets": {
+                        "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.",
+                        "default": null,
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
                                 "type": "string"
+                            },
+                            {
+                                "type": "array",
+                                "items": {
+                                    "type": "string"
+                                }
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "check",
+                "properties": {
+                    "rust-analyzer.check.workspace": {
+                        "markdownDescription": "Whether `--workspace` should be passed to `cargo check`.\nIf false, `-p <package>` will be passed instead.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.autoimport.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.autoself.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.callable.snippets": {
+                        "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.",
+                        "default": "fill_arguments",
+                        "type": "string",
+                        "enum": [
+                            "fill_arguments",
+                            "add_parentheses",
+                            "none"
+                        ],
+                        "enumDescriptions": [
+                            "Add call parentheses and pre-fill arguments.",
+                            "Add call parentheses.",
+                            "Do no snippet completions for callables."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.fullFunctionSignatures.enable": {
+                        "markdownDescription": "Whether to show full function/method signatures in completion docs.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.limit": {
+                        "markdownDescription": "Maximum number of completions to return. If `None`, the limit is infinite.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.postfix.enable": {
+                        "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.privateEditable.enable": {
+                        "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.snippets.custom": {
+                        "markdownDescription": "Custom completion snippets.",
+                        "default": {
+                            "Arc::new": {
+                                "postfix": "arc",
+                                "body": "Arc::new(${receiver})",
+                                "requires": "std::sync::Arc",
+                                "description": "Put the expression into an `Arc`",
+                                "scope": "expr"
+                            },
+                            "Rc::new": {
+                                "postfix": "rc",
+                                "body": "Rc::new(${receiver})",
+                                "requires": "std::rc::Rc",
+                                "description": "Put the expression into an `Rc`",
+                                "scope": "expr"
+                            },
+                            "Box::pin": {
+                                "postfix": "pinbox",
+                                "body": "Box::pin(${receiver})",
+                                "requires": "std::boxed::Box",
+                                "description": "Put the expression into a pinned `Box`",
+                                "scope": "expr"
+                            },
+                            "Ok": {
+                                "postfix": "ok",
+                                "body": "Ok(${receiver})",
+                                "description": "Wrap the expression in a `Result::Ok`",
+                                "scope": "expr"
+                            },
+                            "Err": {
+                                "postfix": "err",
+                                "body": "Err(${receiver})",
+                                "description": "Wrap the expression in a `Result::Err`",
+                                "scope": "expr"
+                            },
+                            "Some": {
+                                "postfix": "some",
+                                "body": "Some(${receiver})",
+                                "description": "Wrap the expression in an `Option::Some`",
+                                "scope": "expr"
                             }
-                        }
-                    ]
-                },
-                "rust-analyzer.check.workspace": {
-                    "markdownDescription": "Whether `--workspace` should be passed to `cargo check`.\nIf false, `-p <package>` will be passed instead.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.autoimport.enable": {
-                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.autoself.enable": {
-                    "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.callable.snippets": {
-                    "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.",
-                    "default": "fill_arguments",
-                    "type": "string",
-                    "enum": [
-                        "fill_arguments",
-                        "add_parentheses",
-                        "none"
-                    ],
-                    "enumDescriptions": [
-                        "Add call parentheses and pre-fill arguments.",
-                        "Add call parentheses.",
-                        "Do no snippet completions for callables."
-                    ]
-                },
-                "rust-analyzer.completion.fullFunctionSignatures.enable": {
-                    "markdownDescription": "Whether to show full function/method signatures in completion docs.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.limit": {
-                    "markdownDescription": "Maximum number of completions to return. If `None`, the limit is infinite.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.completion.postfix.enable": {
-                    "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.privateEditable.enable": {
-                    "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.snippets.custom": {
-                    "markdownDescription": "Custom completion snippets.",
-                    "default": {
-                        "Arc::new": {
-                            "postfix": "arc",
-                            "body": "Arc::new(${receiver})",
-                            "requires": "std::sync::Arc",
-                            "description": "Put the expression into an `Arc`",
-                            "scope": "expr"
-                        },
-                        "Rc::new": {
-                            "postfix": "rc",
-                            "body": "Rc::new(${receiver})",
-                            "requires": "std::rc::Rc",
-                            "description": "Put the expression into an `Rc`",
-                            "scope": "expr"
-                        },
-                        "Box::pin": {
-                            "postfix": "pinbox",
-                            "body": "Box::pin(${receiver})",
-                            "requires": "std::boxed::Box",
-                            "description": "Put the expression into a pinned `Box`",
-                            "scope": "expr"
-                        },
-                        "Ok": {
-                            "postfix": "ok",
-                            "body": "Ok(${receiver})",
-                            "description": "Wrap the expression in a `Result::Ok`",
-                            "scope": "expr"
                         },
-                        "Err": {
-                            "postfix": "err",
-                            "body": "Err(${receiver})",
-                            "description": "Wrap the expression in a `Result::Err`",
-                            "scope": "expr"
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.termSearch.enable": {
+                        "markdownDescription": "Whether to enable term search based snippets like `Some(foo.bar().baz())`.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.termSearch.fuel": {
+                        "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).",
+                        "default": 200,
+                        "type": "integer",
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.disabled": {
+                        "markdownDescription": "List of rust-analyzer diagnostics to disable.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
                         },
-                        "Some": {
-                            "postfix": "some",
-                            "body": "Some(${receiver})",
-                            "description": "Wrap the expression in an `Option::Some`",
-                            "scope": "expr"
+                        "uniqueItems": true
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.enable": {
+                        "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.experimental.enable": {
+                        "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.remapPrefix": {
+                        "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.",
+                        "default": {},
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.styleLints.enable": {
+                        "markdownDescription": "Whether to run additional style lints.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.warningsAsHint": {
+                        "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
                         }
-                    },
-                    "type": "object"
-                },
-                "rust-analyzer.completion.termSearch.enable": {
-                    "markdownDescription": "Whether to enable term search based snippets like `Some(foo.bar().baz())`.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.completion.termSearch.fuel": {
-                    "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).",
-                    "default": 200,
-                    "type": "integer",
-                    "minimum": 0
-                },
-                "rust-analyzer.diagnostics.disabled": {
-                    "markdownDescription": "List of rust-analyzer diagnostics to disable.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
-                    },
-                    "uniqueItems": true
-                },
-                "rust-analyzer.diagnostics.enable": {
-                    "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.diagnostics.experimental.enable": {
-                    "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.diagnostics.remapPrefix": {
-                    "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.",
-                    "default": {},
-                    "type": "object"
-                },
-                "rust-analyzer.diagnostics.styleLints.enable": {
-                    "markdownDescription": "Whether to run additional style lints.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.diagnostics.warningsAsHint": {
-                    "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
                     }
-                },
-                "rust-analyzer.diagnostics.warningsAsInfo": {
-                    "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "diagnostics",
+                "properties": {
+                    "rust-analyzer.diagnostics.warningsAsInfo": {
+                        "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
                     }
-                },
-                "rust-analyzer.files.excludeDirs": {
-                    "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "files",
+                "properties": {
+                    "rust-analyzer.files.excludeDirs": {
+                        "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
                     }
-                },
-                "rust-analyzer.files.watcher": {
-                    "markdownDescription": "Controls file watching implementation.",
-                    "default": "client",
-                    "type": "string",
-                    "enum": [
-                        "client",
-                        "server"
-                    ],
-                    "enumDescriptions": [
-                        "Use the client (editor) to watch files for changes",
-                        "Use server-side file watching"
-                    ]
-                },
-                "rust-analyzer.highlightRelated.breakPoints.enable": {
-                    "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.highlightRelated.closureCaptures.enable": {
-                    "markdownDescription": "Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.highlightRelated.exitPoints.enable": {
-                    "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.highlightRelated.references.enable": {
-                    "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.highlightRelated.yieldPoints.enable": {
-                    "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.debug.enable": {
-                    "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.enable": {
-                    "markdownDescription": "Whether to show HoverActions in Rust files.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.gotoTypeDef.enable": {
-                    "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.implementations.enable": {
-                    "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.references.enable": {
-                    "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.actions.run.enable": {
-                    "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.documentation.enable": {
-                    "markdownDescription": "Whether to show documentation on hover.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.documentation.keywords.enable": {
-                    "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.links.enable": {
-                    "markdownDescription": "Use markdown syntax for links on hover.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.memoryLayout.alignment": {
-                    "markdownDescription": "How to render the align information in a memory layout hover.",
-                    "default": "hexadecimal",
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
-                            "type": "string",
-                            "enum": [
-                                "both",
-                                "decimal",
-                                "hexadecimal"
-                            ],
-                            "enumDescriptions": [
-                                "Render as 12 (0xC)",
-                                "Render as 12",
-                                "Render as 0xC"
+                }
+            },
+            {
+                "title": "files",
+                "properties": {
+                    "rust-analyzer.files.watcher": {
+                        "markdownDescription": "Controls file watching implementation.",
+                        "default": "client",
+                        "type": "string",
+                        "enum": [
+                            "client",
+                            "server"
+                        ],
+                        "enumDescriptions": [
+                            "Use the client (editor) to watch files for changes",
+                            "Use server-side file watching"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
+                    "rust-analyzer.highlightRelated.breakPoints.enable": {
+                        "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
+                    "rust-analyzer.highlightRelated.closureCaptures.enable": {
+                        "markdownDescription": "Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
+                    "rust-analyzer.highlightRelated.exitPoints.enable": {
+                        "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
+                    "rust-analyzer.highlightRelated.references.enable": {
+                        "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
+                    "rust-analyzer.highlightRelated.yieldPoints.enable": {
+                        "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.debug.enable": {
+                        "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.enable": {
+                        "markdownDescription": "Whether to show HoverActions in Rust files.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.gotoTypeDef.enable": {
+                        "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.implementations.enable": {
+                        "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.references.enable": {
+                        "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.actions.run.enable": {
+                        "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.documentation.enable": {
+                        "markdownDescription": "Whether to show documentation on hover.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.documentation.keywords.enable": {
+                        "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.links.enable": {
+                        "markdownDescription": "Use markdown syntax for links on hover.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.memoryLayout.alignment": {
+                        "markdownDescription": "How to render the align information in a memory layout hover.",
+                        "default": "hexadecimal",
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "both",
+                                    "decimal",
+                                    "hexadecimal"
+                                ],
+                                "enumDescriptions": [
+                                    "Render as 12 (0xC)",
+                                    "Render as 12",
+                                    "Render as 0xC"
+                                ]
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.memoryLayout.enable": {
+                        "markdownDescription": "Whether to show memory layout data on hover.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.memoryLayout.niches": {
+                        "markdownDescription": "How to render the niche information in a memory layout hover.",
+                        "default": false,
+                        "type": [
+                            "null",
+                            "boolean"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.memoryLayout.offset": {
+                        "markdownDescription": "How to render the offset information in a memory layout hover.",
+                        "default": "hexadecimal",
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "both",
+                                    "decimal",
+                                    "hexadecimal"
+                                ],
+                                "enumDescriptions": [
+                                    "Render as 12 (0xC)",
+                                    "Render as 12",
+                                    "Render as 0xC"
+                                ]
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.memoryLayout.size": {
+                        "markdownDescription": "How to render the size information in a memory layout hover.",
+                        "default": "both",
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "both",
+                                    "decimal",
+                                    "hexadecimal"
+                                ],
+                                "enumDescriptions": [
+                                    "Render as 12 (0xC)",
+                                    "Render as 12",
+                                    "Render as 0xC"
+                                ]
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.show.enumVariants": {
+                        "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.",
+                        "default": 5,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.show.fields": {
+                        "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.",
+                        "default": 5,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
+                    "rust-analyzer.hover.show.traitAssocItems": {
+                        "markdownDescription": "How many associated items of a trait to display when hovering a trait.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.granularity.enforce": {
+                        "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.granularity.group": {
+                        "markdownDescription": "How imports should be grouped into use statements.",
+                        "default": "crate",
+                        "type": "string",
+                        "enum": [
+                            "preserve",
+                            "crate",
+                            "module",
+                            "item",
+                            "one"
+                        ],
+                        "enumDescriptions": [
+                            "Do not change the granularity of any imports and preserve the original structure written by the developer.",
+                            "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
+                            "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
+                            "Flatten imports so that each has its own use statement.",
+                            "Merge all imports into a single use statement as long as they have the same visibility and attributes."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.group.enable": {
+                        "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.merge.glob": {
+                        "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.preferNoStd": {
+                        "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.preferPrelude": {
+                        "markdownDescription": "Whether to prefer import paths containing a `prelude` module.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "imports",
+                "properties": {
+                    "rust-analyzer.imports.prefix": {
+                        "markdownDescription": "The path structure for newly inserted paths to use.",
+                        "default": "plain",
+                        "type": "string",
+                        "enum": [
+                            "plain",
+                            "self",
+                            "crate"
+                        ],
+                        "enumDescriptions": [
+                            "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
+                            "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
+                            "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.bindingModeHints.enable": {
+                        "markdownDescription": "Whether to show inlay type hints for binding modes.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.chainingHints.enable": {
+                        "markdownDescription": "Whether to show inlay type hints for method chains.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.closingBraceHints.enable": {
+                        "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.closingBraceHints.minLines": {
+                        "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
+                        "default": 25,
+                        "type": "integer",
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.closureCaptureHints.enable": {
+                        "markdownDescription": "Whether to show inlay hints for closure captures.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
+                        "markdownDescription": "Whether to show inlay type hints for return types of closures.",
+                        "default": "never",
+                        "type": "string",
+                        "enum": [
+                            "always",
+                            "never",
+                            "with_block"
+                        ],
+                        "enumDescriptions": [
+                            "Always show type hints for return types of closures.",
+                            "Never show type hints for return types of closures.",
+                            "Only show type hints for return types of closures with blocks."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.closureStyle": {
+                        "markdownDescription": "Closure notation in type and chaining inlay hints.",
+                        "default": "impl_fn",
+                        "type": "string",
+                        "enum": [
+                            "impl_fn",
+                            "rust_analyzer",
+                            "with_id",
+                            "hide"
+                        ],
+                        "enumDescriptions": [
+                            "`impl_fn`: `impl FnMut(i32, u64) -> i8`",
+                            "`rust_analyzer`: `|i32, u64| -> i8`",
+                            "`with_id`: `{closure#14352}`, where that id is the unique number of the closure in r-a internals",
+                            "`hide`: Shows `...` for every closure type"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.discriminantHints.enable": {
+                        "markdownDescription": "Whether to show enum variant discriminant hints.",
+                        "default": "never",
+                        "type": "string",
+                        "enum": [
+                            "always",
+                            "never",
+                            "fieldless"
+                        ],
+                        "enumDescriptions": [
+                            "Always show all discriminant hints.",
+                            "Never show discriminant hints.",
+                            "Only show discriminant hints on fieldless enum variants."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
+                        "markdownDescription": "Whether to show inlay hints for type adjustments.",
+                        "default": "never",
+                        "type": "string",
+                        "enum": [
+                            "always",
+                            "never",
+                            "reborrow"
+                        ],
+                        "enumDescriptions": [
+                            "Always show all adjustment hints.",
+                            "Never show adjustment hints.",
+                            "Only show auto borrow and dereference adjustment hints."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": {
+                        "markdownDescription": "Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": {
+                        "markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).",
+                        "default": "prefix",
+                        "type": "string",
+                        "enum": [
+                            "prefix",
+                            "postfix",
+                            "prefer_prefix",
+                            "prefer_postfix"
+                        ],
+                        "enumDescriptions": [
+                            "Always show adjustment hints as prefix (`*expr`).",
+                            "Always show adjustment hints as postfix (`expr.*`).",
+                            "Show prefix or postfix depending on which uses less parenthesis, preferring prefix.",
+                            "Show prefix or postfix depending on which uses less parenthesis, preferring postfix."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.implicitDrops.enable": {
+                        "markdownDescription": "Whether to show implicit drop hints.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
+                        "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
+                        "default": "never",
+                        "type": "string",
+                        "enum": [
+                            "always",
+                            "never",
+                            "skip_trivial"
+                        ],
+                        "enumDescriptions": [
+                            "Always show lifetime elision hints.",
+                            "Never show lifetime elision hints.",
+                            "Only show lifetime elision hints if a return type is involved."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": {
+                        "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.maxLength": {
+                        "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
+                        "default": 25,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.parameterHints.enable": {
+                        "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.rangeExclusiveHints.enable": {
+                        "markdownDescription": "Whether to show exclusive range inlay hints.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.reborrowHints.enable": {
+                        "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.",
+                        "default": "never",
+                        "type": "string",
+                        "enum": [
+                            "always",
+                            "never",
+                            "mutable"
+                        ],
+                        "enumDescriptions": [
+                            "Always show reborrow hints.",
+                            "Never show reborrow hints.",
+                            "Only show mutable reborrow hints."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.renderColons": {
+                        "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.typeHints.enable": {
+                        "markdownDescription": "Whether to show inlay type hints for variables.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
+                        "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
+                        "markdownDescription": "Whether to hide inlay type hints for constructors.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "interpret",
+                "properties": {
+                    "rust-analyzer.interpret.tests": {
+                        "markdownDescription": "Enables the experimental support for interpreting tests.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "joinLines",
+                "properties": {
+                    "rust-analyzer.joinLines.joinAssignments": {
+                        "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "joinLines",
+                "properties": {
+                    "rust-analyzer.joinLines.joinElseIf": {
+                        "markdownDescription": "Join lines inserts else between consecutive ifs.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "joinLines",
+                "properties": {
+                    "rust-analyzer.joinLines.removeTrailingComma": {
+                        "markdownDescription": "Join lines removes trailing commas.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "joinLines",
+                "properties": {
+                    "rust-analyzer.joinLines.unwrapTrivialBlock": {
+                        "markdownDescription": "Join lines unwraps trivial blocks.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.debug.enable": {
+                        "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.enable": {
+                        "markdownDescription": "Whether to show CodeLens in Rust files.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.forceCustomCommands": {
+                        "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.implementations.enable": {
+                        "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.location": {
+                        "markdownDescription": "Where to render annotations.",
+                        "default": "above_name",
+                        "type": "string",
+                        "enum": [
+                            "above_name",
+                            "above_whole_item"
+                        ],
+                        "enumDescriptions": [
+                            "Render annotations above the name of the item.",
+                            "Render annotations above the whole item, including documentation comments and attributes."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.references.adt.enable": {
+                        "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.references.enumVariant.enable": {
+                        "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.references.method.enable": {
+                        "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.references.trait.enable": {
+                        "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "lens",
+                "properties": {
+                    "rust-analyzer.lens.run.enable": {
+                        "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "general",
+                "properties": {
+                    "rust-analyzer.linkedProjects": {
+                        "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": [
+                                "string",
+                                "object"
                             ]
                         }
-                    ]
-                },
-                "rust-analyzer.hover.memoryLayout.enable": {
-                    "markdownDescription": "Whether to show memory layout data on hover.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.hover.memoryLayout.niches": {
-                    "markdownDescription": "How to render the niche information in a memory layout hover.",
-                    "default": false,
-                    "type": [
-                        "null",
-                        "boolean"
-                    ]
-                },
-                "rust-analyzer.hover.memoryLayout.offset": {
-                    "markdownDescription": "How to render the offset information in a memory layout hover.",
-                    "default": "hexadecimal",
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
-                            "type": "string",
-                            "enum": [
-                                "both",
-                                "decimal",
-                                "hexadecimal"
-                            ],
-                            "enumDescriptions": [
-                                "Render as 12 (0xC)",
-                                "Render as 12",
-                                "Render as 0xC"
-                            ]
+                    }
+                }
+            },
+            {
+                "title": "lru",
+                "properties": {
+                    "rust-analyzer.lru.capacity": {
+                        "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "lru",
+                "properties": {
+                    "rust-analyzer.lru.query.capacities": {
+                        "markdownDescription": "Sets the LRU capacity of the specified queries.",
+                        "default": {},
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "notifications",
+                "properties": {
+                    "rust-analyzer.notifications.cargoTomlNotFound": {
+                        "markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "notifications",
+                "properties": {
+                    "rust-analyzer.notifications.unindexedProject": {
+                        "markdownDescription": "Whether to send an UnindexedProject notification to the client.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "general",
+                "properties": {
+                    "rust-analyzer.numThreads": {
+                        "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.",
+                        "default": null,
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "number",
+                                "minimum": 0,
+                                "maximum": 255
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "physical",
+                                    "logical"
+                                ],
+                                "enumDescriptions": [
+                                    "Use the number of physical cores",
+                                    "Use the number of logical cores"
+                                ]
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "procMacro",
+                "properties": {
+                    "rust-analyzer.procMacro.attributes.enable": {
+                        "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "procMacro",
+                "properties": {
+                    "rust-analyzer.procMacro.enable": {
+                        "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "procMacro",
+                "properties": {
+                    "rust-analyzer.procMacro.ignored": {
+                        "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
+                        "default": {},
+                        "type": "object"
+                    }
+                }
+            },
+            {
+                "title": "procMacro",
+                "properties": {
+                    "rust-analyzer.procMacro.server": {
+                        "markdownDescription": "Internal config, path to proc-macro server executable.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "references",
+                "properties": {
+                    "rust-analyzer.references.excludeImports": {
+                        "markdownDescription": "Exclude imports from find-all-references.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "references",
+                "properties": {
+                    "rust-analyzer.references.excludeTests": {
+                        "markdownDescription": "Exclude tests from find-all-references.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "runnables",
+                "properties": {
+                    "rust-analyzer.runnables.command": {
+                        "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "runnables",
+                "properties": {
+                    "rust-analyzer.runnables.extraArgs": {
+                        "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
                         }
-                    ]
-                },
-                "rust-analyzer.hover.memoryLayout.size": {
-                    "markdownDescription": "How to render the size information in a memory layout hover.",
-                    "default": "both",
-                    "anyOf": [
-                        {
-                            "type": "null"
-                        },
-                        {
-                            "type": "string",
-                            "enum": [
-                                "both",
-                                "decimal",
-                                "hexadecimal"
-                            ],
-                            "enumDescriptions": [
-                                "Render as 12 (0xC)",
-                                "Render as 12",
-                                "Render as 0xC"
-                            ]
+                    }
+                }
+            },
+            {
+                "title": "runnables",
+                "properties": {
+                    "rust-analyzer.runnables.extraTestBinaryArgs": {
+                        "markdownDescription": "Additional arguments to be passed through Cargo to launched tests, benchmarks, or\ndoc-tests.\n\nUnless the launched target uses a\n[custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),\nthey will end up being interpreted as options to\n[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).",
+                        "default": [
+                            "--show-output"
+                        ],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
                         }
-                    ]
-                },
-                "rust-analyzer.hover.show.enumVariants": {
-                    "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.",
-                    "default": 5,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.hover.show.fields": {
-                    "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.",
-                    "default": 5,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.hover.show.traitAssocItems": {
-                    "markdownDescription": "How many associated items of a trait to display when hovering a trait.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.imports.granularity.enforce": {
-                    "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.imports.granularity.group": {
-                    "markdownDescription": "How imports should be grouped into use statements.",
-                    "default": "crate",
-                    "type": "string",
-                    "enum": [
-                        "preserve",
-                        "crate",
-                        "module",
-                        "item",
-                        "one"
-                    ],
-                    "enumDescriptions": [
-                        "Do not change the granularity of any imports and preserve the original structure written by the developer.",
-                        "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
-                        "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
-                        "Flatten imports so that each has its own use statement.",
-                        "Merge all imports into a single use statement as long as they have the same visibility and attributes."
-                    ]
-                },
-                "rust-analyzer.imports.group.enable": {
-                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.imports.merge.glob": {
-                    "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.imports.preferNoStd": {
-                    "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.imports.preferPrelude": {
-                    "markdownDescription": "Whether to prefer import paths containing a `prelude` module.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.imports.prefix": {
-                    "markdownDescription": "The path structure for newly inserted paths to use.",
-                    "default": "plain",
-                    "type": "string",
-                    "enum": [
-                        "plain",
-                        "self",
-                        "crate"
-                    ],
-                    "enumDescriptions": [
-                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
-                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
-                        "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
-                    ]
-                },
-                "rust-analyzer.inlayHints.bindingModeHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for binding modes.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.chainingHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for method chains.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.closingBraceHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.closingBraceHints.minLines": {
-                    "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
-                    "default": 25,
-                    "type": "integer",
-                    "minimum": 0
-                },
-                "rust-analyzer.inlayHints.closureCaptureHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints for closure captures.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for return types of closures.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "with_block"
-                    ],
-                    "enumDescriptions": [
-                        "Always show type hints for return types of closures.",
-                        "Never show type hints for return types of closures.",
-                        "Only show type hints for return types of closures with blocks."
-                    ]
-                },
-                "rust-analyzer.inlayHints.closureStyle": {
-                    "markdownDescription": "Closure notation in type and chaining inlay hints.",
-                    "default": "impl_fn",
-                    "type": "string",
-                    "enum": [
-                        "impl_fn",
-                        "rust_analyzer",
-                        "with_id",
-                        "hide"
-                    ],
-                    "enumDescriptions": [
-                        "`impl_fn`: `impl FnMut(i32, u64) -> i8`",
-                        "`rust_analyzer`: `|i32, u64| -> i8`",
-                        "`with_id`: `{closure#14352}`, where that id is the unique number of the closure in r-a internals",
-                        "`hide`: Shows `...` for every closure type"
-                    ]
-                },
-                "rust-analyzer.inlayHints.discriminantHints.enable": {
-                    "markdownDescription": "Whether to show enum variant discriminant hints.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "fieldless"
-                    ],
-                    "enumDescriptions": [
-                        "Always show all discriminant hints.",
-                        "Never show discriminant hints.",
-                        "Only show discriminant hints on fieldless enum variants."
-                    ]
-                },
-                "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints for type adjustments.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "reborrow"
-                    ],
-                    "enumDescriptions": [
-                        "Always show all adjustment hints.",
-                        "Never show adjustment hints.",
-                        "Only show auto borrow and dereference adjustment hints."
-                    ]
-                },
-                "rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": {
-                    "markdownDescription": "Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": {
-                    "markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).",
-                    "default": "prefix",
-                    "type": "string",
-                    "enum": [
-                        "prefix",
-                        "postfix",
-                        "prefer_prefix",
-                        "prefer_postfix"
-                    ],
-                    "enumDescriptions": [
-                        "Always show adjustment hints as prefix (`*expr`).",
-                        "Always show adjustment hints as postfix (`expr.*`).",
-                        "Show prefix or postfix depending on which uses less parenthesis, preferring prefix.",
-                        "Show prefix or postfix depending on which uses less parenthesis, preferring postfix."
-                    ]
-                },
-                "rust-analyzer.inlayHints.implicitDrops.enable": {
-                    "markdownDescription": "Whether to show implicit drop hints.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "skip_trivial"
-                    ],
-                    "enumDescriptions": [
-                        "Always show lifetime elision hints.",
-                        "Never show lifetime elision hints.",
-                        "Only show lifetime elision hints if a return type is involved."
-                    ]
-                },
-                "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": {
-                    "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.maxLength": {
-                    "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
-                    "default": 25,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.inlayHints.parameterHints.enable": {
-                    "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.rangeExclusiveHints.enable": {
-                    "markdownDescription": "Whether to show exclusive range inlay hints.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.reborrowHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "mutable"
-                    ],
-                    "enumDescriptions": [
-                        "Always show reborrow hints.",
-                        "Never show reborrow hints.",
-                        "Only show mutable reborrow hints."
-                    ]
-                },
-                "rust-analyzer.inlayHints.renderColons": {
-                    "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.typeHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for variables.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
-                    "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
-                    "markdownDescription": "Whether to hide inlay type hints for constructors.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.interpret.tests": {
-                    "markdownDescription": "Enables the experimental support for interpreting tests.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.joinLines.joinAssignments": {
-                    "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.joinLines.joinElseIf": {
-                    "markdownDescription": "Join lines inserts else between consecutive ifs.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.joinLines.removeTrailingComma": {
-                    "markdownDescription": "Join lines removes trailing commas.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.joinLines.unwrapTrivialBlock": {
-                    "markdownDescription": "Join lines unwraps trivial blocks.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.debug.enable": {
-                    "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.enable": {
-                    "markdownDescription": "Whether to show CodeLens in Rust files.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.forceCustomCommands": {
-                    "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.implementations.enable": {
-                    "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.location": {
-                    "markdownDescription": "Where to render annotations.",
-                    "default": "above_name",
-                    "type": "string",
-                    "enum": [
-                        "above_name",
-                        "above_whole_item"
-                    ],
-                    "enumDescriptions": [
-                        "Render annotations above the name of the item.",
-                        "Render annotations above the whole item, including documentation comments and attributes."
-                    ]
-                },
-                "rust-analyzer.lens.references.adt.enable": {
-                    "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.references.enumVariant.enable": {
-                    "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.references.method.enable": {
-                    "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.references.trait.enable": {
-                    "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.lens.run.enable": {
-                    "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.linkedProjects": {
-                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
+                    }
+                }
+            },
+            {
+                "title": "rustc",
+                "properties": {
+                    "rust-analyzer.rustc.source": {
+                        "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                        "default": null,
                         "type": [
-                            "string",
-                            "object"
+                            "null",
+                            "string"
                         ]
                     }
-                },
-                "rust-analyzer.lru.capacity": {
-                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.lru.query.capacities": {
-                    "markdownDescription": "Sets the LRU capacity of the specified queries.",
-                    "default": {},
-                    "type": "object"
-                },
-                "rust-analyzer.notifications.cargoTomlNotFound": {
-                    "markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.notifications.unindexedProject": {
-                    "markdownDescription": "Whether to send an UnindexedProject notification to the client.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.numThreads": {
-                    "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "integer"
-                    ],
-                    "minimum": 0
-                },
-                "rust-analyzer.procMacro.attributes.enable": {
-                    "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.procMacro.enable": {
-                    "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.procMacro.ignored": {
-                    "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
-                    "default": {},
-                    "type": "object"
-                },
-                "rust-analyzer.procMacro.server": {
-                    "markdownDescription": "Internal config, path to proc-macro server executable.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.references.excludeImports": {
-                    "markdownDescription": "Exclude imports from find-all-references.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.references.excludeTests": {
-                    "markdownDescription": "Exclude tests from find-all-references.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.runnables.command": {
-                    "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.runnables.extraArgs": {
-                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "rustfmt",
+                "properties": {
+                    "rust-analyzer.rustfmt.extraArgs": {
+                        "markdownDescription": "Additional arguments to `rustfmt`.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
                     }
-                },
-                "rust-analyzer.runnables.extraTestBinaryArgs": {
-                    "markdownDescription": "Additional arguments to be passed through Cargo to launched tests, benchmarks, or\ndoc-tests.\n\nUnless the launched target uses a\n[custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),\nthey will end up being interpreted as options to\n[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).",
-                    "default": [
-                        "--show-output"
-                    ],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "rustfmt",
+                "properties": {
+                    "rust-analyzer.rustfmt.overrideCommand": {
+                        "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting. This should be the equivalent of `rustfmt` here, and\nnot that of `cargo fmt`. The file contents will be passed on the\nstandard input and the formatted result will be read from the\nstandard output.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "array"
+                        ],
+                        "items": {
+                            "type": "string"
+                        }
                     }
-                },
-                "rust-analyzer.rustc.source": {
-                    "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
-                    ]
-                },
-                "rust-analyzer.rustfmt.extraArgs": {
-                    "markdownDescription": "Additional arguments to `rustfmt`.",
-                    "default": [],
-                    "type": "array",
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "rustfmt",
+                "properties": {
+                    "rust-analyzer.rustfmt.rangeFormatting.enable": {
+                        "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
+                        "default": false,
+                        "type": "boolean"
                     }
-                },
-                "rust-analyzer.rustfmt.overrideCommand": {
-                    "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting. This should be the equivalent of `rustfmt` here, and\nnot that of `cargo fmt`. The file contents will be passed on the\nstandard input and the formatted result will be read from the\nstandard output.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "array"
-                    ],
-                    "items": {
-                        "type": "string"
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": {
+                        "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.",
+                        "default": true,
+                        "type": "boolean"
                     }
-                },
-                "rust-analyzer.rustfmt.rangeFormatting.enable": {
-                    "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": {
-                    "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.nonStandardTokens": {
-                    "markdownDescription": "Whether the server is allowed to emit non-standard tokens and modifiers.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.operator.enable": {
-                    "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.operator.specialization.enable": {
-                    "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.punctuation.enable": {
-                    "markdownDescription": "Use semantic tokens for punctuation.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": {
-                    "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": {
-                    "markdownDescription": "Use specialized semantic tokens for punctuation.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.semanticHighlighting.strings.enable": {
-                    "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.signatureInfo.detail": {
-                    "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.",
-                    "default": "full",
-                    "type": "string",
-                    "enum": [
-                        "full",
-                        "parameters"
-                    ],
-                    "enumDescriptions": [
-                        "Show the entire signature.",
-                        "Show only the parameters."
-                    ]
-                },
-                "rust-analyzer.signatureInfo.documentation.enable": {
-                    "markdownDescription": "Show documentation.",
-                    "default": true,
-                    "type": "boolean"
-                },
-                "rust-analyzer.typing.autoClosingAngleBrackets.enable": {
-                    "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.",
-                    "default": false,
-                    "type": "boolean"
-                },
-                "rust-analyzer.workspace.symbol.search.kind": {
-                    "markdownDescription": "Workspace symbol search kind.",
-                    "default": "only_types",
-                    "type": "string",
-                    "enum": [
-                        "only_types",
-                        "all_symbols"
-                    ],
-                    "enumDescriptions": [
-                        "Search for types only.",
-                        "Search for all symbols kinds."
-                    ]
-                },
-                "rust-analyzer.workspace.symbol.search.limit": {
-                    "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.",
-                    "default": 128,
-                    "type": "integer",
-                    "minimum": 0
-                },
-                "rust-analyzer.workspace.symbol.search.scope": {
-                    "markdownDescription": "Workspace symbol search scope.",
-                    "default": "workspace",
-                    "type": "string",
-                    "enum": [
-                        "workspace",
-                        "workspace_and_dependencies"
-                    ],
-                    "enumDescriptions": [
-                        "Search in current workspace only.",
-                        "Search in current workspace and dependencies."
-                    ]
-                },
-                "$generated-end": {}
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.nonStandardTokens": {
+                        "markdownDescription": "Whether the server is allowed to emit non-standard tokens and modifiers.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.operator.enable": {
+                        "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.operator.specialization.enable": {
+                        "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.punctuation.enable": {
+                        "markdownDescription": "Use semantic tokens for punctuation.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": {
+                        "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": {
+                        "markdownDescription": "Use specialized semantic tokens for punctuation.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "semanticHighlighting",
+                "properties": {
+                    "rust-analyzer.semanticHighlighting.strings.enable": {
+                        "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "signatureInfo",
+                "properties": {
+                    "rust-analyzer.signatureInfo.detail": {
+                        "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.",
+                        "default": "full",
+                        "type": "string",
+                        "enum": [
+                            "full",
+                            "parameters"
+                        ],
+                        "enumDescriptions": [
+                            "Show the entire signature.",
+                            "Show only the parameters."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "signatureInfo",
+                "properties": {
+                    "rust-analyzer.signatureInfo.documentation.enable": {
+                        "markdownDescription": "Show documentation.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "typing",
+                "properties": {
+                    "rust-analyzer.typing.autoClosingAngleBrackets.enable": {
+                        "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "workspace",
+                "properties": {
+                    "rust-analyzer.workspace.symbol.search.kind": {
+                        "markdownDescription": "Workspace symbol search kind.",
+                        "default": "only_types",
+                        "type": "string",
+                        "enum": [
+                            "only_types",
+                            "all_symbols"
+                        ],
+                        "enumDescriptions": [
+                            "Search for types only.",
+                            "Search for all symbols kinds."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "workspace",
+                "properties": {
+                    "rust-analyzer.workspace.symbol.search.limit": {
+                        "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.",
+                        "default": 128,
+                        "type": "integer",
+                        "minimum": 0
+                    }
+                }
+            },
+            {
+                "title": "workspace",
+                "properties": {
+                    "rust-analyzer.workspace.symbol.search.scope": {
+                        "markdownDescription": "Workspace symbol search scope.",
+                        "default": "workspace",
+                        "type": "string",
+                        "enum": [
+                            "workspace",
+                            "workspace_and_dependencies"
+                        ],
+                        "enumDescriptions": [
+                            "Search in current workspace only.",
+                            "Search in current workspace and dependencies."
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "$generated-end"
             }
-        },
+        ],
         "configurationDefaults": {
             "explorer.fileNesting.patterns": {
                 "Cargo.toml": "Cargo.lock"
@@ -2282,6 +3128,10 @@
                 {
                     "command": "rust-analyzer.viewMemoryLayout",
                     "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.toggleLSPLogs",
+                    "when": "inRustProject"
                 }
             ],
             "editor/context": [
diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
index 688c53a9b1f..35b705c477e 100644
--- a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
@@ -1,8 +1,7 @@
 import * as vscode from "vscode";
 
 import type { Ctx, Disposable } from "./ctx";
-import { type RustEditor, isRustEditor } from "./util";
-import { unwrapUndefinable } from "./undefinable";
+import { type RustEditor, isRustEditor, unwrapUndefinable } from "./util";
 
 // FIXME: consider implementing this via the Tree View API?
 // https://code.visualstudio.com/api/extension-guides/tree-view
diff --git a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts
index 6cf399599d9..5a92b285ae6 100644
--- a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts
+++ b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts
@@ -1,9 +1,9 @@
 import * as vscode from "vscode";
 import * as os from "os";
 import type { Config } from "./config";
-import { log, isValidExecutable } from "./util";
+import { type Env, log } from "./util";
 import type { PersistentState } from "./persistent_state";
-import { exec } from "child_process";
+import { exec, spawnSync } from "child_process";
 
 export async function bootstrap(
     context: vscode.ExtensionContext,
@@ -13,7 +13,7 @@ export async function bootstrap(
     const path = await getServer(context, config, state);
     if (!path) {
         throw new Error(
-            "Rust Analyzer Language Server is not available. " +
+            "rust-analyzer Language Server is not available. " +
                 "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation).",
         );
     }
@@ -21,12 +21,12 @@ export async function bootstrap(
     log.info("Using server binary at", path);
 
     if (!isValidExecutable(path, config.serverExtraEnv)) {
-        if (config.serverPath) {
-            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
-            Consider removing this config or making a valid server binary available at that path.`);
-        } else {
-            throw new Error(`Failed to execute ${path} --version`);
-        }
+        throw new Error(
+            `Failed to execute ${path} --version.` + config.serverPath
+                ? `\`config.server.path\` or \`config.serverPath\` has been set explicitly.\
+            Consider removing this config or making a valid server binary available at that path.`
+                : "",
+        );
     }
 
     return path;
@@ -54,27 +54,12 @@ async function getServer(
     if (bundledExists) {
         let server = bundled;
         if (await isNixOs()) {
-            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
-            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
-            let exists = await vscode.workspace.fs.stat(dest).then(
-                () => true,
-                () => false,
-            );
-            if (exists && config.package.version !== state.serverVersion) {
-                await vscode.workspace.fs.delete(dest);
-                exists = false;
-            }
-            if (!exists) {
-                await vscode.workspace.fs.copy(bundled, dest);
-                await patchelf(dest);
-            }
-            server = dest;
+            server = await getNixOsServer(config, ext, state, bundled, server);
+            await state.updateServerVersion(config.package.version);
         }
-        await state.updateServerVersion(config.package.version);
         return server.fsPath;
     }
 
-    await state.updateServerVersion(undefined);
     await vscode.window.showErrorMessage(
         "Unfortunately we don't ship binaries for your platform yet. " +
             "You need to manually clone the rust-analyzer repository and " +
@@ -86,6 +71,45 @@ async function getServer(
     return undefined;
 }
 
+export function isValidExecutable(path: string, extraEnv: Env): boolean {
+    log.debug("Checking availability of a binary at", path);
+
+    const res = spawnSync(path, ["--version"], {
+        encoding: "utf8",
+        env: { ...process.env, ...extraEnv },
+    });
+
+    const printOutput = res.error ? log.warn : log.info;
+    printOutput(path, "--version:", res);
+
+    return res.status === 0;
+}
+
+async function getNixOsServer(
+    config: Config,
+    ext: string,
+    state: PersistentState,
+    bundled: vscode.Uri,
+    server: vscode.Uri,
+) {
+    await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
+    const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
+    let exists = await vscode.workspace.fs.stat(dest).then(
+        () => true,
+        () => false,
+    );
+    if (exists && config.package.version !== state.serverVersion) {
+        await vscode.workspace.fs.delete(dest);
+        exists = false;
+    }
+    if (!exists) {
+        await vscode.workspace.fs.copy(bundled, dest);
+        await patchelf(dest);
+    }
+    server = dest;
+    return server;
+}
+
 async function isNixOs(): Promise<boolean> {
     try {
         const contents = (
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 372dc8bedfd..1c2a34b484d 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -3,73 +3,13 @@ import * as lc from "vscode-languageclient/node";
 import * as vscode from "vscode";
 import * as ra from "../src/lsp_ext";
 import * as Is from "vscode-languageclient/lib/common/utils/is";
-import { assert } from "./util";
+import { assert, unwrapUndefinable } from "./util";
 import * as diagnostics from "./diagnostics";
 import { WorkspaceEdit } from "vscode";
 import { type Config, prepareVSCodeConfig } from "./config";
-import { randomUUID } from "crypto";
 import { sep as pathSeparator } from "path";
-import { unwrapUndefinable } from "./undefinable";
 import { RaLanguageClient } from "./lang_client";
 
-export interface Env {
-    [name: string]: string;
-}
-
-// Command URIs have a form of command:command-name?arguments, where
-// arguments is a percent-encoded array of data we want to pass along to
-// the command function. For "Show References" this is a list of all file
-// URIs with locations of every reference, and it can get quite long.
-//
-// To work around it we use an intermediary linkToCommand command. When
-// we render a command link, a reference to a command with all its arguments
-// is stored in a map, and instead a linkToCommand link is rendered
-// with the key to that map.
-export const LINKED_COMMANDS = new Map<string, ra.CommandLink>();
-
-// For now the map is cleaned up periodically (I've set it to every
-// 10 minutes). In general case we'll probably need to introduce TTLs or
-// flags to denote ephemeral links (like these in hover popups) and
-// persistent links and clean those separately. But for now simply keeping
-// the last few links in the map should be good enough. Likewise, we could
-// add code to remove a target command from the map after the link is
-// clicked, but assuming most links in hover sheets won't be clicked anyway
-// this code won't change the overall memory use much.
-setInterval(
-    function cleanupOlderCommandLinks() {
-        // keys are returned in insertion order, we'll keep a few
-        // of recent keys available, and clean the rest
-        const keys = [...LINKED_COMMANDS.keys()];
-        const keysToRemove = keys.slice(0, keys.length - 10);
-        for (const key of keysToRemove) {
-            LINKED_COMMANDS.delete(key);
-        }
-    },
-    10 * 60 * 1000,
-);
-
-function renderCommand(cmd: ra.CommandLink): string {
-    const commandId = randomUUID();
-    LINKED_COMMANDS.set(commandId, cmd);
-    return `[${cmd.title}](command:rust-analyzer.linkToCommand?${encodeURIComponent(
-        JSON.stringify([commandId]),
-    )} '${cmd.tooltip}')`;
-}
-
-function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
-    const text = actions
-        .map(
-            (group) =>
-                (group.title ? group.title + " " : "") +
-                group.commands.map(renderCommand).join(" | "),
-        )
-        .join("___");
-
-    const result = new vscode.MarkdownString(text);
-    result.isTrusted = true;
-    return result;
-}
-
 export async function createClient(
     traceOutputChannel: vscode.OutputChannel,
     outputChannel: vscode.OutputChannel,
@@ -450,3 +390,32 @@ function isCodeActionWithoutEditsAndCommands(value: any): boolean {
         candidate.command === void 0
     );
 }
+
+// Command URIs have a form of command:command-name?arguments, where
+// arguments is a percent-encoded array of data we want to pass along to
+// the command function. For "Show References" this is a list of all file
+// URIs with locations of every reference, and it can get quite long.
+// So long in fact that it will fail rendering inside an `a` tag so we need
+// to proxy around that. We store the last hover's reference command link
+// here, as only one hover can be active at a time, and we don't need to
+// keep a history of these.
+export let HOVER_REFERENCE_COMMAND: ra.CommandLink | undefined = undefined;
+
+function renderCommand(cmd: ra.CommandLink): string {
+    HOVER_REFERENCE_COMMAND = cmd;
+    return `[${cmd.title}](command:rust-analyzer.hoverRefCommandProxy '${cmd.tooltip}')`;
+}
+
+function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
+    const text = actions
+        .map(
+            (group) =>
+                (group.title ? group.title + " " : "") +
+                group.commands.map(renderCommand).join(" | "),
+        )
+        .join(" | ");
+
+    const result = new vscode.MarkdownString(text);
+    result.isTrusted = true;
+    return result;
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index 849fae5cf24..f0f9fab1c64 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -9,22 +9,27 @@ import {
     applySnippetTextEdits,
     type SnippetTextDocumentEdit,
 } from "./snippets";
-import { spawnSync } from "child_process";
-import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
+import {
+    type RunnableQuickPick,
+    selectRunnable,
+    createTaskFromRunnable,
+    createCargoArgs,
+} from "./run";
 import { AstInspector } from "./ast_inspector";
 import {
     isRustDocument,
+    isCargoRunnableArgs,
     isCargoTomlDocument,
     sleep,
     isRustEditor,
     type RustEditor,
     type RustDocument,
+    unwrapUndefinable,
 } from "./util";
 import { startDebugSession, makeDebugConfig } from "./debug";
 import type { LanguageClient } from "vscode-languageclient/node";
-import { LINKED_COMMANDS } from "./client";
+import { HOVER_REFERENCE_COMMAND } from "./client";
 import type { DependencyId } from "./dependencies_provider";
-import { unwrapUndefinable } from "./undefinable";
 import { log } from "./util";
 
 export * from "./ast_inspector";
@@ -415,10 +420,9 @@ export function serverVersion(ctx: CtxInit): Cmd {
             void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
             return;
         }
-        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
-        const versionString = stdout.slice(`rust-analyzer `.length).trim();
-
-        void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
+        void vscode.window.showInformationMessage(
+            `rust-analyzer version: ${ctx.serverVersion} [${ctx.serverPath}]`,
+        );
     };
 }
 
@@ -1097,7 +1101,7 @@ export function run(ctx: CtxInit): Cmd {
 
         item.detail = "rerun";
         prevRunnable = item;
-        const task = await createTask(item.runnable, ctx.config);
+        const task = await createTaskFromRunnable(item.runnable, ctx.config);
         return await vscode.tasks.executeTask(task);
     };
 }
@@ -1140,7 +1144,7 @@ export function runSingle(ctx: CtxInit): Cmd {
         const editor = ctx.activeRustEditor;
         if (!editor) return;
 
-        const task = await createTask(runnable, ctx.config);
+        const task = await createTaskFromRunnable(runnable, ctx.config);
         task.group = vscode.TaskGroup.Build;
         task.presentationOptions = {
             reveal: vscode.TaskRevealKind.Always,
@@ -1156,8 +1160,8 @@ export function copyRunCommandLine(ctx: CtxInit) {
     let prevRunnable: RunnableQuickPick | undefined;
     return async () => {
         const item = await selectRunnable(ctx, prevRunnable);
-        if (!item) return;
-        const args = createArgs(item.runnable);
+        if (!item || !isCargoRunnableArgs(item.runnable.args)) return;
+        const args = createCargoArgs(item.runnable.args);
         const commandLine = ["cargo", ...args].join(" ");
         await vscode.env.clipboard.writeText(commandLine);
         await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
@@ -1192,11 +1196,10 @@ export function newDebugConfig(ctx: CtxInit): Cmd {
     };
 }
 
-export function linkToCommand(_: Ctx): Cmd {
-    return async (commandId: string) => {
-        const link = LINKED_COMMANDS.get(commandId);
-        if (link) {
-            const { command, arguments: args = [] } = link;
+export function hoverRefCommandProxy(_: Ctx): Cmd {
+    return async () => {
+        if (HOVER_REFERENCE_COMMAND) {
+            const { command, arguments: args = [] } = HOVER_REFERENCE_COMMAND;
             await vscode.commands.executeCommand(command, ...args);
         }
     };
@@ -1486,3 +1489,16 @@ export function toggleCheckOnSave(ctx: Ctx): Cmd {
         ctx.refreshServerStatus();
     };
 }
+
+export function toggleLSPLogs(ctx: Ctx): Cmd {
+    return async () => {
+        const config = vscode.workspace.getConfiguration("rust-analyzer");
+        const targetValue =
+            config.get<string | undefined>("trace.server") === "verbose" ? undefined : "verbose";
+
+        await config.update("trace.server", targetValue, vscode.ConfigurationTarget.Workspace);
+        if (targetValue && ctx.client && ctx.client.traceOutputChannel) {
+            ctx.client.traceOutputChannel.show();
+        }
+    };
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index e676bc0826c..1931cfe3813 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -2,9 +2,7 @@ import * as Is from "vscode-languageclient/lib/common/utils/is";
 import * as os from "os";
 import * as path from "path";
 import * as vscode from "vscode";
-import type { Env } from "./client";
-import { log } from "./util";
-import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
+import { type Env, log, unwrapUndefinable, expectNotUndefined } from "./util";
 import type { JsonProject } from "./rust_project";
 
 export type RunnableEnvCfgItem = {
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 474e18b722f..bf0b84ec358 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -25,6 +25,8 @@ import { bootstrap } from "./bootstrap";
 import type { RustAnalyzerExtensionApi } from "./main";
 import type { JsonProject } from "./rust_project";
 import { prepareTestExplorer } from "./test_explorer";
+import { spawn } from "node:child_process";
+import { text } from "node:stream/consumers";
 
 // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 // only those are in use. We use "Empty" to represent these scenarios
@@ -71,6 +73,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
     readonly statusBar: vscode.StatusBarItem;
     config: Config;
     readonly workspace: Workspace;
+    readonly version: string;
 
     private _client: lc.LanguageClient | undefined;
     private _serverPath: string | undefined;
@@ -85,6 +88,15 @@ export class Ctx implements RustAnalyzerExtensionApi {
     private _dependencies: RustDependenciesProvider | undefined;
     private _treeView: vscode.TreeView<Dependency | DependencyFile | DependencyId> | undefined;
     private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" };
+    private _serverVersion: string;
+
+    get serverPath(): string | undefined {
+        return this._serverPath;
+    }
+
+    get serverVersion(): string | undefined {
+        return this._serverVersion;
+    }
 
     get client() {
         return this._client;
@@ -104,6 +116,8 @@ export class Ctx implements RustAnalyzerExtensionApi {
         workspace: Workspace,
     ) {
         extCtx.subscriptions.push(this);
+        this.version = extCtx.extension.packageJSON.version ?? "<unknown>";
+        this._serverVersion = "<not running>";
         this.config = new Config(extCtx);
         this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
         if (this.config.testExplorer) {
@@ -186,6 +200,19 @@ export class Ctx implements RustAnalyzerExtensionApi {
                     throw new Error(message);
                 },
             );
+            text(spawn(this._serverPath, ["--version"]).stdout.setEncoding("utf-8")).then(
+                (data) => {
+                    const prefix = `rust-analyzer `;
+                    this._serverVersion = data
+                        .slice(data.startsWith(prefix) ? prefix.length : 0)
+                        .trim();
+                    this.refreshServerStatus();
+                },
+                (_) => {
+                    this._serverVersion = "<unknown>";
+                    this.refreshServerStatus();
+                },
+            );
             const newEnv = Object.assign({}, process.env, this.config.serverExtraEnv);
             const run: lc.Executable = {
                 command: this._serverPath,
@@ -372,10 +399,6 @@ export class Ctx implements RustAnalyzerExtensionApi {
         return this.extCtx.subscriptions;
     }
 
-    get serverPath(): string | undefined {
-        return this._serverPath;
-    }
-
     setWorkspaces(workspaces: JsonProject[]) {
         this.config.discoveredWorkspaces = workspaces;
     }
@@ -475,23 +498,24 @@ export class Ctx implements RustAnalyzerExtensionApi {
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendMarkdown("\n\n---\n\n");
         }
-        statusBar.tooltip.appendMarkdown("\n\n[Open Logs](command:rust-analyzer.openLogs)");
-        statusBar.tooltip.appendMarkdown(
-            `\n\n[${
-                this.config.checkOnSave ? "Disable" : "Enable"
-            } Check on Save](command:rust-analyzer.toggleCheckOnSave)`,
-        );
-        statusBar.tooltip.appendMarkdown(
-            "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)",
-        );
-        statusBar.tooltip.appendMarkdown(
-            "\n\n[Rebuild Proc Macros](command:rust-analyzer.rebuildProcMacros)",
-        );
+
+        const toggleCheckOnSave = this.config.checkOnSave ? "Disable" : "Enable";
         statusBar.tooltip.appendMarkdown(
-            "\n\n[Restart server](command:rust-analyzer.restartServer)",
+            `[Extension Info](command:analyzer.serverVersion "Show version and server binary info"): Version ${this.version}, Server Version ${this._serverVersion}` +
+                "\n\n---\n\n" +
+                '[$(terminal) Open Logs](command:rust-analyzer.openLogs "Open the server logs")' +
+                "\n\n" +
+                `[$(settings) ${toggleCheckOnSave} Check on Save](command:rust-analyzer.toggleCheckOnSave "Temporarily ${toggleCheckOnSave.toLowerCase()} check on save functionality")` +
+                "\n\n" +
+                '[$(refresh) Reload Workspace](command:rust-analyzer.reloadWorkspace "Reload and rediscover workspaces")' +
+                "\n\n" +
+                '[$(symbol-property) Rebuild Build Dependencies](command:rust-analyzer.rebuildProcMacros "Rebuild build scripts and proc-macros")' +
+                "\n\n" +
+                '[$(stop-circle) Stop server](command:rust-analyzer.stopServer "Stop the server")' +
+                "\n\n" +
+                '[$(debug-restart) Restart server](command:rust-analyzer.restartServer "Restart the server")',
         );
-        statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)");
-        if (!status.quiescent) icon = "$(sync~spin) ";
+        if (!status.quiescent) icon = "$(loading~spin) ";
         statusBar.text = `${icon}rust-analyzer`;
     }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index 4b96e4d5c8e..58fe1df51f4 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -6,11 +6,12 @@ import type * as ra from "./lsp_ext";
 import { Cargo, getRustcId, getSysroot } from "./toolchain";
 import type { Ctx } from "./ctx";
 import { prepareEnv } from "./run";
-import { unwrapUndefinable } from "./undefinable";
+import { isCargoRunnableArgs, unwrapUndefinable } from "./util";
 
 const debugOutput = vscode.window.createOutputChannel("Debug");
 type DebugConfigProvider = (
-    config: ra.Runnable,
+    runnable: ra.Runnable,
+    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -76,6 +77,11 @@ async function getDebugConfiguration(
     ctx: Ctx,
     runnable: ra.Runnable,
 ): Promise<vscode.DebugConfiguration | undefined> {
+    if (!isCargoRunnableArgs(runnable.args)) {
+        return;
+    }
+    const runnableArgs: ra.CargoRunnableArgs = runnable.args;
+
     const editor = ctx.activeRustEditor;
     if (!editor) return;
 
@@ -119,9 +125,9 @@ async function getDebugConfiguration(
     const isMultiFolderWorkspace = workspaceFolders.length > 1;
     const firstWorkspace = workspaceFolders[0];
     const maybeWorkspace =
-        !isMultiFolderWorkspace || !runnable.args.workspaceRoot
+        !isMultiFolderWorkspace || !runnableArgs.workspaceRoot
             ? firstWorkspace
-            : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) ||
+            : workspaceFolders.find((w) => runnableArgs.workspaceRoot?.includes(w.uri.fsPath)) ||
               firstWorkspace;
 
     const workspace = unwrapUndefinable(maybeWorkspace);
@@ -129,11 +135,11 @@ async function getDebugConfiguration(
     const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : "";
     function simplifyPath(p: string): string {
         // see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed
-        return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}");
+        return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`);
     }
 
-    const env = prepareEnv(runnable, ctx.config.runnablesExtraEnv);
-    const executable = await getDebugExecutable(runnable, env);
+    const env = prepareEnv(runnable.label, runnableArgs, ctx.config.runnablesExtraEnv);
+    const executable = await getDebugExecutable(runnableArgs, env);
     let sourceFileMap = debugOptions.sourceFileMap;
     if (sourceFileMap === "auto") {
         // let's try to use the default toolchain
@@ -147,7 +153,7 @@ async function getDebugConfiguration(
     }
 
     const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
-    const debugConfig = provider(runnable, simplifyPath(executable), env, sourceFileMap);
+    const debugConfig = provider(runnable, runnableArgs, simplifyPath(executable), env);
     if (debugConfig.type in debugOptions.engineSettings) {
         const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
         for (var key in settingsMap) {
@@ -170,11 +176,11 @@ async function getDebugConfiguration(
 }
 
 async function getDebugExecutable(
-    runnable: ra.Runnable,
+    runnableArgs: ra.CargoRunnableArgs,
     env: Record<string, string>,
 ): Promise<string> {
-    const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput, env);
-    const executable = await cargo.executableFromArgs(runnable.args.cargoArgs);
+    const cargo = new Cargo(runnableArgs.workspaceRoot || ".", debugOutput, env);
+    const executable = await cargo.executableFromArgs(runnableArgs.cargoArgs);
 
     // if we are here, there were no compilation errors.
     return executable;
@@ -182,6 +188,7 @@ async function getDebugExecutable(
 
 function getCCppDebugConfig(
     runnable: ra.Runnable,
+    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -191,8 +198,8 @@ function getCCppDebugConfig(
         request: "launch",
         name: runnable.label,
         program: executable,
-        args: runnable.args.executableArgs,
-        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
+        args: runnableArgs.executableArgs,
+        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
         sourceFileMap,
         environment: Object.entries(env).map((entry) => ({
             name: entry[0],
@@ -207,6 +214,7 @@ function getCCppDebugConfig(
 
 function getCodeLldbDebugConfig(
     runnable: ra.Runnable,
+    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -216,8 +224,8 @@ function getCodeLldbDebugConfig(
         request: "launch",
         name: runnable.label,
         program: executable,
-        args: runnable.args.executableArgs,
-        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
+        args: runnableArgs.executableArgs,
+        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
         sourceMap: sourceFileMap,
         sourceLanguages: ["rust"],
         env,
@@ -226,6 +234,7 @@ function getCodeLldbDebugConfig(
 
 function getNativeDebugConfig(
     runnable: ra.Runnable,
+    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     _sourceFileMap?: Record<string, string>,
@@ -236,8 +245,8 @@ function getNativeDebugConfig(
         name: runnable.label,
         target: executable,
         // See https://github.com/WebFreak001/code-debug/issues/359
-        arguments: quote(runnable.args.executableArgs),
-        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
+        arguments: quote(runnableArgs.executableArgs),
+        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
         env,
         valuesFormatting: "prettyPrinters",
     };
diff --git a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
index 863ace07801..203ef5cc85e 100644
--- a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
+++ b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
@@ -4,7 +4,7 @@ import * as fs from "fs";
 import type { CtxInit } from "./ctx";
 import * as ra from "./lsp_ext";
 import type { FetchDependencyListResult } from "./lsp_ext";
-import { unwrapUndefinable } from "./undefinable";
+import { unwrapUndefinable } from "./util";
 
 export class RustDependenciesProvider
     implements vscode.TreeDataProvider<Dependency | DependencyFile>
diff --git a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
index e31a1cdcef9..9fb2993d12f 100644
--- a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
+++ b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
@@ -8,7 +8,7 @@ import {
     window,
 } from "vscode";
 import type { Ctx } from "./ctx";
-import { unwrapUndefinable } from "./undefinable";
+import { unwrapUndefinable } from "./util";
 
 export const URI_SCHEME = "rust-analyzer-diagnostics-view";
 
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 8e48aeef158..699052e4d44 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -223,17 +223,35 @@ export type OpenCargoTomlParams = {
 export type Runnable = {
     label: string;
     location?: lc.LocationLink;
+} & (RunnableCargo | RunnableShell);
+
+type RunnableCargo = {
     kind: "cargo";
-    args: {
-        workspaceRoot?: string;
-        cwd?: string;
-        cargoArgs: string[];
-        cargoExtraArgs: string[];
-        executableArgs: string[];
-        expectTest?: boolean;
-        overrideCargo?: string;
-    };
+    args: CargoRunnableArgs;
+};
+
+type RunnableShell = {
+    kind: "shell";
+    args: ShellRunnableArgs;
+};
+
+export type ShellRunnableArgs = {
+    kind: string;
+    program: string;
+    args: string[];
+    cwd: string;
+};
+
+export type CargoRunnableArgs = {
+    workspaceRoot?: string;
+    cargoArgs: string[];
+    cwd: string;
+    cargoExtraArgs: string[];
+    executableArgs: string[];
+    expectTest?: boolean;
+    overrideCargo?: string;
 };
+
 export type RunnablesParams = {
     textDocument: lc.TextDocumentIdentifier;
     position: lc.Position | null;
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index 0af58fd7812..ff67bb7bd59 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -177,12 +177,13 @@ function createCommands(): Record<string, CommandFactory> {
         serverVersion: { enabled: commands.serverVersion },
         viewMemoryLayout: { enabled: commands.viewMemoryLayout },
         toggleCheckOnSave: { enabled: commands.toggleCheckOnSave },
+        toggleLSPLogs: { enabled: commands.toggleLSPLogs },
         // Internal commands which are invoked by the server.
         applyActionGroup: { enabled: commands.applyActionGroup },
         applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand },
         debugSingle: { enabled: commands.debugSingle },
         gotoLocation: { enabled: commands.gotoLocation },
-        linkToCommand: { enabled: commands.linkToCommand },
+        hoverRefCommandProxy: { enabled: commands.hoverRefCommandProxy },
         resolveCodeAction: { enabled: commands.resolveCodeAction },
         runSingle: { enabled: commands.runSingle },
         showReferences: { enabled: commands.showReferences },
@@ -203,14 +204,4 @@ function checkConflictingExtensions() {
             )
             .then(() => {}, console.error);
     }
-
-    if (vscode.extensions.getExtension("panicbit.cargo")) {
-        vscode.window
-            .showWarningMessage(
-                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Cargo (panicbit.cargo) plugins enabled, ` +
-                    'you can disable it or set {"cargo.automaticCheck": false} in settings.json to avoid invoking cargo twice',
-                "Got it",
-            )
-            .then(() => {}, console.error);
-    }
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/nullable.ts b/src/tools/rust-analyzer/editors/code/src/nullable.ts
deleted file mode 100644
index e973e162907..00000000000
--- a/src/tools/rust-analyzer/editors/code/src/nullable.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export type NotNull<T> = T extends null ? never : T;
-
-export type Nullable<T> = T | null;
-
-function isNotNull<T>(input: Nullable<T>): input is NotNull<T> {
-    return input !== null;
-}
-
-function expectNotNull<T>(input: Nullable<T>, msg: string): NotNull<T> {
-    if (isNotNull(input)) {
-        return input;
-    }
-
-    throw new TypeError(msg);
-}
-
-export function unwrapNullable<T>(input: Nullable<T>): NotNull<T> {
-    return expectNotNull(input, `unwrapping \`null\``);
-}
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index 4470689cd8c..7a9049af0de 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -6,9 +6,9 @@ import * as tasks from "./tasks";
 import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
 import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
-import { unwrapUndefinable } from "./undefinable";
 import type { LanguageClient } from "vscode-languageclient/node";
-import type { RustEditor } from "./util";
+import { unwrapUndefinable, type RustEditor } from "./util";
+import * as toolchain from "./toolchain";
 
 const quickPickButtons = [
     { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -66,17 +66,23 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
     }
 }
 
+export function prepareBaseEnv(): Record<string, string> {
+    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
+    Object.assign(env, process.env as { [key: string]: string });
+    return env;
+}
+
 export function prepareEnv(
-    runnable: ra.Runnable,
+    label: string,
+    runnableArgs: ra.CargoRunnableArgs,
     runnableEnvCfg: RunnableEnvCfg,
 ): Record<string, string> {
-    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
+    const env = prepareBaseEnv();
 
-    if (runnable.args.expectTest) {
+    if (runnableArgs.expectTest) {
         env["UPDATE_EXPECT"] = "1";
     }
 
-    Object.assign(env, process.env as { [key: string]: string });
     const platform = process.platform;
 
     const checkPlatform = (it: RunnableEnvCfgItem) => {
@@ -90,7 +96,7 @@ export function prepareEnv(
     if (runnableEnvCfg) {
         if (Array.isArray(runnableEnvCfg)) {
             for (const it of runnableEnvCfg) {
-                const masked = !it.mask || new RegExp(it.mask).test(runnable.label);
+                const masked = !it.mask || new RegExp(it.mask).test(label);
                 if (masked && checkPlatform(it)) {
                     Object.assign(env, it.env);
                 }
@@ -103,34 +109,52 @@ export function prepareEnv(
     return env;
 }
 
-export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
-    if (runnable.kind !== "cargo") {
-        // rust-analyzer supports only one kind, "cargo"
-        // do not use tasks.TASK_TYPE here, these are completely different meanings.
+export async function createTaskFromRunnable(
+    runnable: ra.Runnable,
+    config: Config,
+): Promise<vscode.Task> {
+    let definition: tasks.RustTargetDefinition;
+    if (runnable.kind === "cargo") {
+        const runnableArgs = runnable.args;
+        let args = createCargoArgs(runnableArgs);
+
+        let program: string;
+        if (runnableArgs.overrideCargo) {
+            // Split on spaces to allow overrides like "wrapper cargo".
+            const cargoParts = runnableArgs.overrideCargo.split(" ");
+
+            program = unwrapUndefinable(cargoParts[0]);
+            args = [...cargoParts.slice(1), ...args];
+        } else {
+            program = await toolchain.cargoPath();
+        }
 
-        throw `Unexpected runnable kind: ${runnable.kind}`;
+        definition = {
+            type: tasks.CARGO_TASK_TYPE,
+            command: program,
+            args,
+            cwd: runnableArgs.workspaceRoot || ".",
+            env: prepareEnv(runnable.label, runnableArgs, config.runnablesExtraEnv),
+        };
+    } else {
+        const runnableArgs = runnable.args;
+        definition = {
+            type: tasks.SHELL_TASK_TYPE,
+            command: runnableArgs.program,
+            args: runnableArgs.args,
+            cwd: runnableArgs.cwd,
+            env: prepareBaseEnv(),
+        };
     }
 
-    const args = createArgs(runnable);
-
-    const definition: tasks.CargoTaskDefinition = {
-        type: tasks.TASK_TYPE,
-        command: unwrapUndefinable(args[0]), // run, test, etc...
-        args: args.slice(1),
-        cwd: runnable.args.workspaceRoot || ".",
-        env: prepareEnv(runnable, config.runnablesExtraEnv),
-        overrideCargo: runnable.args.overrideCargo,
-    };
-
-    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
-    const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
+    const target = vscode.workspace.workspaceFolders?.[0];
+    const exec = await tasks.targetToExecution(definition, config.cargoRunner, true);
     const task = await tasks.buildRustTask(
         target,
         definition,
         runnable.label,
         config.problemMatcher,
-        config.cargoRunner,
-        true,
+        exec,
     );
 
     task.presentationOptions.clear = true;
@@ -141,13 +165,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
     return task;
 }
 
-export function createArgs(runnable: ra.Runnable): string[] {
-    const args = [...runnable.args.cargoArgs]; // should be a copy!
-    if (runnable.args.cargoExtraArgs) {
-        args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options.
+export function createCargoArgs(runnableArgs: ra.CargoRunnableArgs): string[] {
+    const args = [...runnableArgs.cargoArgs]; // should be a copy!
+    if (runnableArgs.cargoExtraArgs) {
+        args.push(...runnableArgs.cargoExtraArgs); // Append user-specified cargo options.
     }
-    if (runnable.args.executableArgs.length > 0) {
-        args.push("--", ...runnable.args.executableArgs);
+    if (runnableArgs.executableArgs.length > 0) {
+        args.push("--", ...runnableArgs.executableArgs);
     }
     return args;
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts
index b3982bdf2be..a469a9cd1f4 100644
--- a/src/tools/rust-analyzer/editors/code/src/snippets.ts
+++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts
@@ -1,7 +1,6 @@
 import * as vscode from "vscode";
 
-import { assert } from "./util";
-import { unwrapUndefinable } from "./undefinable";
+import { assert, unwrapUndefinable } from "./util";
 
 export type SnippetTextDocumentEdit = [vscode.Uri, (vscode.TextEdit | vscode.SnippetTextEdit)[]];
 
diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts
index 2b3abc5d65f..6f4fbf91889 100644
--- a/src/tools/rust-analyzer/editors/code/src/tasks.ts
+++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts
@@ -1,28 +1,29 @@
 import * as vscode from "vscode";
-import * as toolchain from "./toolchain";
 import type { Config } from "./config";
-import { log } from "./util";
-import { unwrapUndefinable } from "./undefinable";
+import { log, unwrapUndefinable } from "./util";
+import * as toolchain from "./toolchain";
 
 // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
 // our configuration should be compatible with it so use the same key.
-export const TASK_TYPE = "cargo";
+export const CARGO_TASK_TYPE = "cargo";
+export const SHELL_TASK_TYPE = "shell";
 
-export const TASK_SOURCE = "rust";
+export const RUST_TASK_SOURCE = "rust";
 
-export interface CargoTaskDefinition extends vscode.TaskDefinition {
-    // The cargo command, such as "run" or "check".
+export type RustTargetDefinition = {
+    readonly type: typeof CARGO_TASK_TYPE | typeof SHELL_TASK_TYPE;
+} & vscode.TaskDefinition &
+    RustTarget;
+export type RustTarget = {
+    // The command to run, usually `cargo`.
     command: string;
-    // Additional arguments passed to the cargo command.
+    // Additional arguments passed to the command.
     args?: string[];
-    // The working directory to run the cargo command in.
+    // The working directory to run the command in.
     cwd?: string;
     // The shell environment.
     env?: { [key: string]: string };
-    // Override the cargo executable name, such as
-    // "my_custom_cargo_bin".
-    overrideCargo?: string;
-}
+};
 
 class RustTaskProvider implements vscode.TaskProvider {
     private readonly config: Config;
@@ -32,6 +33,10 @@ class RustTaskProvider implements vscode.TaskProvider {
     }
 
     async provideTasks(): Promise<vscode.Task[]> {
+        if (!vscode.workspace.workspaceFolders) {
+            return [];
+        }
+
         // Detect Rust tasks. Currently we do not do any actual detection
         // of tasks (e.g. aliases in .cargo/config) and just return a fixed
         // set of tasks that always exist. These tasks cannot be removed in
@@ -46,15 +51,23 @@ class RustTaskProvider implements vscode.TaskProvider {
             { command: "run", group: undefined },
         ];
 
+        // FIXME: The server should provide this
+        const cargo = await toolchain.cargoPath();
+
         const tasks: vscode.Task[] = [];
-        for (const workspaceTarget of vscode.workspace.workspaceFolders || []) {
+        for (const workspaceTarget of vscode.workspace.workspaceFolders) {
             for (const def of defs) {
+                const definition = {
+                    command: cargo,
+                    args: [def.command],
+                };
+                const exec = await targetToExecution(definition, this.config.cargoRunner);
                 const vscodeTask = await buildRustTask(
                     workspaceTarget,
-                    { type: TASK_TYPE, command: def.command },
+                    { ...definition, type: CARGO_TASK_TYPE },
                     `cargo ${def.command}`,
                     this.config.problemMatcher,
-                    this.config.cargoRunner,
+                    exec,
                 );
                 vscodeTask.group = def.group;
                 tasks.push(vscodeTask);
@@ -68,16 +81,24 @@ class RustTaskProvider implements vscode.TaskProvider {
         // VSCode calls this for every cargo task in the user's tasks.json,
         // we need to inform VSCode how to execute that command by creating
         // a ShellExecution for it.
-
-        const definition = task.definition as CargoTaskDefinition;
-
-        if (definition.type === TASK_TYPE) {
+        if (task.definition.type === CARGO_TASK_TYPE) {
+            const taskDefinition = task.definition as RustTargetDefinition;
+            const cargo = await toolchain.cargoPath();
+            const exec = await targetToExecution(
+                {
+                    command: cargo,
+                    args: [taskDefinition.command].concat(taskDefinition.args || []),
+                    cwd: taskDefinition.cwd,
+                    env: taskDefinition.env,
+                },
+                this.config.cargoRunner,
+            );
             return await buildRustTask(
                 task.scope,
-                definition,
+                taskDefinition,
                 task.name,
                 this.config.problemMatcher,
-                this.config.cargoRunner,
+                exec,
             );
         }
 
@@ -87,37 +108,34 @@ class RustTaskProvider implements vscode.TaskProvider {
 
 export async function buildRustTask(
     scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
-    definition: CargoTaskDefinition,
+    definition: RustTargetDefinition,
     name: string,
     problemMatcher: string[],
-    customRunner?: string,
-    throwOnError: boolean = false,
+    exec: vscode.ProcessExecution | vscode.ShellExecution,
 ): Promise<vscode.Task> {
-    const exec = await cargoToExecution(definition, customRunner, throwOnError);
-
     return new vscode.Task(
         definition,
         // scope can sometimes be undefined. in these situations we default to the workspace taskscope as
         // recommended by the official docs: https://code.visualstudio.com/api/extension-guides/task-provider#task-provider)
         scope ?? vscode.TaskScope.Workspace,
         name,
-        TASK_SOURCE,
+        RUST_TASK_SOURCE,
         exec,
         problemMatcher,
     );
 }
 
-async function cargoToExecution(
-    definition: CargoTaskDefinition,
-    customRunner: string | undefined,
-    throwOnError: boolean,
+export async function targetToExecution(
+    definition: RustTarget,
+    customRunner?: string,
+    throwOnError: boolean = false,
 ): Promise<vscode.ProcessExecution | vscode.ShellExecution> {
     if (customRunner) {
         const runnerCommand = `${customRunner}.buildShellExecution`;
 
         try {
             const runnerArgs = {
-                kind: TASK_TYPE,
+                kind: CARGO_TASK_TYPE,
                 args: definition.args,
                 cwd: definition.cwd,
                 env: definition.env,
@@ -137,18 +155,8 @@ async function cargoToExecution(
             // fallback to default processing
         }
     }
-
-    // Check whether we must use a user-defined substitute for cargo.
-    // Split on spaces to allow overrides like "wrapper cargo".
-    const cargoPath = await toolchain.cargoPath();
-    const cargoCommand = definition.overrideCargo?.split(" ") ?? [cargoPath];
-
-    const args = [definition.command].concat(definition.args ?? []);
-    const fullCommand = [...cargoCommand, ...args];
-
-    const processName = unwrapUndefinable(fullCommand[0]);
-
-    return new vscode.ProcessExecution(processName, fullCommand.slice(1), {
+    const args = unwrapUndefinable(definition.args);
+    return new vscode.ProcessExecution(definition.command, args, {
         cwd: definition.cwd,
         env: definition.env,
     });
@@ -156,5 +164,5 @@ async function cargoToExecution(
 
 export function activateTaskProvider(config: Config): vscode.Disposable {
     const provider = new RustTaskProvider(config);
-    return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
+    return vscode.tasks.registerTaskProvider(CARGO_TASK_TYPE, provider);
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
index 58e5fc747a1..a48d2d90cce 100644
--- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts
+++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
@@ -3,9 +3,7 @@ import * as os from "os";
 import * as path from "path";
 import * as readline from "readline";
 import * as vscode from "vscode";
-import { execute, log, memoizeAsync } from "./util";
-import { unwrapNullable } from "./nullable";
-import { unwrapUndefinable } from "./undefinable";
+import { execute, log, memoizeAsync, unwrapNullable, unwrapUndefinable } from "./util";
 
 interface CompilationArtifact {
     fileName: string;
@@ -151,12 +149,13 @@ export async function getRustcId(dir: string): Promise<string> {
 }
 
 /** Mirrors `toolchain::cargo()` implementation */
+// FIXME: The server should provide this
 export function cargoPath(): Promise<string> {
     return getPathForExecutable("cargo");
 }
 
 /** Mirrors `toolchain::get_path_for_executable()` implementation */
-export const getPathForExecutable = memoizeAsync(
+const getPathForExecutable = memoizeAsync(
     // We apply caching to decrease file-system interactions
     async (executableName: "cargo" | "rustc" | "rustup"): Promise<string> => {
         {
diff --git a/src/tools/rust-analyzer/editors/code/src/undefinable.ts b/src/tools/rust-analyzer/editors/code/src/undefinable.ts
deleted file mode 100644
index 813bac5a123..00000000000
--- a/src/tools/rust-analyzer/editors/code/src/undefinable.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export type NotUndefined<T> = T extends undefined ? never : T;
-
-export type Undefinable<T> = T | undefined;
-
-function isNotUndefined<T>(input: Undefinable<T>): input is NotUndefined<T> {
-    return input !== undefined;
-}
-
-export function expectNotUndefined<T>(input: Undefinable<T>, msg: string): NotUndefined<T> {
-    if (isNotUndefined(input)) {
-        return input;
-    }
-
-    throw new TypeError(msg);
-}
-
-export function unwrapUndefinable<T>(input: Undefinable<T>): NotUndefined<T> {
-    return expectNotUndefined(input, `unwrapping \`undefined\``);
-}
diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts
index 51f921a2962..dd1cbe38ff9 100644
--- a/src/tools/rust-analyzer/editors/code/src/util.ts
+++ b/src/tools/rust-analyzer/editors/code/src/util.ts
@@ -1,8 +1,8 @@
 import * as vscode from "vscode";
 import { strict as nativeAssert } from "assert";
-import { exec, type ExecOptions, spawnSync } from "child_process";
+import { exec, type ExecOptions } from "child_process";
 import { inspect } from "util";
-import type { Env } from "./client";
+import type { CargoRunnableArgs, ShellRunnableArgs } from "./lsp_ext";
 
 export function assert(condition: boolean, explanation: string): asserts condition {
     try {
@@ -13,6 +13,10 @@ export function assert(condition: boolean, explanation: string): asserts conditi
     }
 }
 
+export type Env = {
+    [name: string]: string;
+};
+
 export const log = new (class {
     private enabled = true;
     private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
@@ -77,6 +81,12 @@ export function isCargoTomlDocument(document: vscode.TextDocument): document is
     return document.uri.scheme === "file" && document.fileName.endsWith("Cargo.toml");
 }
 
+export function isCargoRunnableArgs(
+    args: CargoRunnableArgs | ShellRunnableArgs,
+): args is CargoRunnableArgs {
+    return (args as CargoRunnableArgs).executableArgs !== undefined;
+}
+
 export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
     return isRustDocument(editor.document);
 }
@@ -94,20 +104,6 @@ export function isDocumentInWorkspace(document: RustDocument): boolean {
     return false;
 }
 
-export function isValidExecutable(path: string, extraEnv: Env): boolean {
-    log.debug("Checking availability of a binary at", path);
-
-    const res = spawnSync(path, ["--version"], {
-        encoding: "utf8",
-        env: { ...process.env, ...extraEnv },
-    });
-
-    const printOutput = res.error ? log.warn : log.info;
-    printOutput(path, "--version:", res);
-
-    return res.status === 0;
-}
-
 /** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */
 export function setContextValue(key: string, value: any): Thenable<void> {
     return vscode.commands.executeCommand("setContext", key, value);
@@ -199,3 +195,42 @@ export class LazyOutputChannel implements vscode.OutputChannel {
         }
     }
 }
+
+export type NotNull<T> = T extends null ? never : T;
+
+export type Nullable<T> = T | null;
+
+function isNotNull<T>(input: Nullable<T>): input is NotNull<T> {
+    return input !== null;
+}
+
+function expectNotNull<T>(input: Nullable<T>, msg: string): NotNull<T> {
+    if (isNotNull(input)) {
+        return input;
+    }
+
+    throw new TypeError(msg);
+}
+
+export function unwrapNullable<T>(input: Nullable<T>): NotNull<T> {
+    return expectNotNull(input, `unwrapping \`null\``);
+}
+export type NotUndefined<T> = T extends undefined ? never : T;
+
+export type Undefinable<T> = T | undefined;
+
+function isNotUndefined<T>(input: Undefinable<T>): input is NotUndefined<T> {
+    return input !== undefined;
+}
+
+export function expectNotUndefined<T>(input: Undefinable<T>, msg: string): NotUndefined<T> {
+    if (isNotUndefined(input)) {
+        return input;
+    }
+
+    throw new TypeError(msg);
+}
+
+export function unwrapUndefinable<T>(input: Undefinable<T>): NotUndefined<T> {
+    return expectNotUndefined(input, `unwrapping \`undefined\``);
+}
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
index b1407ce0193..21bdaf5384d 100644
--- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
@@ -10,6 +10,7 @@ function makeRunnable(label: string): ra.Runnable {
         kind: "cargo",
         args: {
             cargoArgs: [],
+            cwd: ".",
             executableArgs: [],
             cargoExtraArgs: [],
         },
@@ -18,7 +19,8 @@ function makeRunnable(label: string): ra.Runnable {
 
 function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> {
     const runnable = makeRunnable(runnableName);
-    return prepareEnv(runnable, config);
+    const runnableArgs = runnable.args as ra.CargoRunnableArgs;
+    return prepareEnv(runnable.label, runnableArgs, config);
 }
 
 export async function getTests(ctx: Context) {
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
index 5dc052b5875..4069e6f2c09 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
@@ -433,8 +433,7 @@ mod tests {
         initialize_start_test(TestCase {
             test_messages: vec![notification_msg.clone()],
             expected_resp: Err(ProtocolError::new(format!(
-                "expected initialize request, got {:?}",
-                notification_msg
+                "expected initialize request, got {notification_msg:?}"
             ))),
         });
     }
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 207ef6c5de7..c605feb6eea 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-6579ed89f0fcc26da71afdd11d30d63f6f812a0a
+3d5d7a24f76006b391d8a53d903ae64c1b4a52d2
diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs
index 2fe9db98cf2..742cf7f609a 100644
--- a/src/tools/rust-analyzer/xtask/src/dist.rs
+++ b/src/tools/rust-analyzer/xtask/src/dist.rs
@@ -70,8 +70,8 @@ fn dist_client(
             &format!(r#""version": "{version}""#),
         )
         .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{release_tag}""#))
-        .replace(r#""$generated-start": {},"#, "")
-        .replace(",\n                \"$generated-end\": {}", "")
+        .replace(r#""title": "$generated-start""#, "")
+        .replace(r#""title": "$generated-end""#, "")
         .replace(r#""enabledApiProposals": [],"#, r#""#);
     patch.commit(sh)?;
 
diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs
index 285abb9efcb..9a7785dd438 100644
--- a/src/tools/rust-analyzer/xtask/src/metrics.rs
+++ b/src/tools/rust-analyzer/xtask/src/metrics.rs
@@ -64,7 +64,7 @@ impl flags::Metrics {
         };
 
         let mut file =
-            fs::File::options().write(true).create(true).open(format!("target/{}.json", name))?;
+            fs::File::options().write(true).create(true).open(format!("target/{name}.json"))?;
         writeln!(file, "{}", metrics.json())?;
         eprintln!("{metrics:#?}");
         Ok(())
diff --git a/src/tools/rust-analyzer/xtask/src/publish.rs b/src/tools/rust-analyzer/xtask/src/publish.rs
index 7faae9b20c4..f5d765d7c98 100644
--- a/src/tools/rust-analyzer/xtask/src/publish.rs
+++ b/src/tools/rust-analyzer/xtask/src/publish.rs
@@ -9,6 +9,15 @@ impl flags::PublishReleaseNotes {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
         let asciidoc = sh.read_file(&self.changelog)?;
         let mut markdown = notes::convert_asciidoc_to_markdown(std::io::Cursor::new(&asciidoc))?;
+        if !markdown.starts_with("# Changelog") {
+            bail!("changelog Markdown should start with `# Changelog`");
+        }
+        const NEWLINES: &str = "\n\n";
+        let Some(idx) = markdown.find(NEWLINES) else {
+            bail!("missing newlines after changelog title");
+        };
+        markdown.replace_range(0..idx + NEWLINES.len(), "");
+
         let file_name = check_file_name(self.changelog)?;
         let tag_name = &file_name[0..10];
         let original_changelog_url = create_original_changelog_url(&file_name);