From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- src/tools/rust-analyzer/crates/base-db/Cargo.toml | 4 + .../rust-analyzer/crates/base-db/src/change.rs | 23 +- .../rust-analyzer/crates/base-db/src/fixture.rs | 90 +- .../rust-analyzer/crates/base-db/src/input.rs | 344 +- src/tools/rust-analyzer/crates/base-db/src/lib.rs | 29 +- src/tools/rust-analyzer/crates/cfg/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/flycheck/Cargo.toml | 5 +- src/tools/rust-analyzer/crates/flycheck/src/lib.rs | 10 +- src/tools/rust-analyzer/crates/hir-def/Cargo.toml | 3 +- src/tools/rust-analyzer/crates/hir-def/src/adt.rs | 554 - src/tools/rust-analyzer/crates/hir-def/src/attr.rs | 241 +- .../crates/hir-def/src/attr/builtin.rs | 693 + .../rust-analyzer/crates/hir-def/src/attr/tests.rs | 40 + src/tools/rust-analyzer/crates/hir-def/src/body.rs | 400 +- .../rust-analyzer/crates/hir-def/src/body/lower.rs | 1072 +- .../crates/hir-def/src/body/pretty.rs | 138 +- .../rust-analyzer/crates/hir-def/src/body/scope.rs | 68 +- .../crates/hir-def/src/body/tests/block.rs | 4 +- .../crates/hir-def/src/builtin_attr.rs | 655 - .../crates/hir-def/src/builtin_type.rs | 10 +- .../crates/hir-def/src/child_by_source.rs | 6 +- src/tools/rust-analyzer/crates/hir-def/src/data.rs | 246 +- .../rust-analyzer/crates/hir-def/src/data/adt.rs | 591 + src/tools/rust-analyzer/crates/hir-def/src/db.rs | 60 +- .../rust-analyzer/crates/hir-def/src/dyn_map.rs | 2 + .../crates/hir-def/src/dyn_map/keys.rs | 70 + .../rust-analyzer/crates/hir-def/src/expander.rs | 211 + src/tools/rust-analyzer/crates/hir-def/src/expr.rs | 498 - .../rust-analyzer/crates/hir-def/src/find_path.rs | 11 +- .../rust-analyzer/crates/hir-def/src/generics.rs | 48 +- src/tools/rust-analyzer/crates/hir-def/src/hir.rs | 558 + .../crates/hir-def/src/hir/type_ref.rs | 505 + .../rust-analyzer/crates/hir-def/src/import_map.rs | 98 +- .../rust-analyzer/crates/hir-def/src/item_scope.rs | 14 +- .../rust-analyzer/crates/hir-def/src/item_tree.rs | 21 +- .../crates/hir-def/src/item_tree/lower.rs | 30 +- .../crates/hir-def/src/item_tree/pretty.rs | 91 +- .../crates/hir-def/src/item_tree/tests.rs | 14 +- src/tools/rust-analyzer/crates/hir-def/src/keys.rs | 70 - .../rust-analyzer/crates/hir-def/src/lang_item.rs | 293 +- .../rust-analyzer/crates/hir-def/src/layout.rs | 97 - src/tools/rust-analyzer/crates/hir-def/src/lib.rs | 407 +- .../rust-analyzer/crates/hir-def/src/lower.rs | 45 + .../crates/hir-def/src/macro_expansion_tests.rs | 356 - .../macro_expansion_tests/builtin_derive_macro.rs | 360 +- .../src/macro_expansion_tests/builtin_fn_macro.rs | 149 +- .../hir-def/src/macro_expansion_tests/mbe.rs | 131 +- .../src/macro_expansion_tests/mbe/matching.rs | 7 +- .../src/macro_expansion_tests/mbe/metavar_expr.rs | 311 + .../src/macro_expansion_tests/mbe/regression.rs | 20 +- .../src/macro_expansion_tests/mbe/tt_conversion.rs | 2 +- .../hir-def/src/macro_expansion_tests/mod.rs | 357 + .../rust-analyzer/crates/hir-def/src/nameres.rs | 286 +- .../crates/hir-def/src/nameres/attr_resolution.rs | 21 +- .../crates/hir-def/src/nameres/collector.rs | 661 +- .../crates/hir-def/src/nameres/diagnostics.rs | 31 +- .../crates/hir-def/src/nameres/mod_resolution.rs | 18 +- .../crates/hir-def/src/nameres/path_resolution.rs | 141 +- .../crates/hir-def/src/nameres/proc_macro.rs | 2 +- .../crates/hir-def/src/nameres/tests.rs | 3 +- .../hir-def/src/nameres/tests/incremental.rs | 17 +- .../crates/hir-def/src/nameres/tests/macros.rs | 256 +- .../hir-def/src/nameres/tests/mod_resolution.rs | 2 +- src/tools/rust-analyzer/crates/hir-def/src/path.rs | 91 +- .../rust-analyzer/crates/hir-def/src/path/lower.rs | 21 +- .../rust-analyzer/crates/hir-def/src/pretty.rs | 80 +- .../rust-analyzer/crates/hir-def/src/resolver.rs | 152 +- src/tools/rust-analyzer/crates/hir-def/src/src.rs | 10 +- .../rust-analyzer/crates/hir-def/src/test_db.rs | 31 +- .../rust-analyzer/crates/hir-def/src/type_ref.rs | 490 - .../rust-analyzer/crates/hir-def/src/visibility.rs | 3 +- .../rust-analyzer/crates/hir-expand/Cargo.toml | 1 + .../crates/hir-expand/src/ast_id_map.rs | 16 +- .../rust-analyzer/crates/hir-expand/src/attrs.rs | 151 +- .../crates/hir-expand/src/builtin_attr_macro.rs | 2 +- .../crates/hir-expand/src/builtin_derive_macro.rs | 713 +- .../crates/hir-expand/src/builtin_fn_macro.rs | 335 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 256 +- .../rust-analyzer/crates/hir-expand/src/eager.rs | 240 +- .../rust-analyzer/crates/hir-expand/src/fixup.rs | 4 +- .../rust-analyzer/crates/hir-expand/src/hygiene.rs | 13 +- .../rust-analyzer/crates/hir-expand/src/lib.rs | 214 +- .../crates/hir-expand/src/mod_path.rs | 102 +- .../rust-analyzer/crates/hir-expand/src/name.rs | 80 +- .../crates/hir-expand/src/proc_macro.rs | 53 +- .../rust-analyzer/crates/hir-expand/src/quote.rs | 6 + src/tools/rust-analyzer/crates/hir-ty/Cargo.toml | 12 +- .../rust-analyzer/crates/hir-ty/src/autoderef.rs | 84 +- .../rust-analyzer/crates/hir-ty/src/builder.rs | 50 +- .../rust-analyzer/crates/hir-ty/src/chalk_db.rs | 149 +- .../rust-analyzer/crates/hir-ty/src/chalk_ext.rs | 55 +- .../rust-analyzer/crates/hir-ty/src/consteval.rs | 119 +- .../crates/hir-ty/src/consteval/tests.rs | 1559 ++- .../hir-ty/src/consteval/tests/intrinsics.rs | 377 + src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 115 +- .../crates/hir-ty/src/diagnostics/decl_check.rs | 43 +- .../crates/hir-ty/src/diagnostics/expr.rs | 6 +- .../crates/hir-ty/src/diagnostics/match_check.rs | 51 +- .../src/diagnostics/match_check/deconstruct_pat.rs | 12 +- .../hir-ty/src/diagnostics/match_check/pat_util.rs | 2 +- .../src/diagnostics/match_check/usefulness.rs | 2 +- .../crates/hir-ty/src/diagnostics/unsafe_check.rs | 11 +- .../rust-analyzer/crates/hir-ty/src/display.rs | 671 +- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 542 +- .../crates/hir-ty/src/infer/closure.rs | 931 +- .../crates/hir-ty/src/infer/coerce.rs | 64 +- .../rust-analyzer/crates/hir-ty/src/infer/expr.rs | 461 +- .../crates/hir-ty/src/infer/mutability.rs | 218 + .../rust-analyzer/crates/hir-ty/src/infer/pat.rs | 59 +- .../rust-analyzer/crates/hir-ty/src/infer/path.rs | 127 +- .../rust-analyzer/crates/hir-ty/src/infer/unify.rs | 157 +- .../crates/hir-ty/src/inhabitedness.rs | 30 +- .../rust-analyzer/crates/hir-ty/src/interner.rs | 147 +- .../rust-analyzer/crates/hir-ty/src/lang_items.rs | 68 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 150 +- .../rust-analyzer/crates/hir-ty/src/layout/adt.rs | 106 +- .../crates/hir-ty/src/layout/target.rs | 3 +- .../crates/hir-ty/src/layout/tests.rs | 192 +- .../crates/hir-ty/src/layout/tests/closure.rs | 257 + src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 85 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 325 +- .../crates/hir-ty/src/method_resolution.rs | 305 +- src/tools/rust-analyzer/crates/hir-ty/src/mir.rs | 343 +- .../crates/hir-ty/src/mir/borrowck.rs | 282 +- .../rust-analyzer/crates/hir-ty/src/mir/eval.rs | 2209 +++- .../crates/hir-ty/src/mir/eval/shim.rs | 792 ++ .../crates/hir-ty/src/mir/eval/tests.rs | 676 + .../rust-analyzer/crates/hir-ty/src/mir/lower.rs | 1795 +-- .../crates/hir-ty/src/mir/lower/as_place.rs | 163 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 617 + .../crates/hir-ty/src/mir/monomorphization.rs | 351 + .../rust-analyzer/crates/hir-ty/src/mir/pretty.rs | 185 +- .../rust-analyzer/crates/hir-ty/src/test_db.rs | 20 +- src/tools/rust-analyzer/crates/hir-ty/src/tests.rs | 45 +- .../crates/hir-ty/src/tests/coercion.rs | 111 +- .../crates/hir-ty/src/tests/incremental.rs | 8 +- .../crates/hir-ty/src/tests/macros.rs | 59 +- .../crates/hir-ty/src/tests/method_resolution.rs | 74 +- .../crates/hir-ty/src/tests/never_type.rs | 47 + .../crates/hir-ty/src/tests/patterns.rs | 43 +- .../crates/hir-ty/src/tests/regression.rs | 234 +- .../crates/hir-ty/src/tests/simple.rs | 398 +- .../crates/hir-ty/src/tests/traits.rs | 383 +- src/tools/rust-analyzer/crates/hir-ty/src/tls.rs | 22 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 55 +- src/tools/rust-analyzer/crates/hir-ty/src/utils.rs | 154 +- src/tools/rust-analyzer/crates/hir/Cargo.toml | 1 + src/tools/rust-analyzer/crates/hir/src/attrs.rs | 8 +- src/tools/rust-analyzer/crates/hir/src/db.rs | 4 +- .../rust-analyzer/crates/hir/src/diagnostics.rs | 59 +- src/tools/rust-analyzer/crates/hir/src/display.rs | 72 +- src/tools/rust-analyzer/crates/hir/src/from_id.rs | 5 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 796 +- .../rust-analyzer/crates/hir/src/semantics.rs | 66 +- .../crates/hir/src/semantics/source_to_def.rs | 10 +- .../crates/hir/src/source_analyzer.rs | 94 +- src/tools/rust-analyzer/crates/hir/src/symbols.rs | 297 +- .../ide-assists/src/handlers/add_explicit_type.rs | 2 +- .../src/handlers/add_missing_impl_members.rs | 538 +- .../src/handlers/add_missing_match_arms.rs | 2 +- .../ide-assists/src/handlers/add_return_type.rs | 6 +- .../crates/ide-assists/src/handlers/auto_import.rs | 6 +- .../ide-assists/src/handlers/convert_bool_then.rs | 2 +- .../src/handlers/convert_iter_for_each_to_for.rs | 2 +- .../src/handlers/convert_let_else_to_match.rs | 161 +- .../src/handlers/convert_match_to_let_else.rs | 37 +- .../convert_named_struct_to_tuple_struct.rs | 248 +- .../handlers/convert_nested_function_to_closure.rs | 209 + .../src/handlers/convert_to_guarded_return.rs | 2 +- .../convert_tuple_struct_to_named_struct.rs | 3 +- .../src/handlers/destructure_tuple_binding.rs | 2 +- .../ide-assists/src/handlers/expand_glob_import.rs | 2 +- .../ide-assists/src/handlers/extract_function.rs | 185 +- .../ide-assists/src/handlers/extract_module.rs | 11 +- .../handlers/extract_struct_from_enum_variant.rs | 4 +- .../ide-assists/src/handlers/extract_type_alias.rs | 51 +- .../ide-assists/src/handlers/extract_variable.rs | 58 +- .../ide-assists/src/handlers/fix_visibility.rs | 11 +- .../ide-assists/src/handlers/generate_constant.rs | 9 +- .../src/handlers/generate_delegate_methods.rs | 133 +- .../ide-assists/src/handlers/generate_deref.rs | 6 +- .../ide-assists/src/handlers/generate_derive.rs | 41 +- .../handlers/generate_documentation_template.rs | 4 +- .../src/handlers/generate_enum_variant.rs | 2 +- .../ide-assists/src/handlers/generate_function.rs | 125 +- .../ide-assists/src/handlers/generate_getter.rs | 2 +- .../ide-assists/src/handlers/generate_new.rs | 6 +- .../crates/ide-assists/src/handlers/inline_call.rs | 3 +- .../src/handlers/inline_const_as_literal.rs | 722 ++ .../ide-assists/src/handlers/inline_macro.rs | 47 +- .../src/handlers/introduce_named_generic.rs | 30 +- .../src/handlers/introduce_named_lifetime.rs | 4 +- .../ide-assists/src/handlers/merge_match_arms.rs | 28 +- .../ide-assists/src/handlers/move_const_to_impl.rs | 2 +- .../ide-assists/src/handlers/move_from_mod_rs.rs | 2 +- .../src/handlers/move_module_to_file.rs | 2 +- .../ide-assists/src/handlers/move_to_mod_rs.rs | 2 +- .../src/handlers/promote_local_to_const.rs | 14 +- .../ide-assists/src/handlers/pull_assignment_up.rs | 4 +- .../src/handlers/qualify_method_call.rs | 4 +- .../ide-assists/src/handlers/qualify_path.rs | 10 +- .../crates/ide-assists/src/handlers/raw_string.rs | 4 +- .../ide-assists/src/handlers/remove_parentheses.rs | 2 +- .../src/handlers/remove_unused_param.rs | 2 +- .../ide-assists/src/handlers/reorder_fields.rs | 7 +- .../ide-assists/src/handlers/reorder_impl_items.rs | 43 +- .../handlers/replace_derive_with_manual_impl.rs | 30 +- .../handlers/replace_named_generic_with_impl.rs | 351 + .../src/handlers/replace_string_with_char.rs | 4 +- .../src/handlers/replace_try_expr_with_match.rs | 6 +- .../replace_turbofish_with_explicit_type.rs | 2 +- .../crates/ide-assists/src/handlers/sort_items.rs | 111 +- .../ide-assists/src/handlers/unwrap_block.rs | 8 +- .../src/handlers/unwrap_result_return_type.rs | 119 +- .../rust-analyzer/crates/ide-assists/src/lib.rs | 8 +- .../rust-analyzer/crates/ide-assists/src/tests.rs | 7 +- .../crates/ide-assists/src/tests/generated.rs | 67 +- .../crates/ide-assists/src/tests/sourcegen.rs | 2 - .../rust-analyzer/crates/ide-assists/src/utils.rs | 110 +- .../crates/ide-assists/src/utils/suggest_name.rs | 4 +- .../crates/ide-completion/src/completions.rs | 132 +- .../ide-completion/src/completions/attribute.rs | 8 +- .../src/completions/attribute/cfg.rs | 6 +- .../src/completions/attribute/derive.rs | 8 +- .../src/completions/attribute/lint.rs | 2 +- .../src/completions/attribute/repr.rs | 2 +- .../crates/ide-completion/src/completions/dot.rs | 161 +- .../ide-completion/src/completions/env_vars.rs | 6 +- .../crates/ide-completion/src/completions/expr.rs | 18 +- .../ide-completion/src/completions/extern_abi.rs | 4 +- .../ide-completion/src/completions/flyimport.rs | 84 +- .../ide-completion/src/completions/fn_param.rs | 10 +- .../src/completions/format_string.rs | 2 +- .../ide-completion/src/completions/item_list.rs | 6 +- .../src/completions/item_list/trait_impl.rs | 149 +- .../ide-completion/src/completions/lifetime.rs | 1 + .../crates/ide-completion/src/completions/mod_.rs | 4 +- .../ide-completion/src/completions/pattern.rs | 8 +- .../ide-completion/src/completions/postfix.rs | 47 +- .../src/completions/postfix/format_like.rs | 2 +- .../ide-completion/src/completions/record.rs | 4 +- .../ide-completion/src/completions/snippet.rs | 14 +- .../crates/ide-completion/src/completions/type.rs | 12 +- .../crates/ide-completion/src/completions/use_.rs | 13 +- .../crates/ide-completion/src/completions/vis.rs | 2 +- .../crates/ide-completion/src/context.rs | 45 +- .../crates/ide-completion/src/context/analysis.rs | 6 +- .../crates/ide-completion/src/item.rs | 49 +- .../rust-analyzer/crates/ide-completion/src/lib.rs | 6 +- .../crates/ide-completion/src/render.rs | 52 +- .../crates/ide-completion/src/render/const_.rs | 2 +- .../crates/ide-completion/src/render/function.rs | 11 +- .../crates/ide-completion/src/render/literal.rs | 8 +- .../crates/ide-completion/src/render/macro_.rs | 6 +- .../crates/ide-completion/src/render/pattern.rs | 9 +- .../crates/ide-completion/src/render/type_alias.rs | 2 +- .../ide-completion/src/render/union_literal.rs | 20 +- .../crates/ide-completion/src/render/variant.rs | 6 +- .../crates/ide-completion/src/tests.rs | 22 +- .../crates/ide-completion/src/tests/expression.rs | 111 +- .../crates/ide-completion/src/tests/flyimport.rs | 56 + .../crates/ide-completion/src/tests/item_list.rs | 54 +- .../crates/ide-completion/src/tests/pattern.rs | 60 +- .../crates/ide-completion/src/tests/predicate.rs | 42 +- .../crates/ide-completion/src/tests/proc_macros.rs | 4 +- .../crates/ide-completion/src/tests/special.rs | 291 + .../crates/ide-completion/src/tests/type_pos.rs | 52 +- .../crates/ide-completion/src/tests/use_tree.rs | 47 + src/tools/rust-analyzer/crates/ide-db/Cargo.toml | 4 + .../crates/ide-db/src/apply_change.rs | 39 +- .../rust-analyzer/crates/ide-db/src/assists.rs | 2 +- src/tools/rust-analyzer/crates/ide-db/src/defs.rs | 23 +- .../crates/ide-db/src/generated/lints.rs | 4 +- .../rust-analyzer/crates/ide-db/src/helpers.rs | 2 +- .../crates/ide-db/src/imports/import_assets.rs | 4 +- .../crates/ide-db/src/items_locator.rs | 34 +- src/tools/rust-analyzer/crates/ide-db/src/lib.rs | 225 +- .../rust-analyzer/crates/ide-db/src/line_index.rs | 314 - .../crates/ide-db/src/path_transform.rs | 167 +- .../rust-analyzer/crates/ide-db/src/rename.rs | 35 +- .../rust-analyzer/crates/ide-db/src/search.rs | 35 +- .../crates/ide-db/src/source_change.rs | 125 +- .../crates/ide-db/src/symbol_index.rs | 103 +- .../ide-db/src/syntax_helpers/format_string.rs | 2 +- .../src/syntax_helpers/format_string_exprs.rs | 2 +- .../syntax_helpers/insert_whitespace_into_node.rs | 4 +- .../crates/ide-db/src/syntax_helpers/node_ext.rs | 4 +- .../crates/ide-db/src/test_data/test_doc_alias.txt | 216 + .../src/test_data/test_symbol_index_collection.txt | 372 +- .../crates/ide-db/src/tests/line_index.rs | 49 + .../rust-analyzer/crates/ide-db/src/traits.rs | 18 +- .../crates/ide-db/src/use_trivial_constructor.rs | 4 +- .../src/handlers/break_outside_of_loop.rs | 41 +- .../ide-diagnostics/src/handlers/incorrect_case.rs | 4 +- .../ide-diagnostics/src/handlers/macro_error.rs | 45 + .../ide-diagnostics/src/handlers/missing_fields.rs | 10 +- .../src/handlers/missing_match_arms.rs | 18 +- .../ide-diagnostics/src/handlers/missing_unsafe.rs | 7 +- .../src/handlers/moved_out_of_ref.rs | 175 + .../src/handlers/mutability_errors.rs | 474 +- .../ide-diagnostics/src/handlers/no_such_field.rs | 4 +- .../src/handlers/private_assoc_item.rs | 6 +- .../ide-diagnostics/src/handlers/private_field.rs | 4 +- .../replace_filter_map_next_with_find_map.rs | 4 +- .../ide-diagnostics/src/handlers/type_mismatch.rs | 145 +- .../ide-diagnostics/src/handlers/typed_hole.rs | 232 + .../src/handlers/undeclared_label.rs | 88 + .../ide-diagnostics/src/handlers/unlinked_file.rs | 30 +- .../src/handlers/unreachable_label.rs | 91 + .../src/handlers/unresolved_field.rs | 6 +- .../src/handlers/unresolved_macro_call.rs | 2 +- .../src/handlers/unresolved_method.rs | 4 +- .../src/handlers/unresolved_module.rs | 2 +- .../src/handlers/unresolved_proc_macro.rs | 24 +- .../crates/ide-diagnostics/src/lib.rs | 47 +- .../crates/ide-diagnostics/src/tests.rs | 36 +- src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml | 2 + src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs | 9 +- .../rust-analyzer/crates/ide-ssr/src/replacing.rs | 18 +- .../rust-analyzer/crates/ide-ssr/src/tests.rs | 2 +- src/tools/rust-analyzer/crates/ide/Cargo.toml | 2 + .../rust-analyzer/crates/ide/src/call_hierarchy.rs | 8 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 177 +- .../crates/ide/src/doc_links/tests.rs | 152 +- .../rust-analyzer/crates/ide/src/expand_macro.rs | 85 +- .../crates/ide/src/extend_selection.rs | 2 +- .../rust-analyzer/crates/ide/src/fetch_crates.rs | 42 + .../rust-analyzer/crates/ide/src/file_structure.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/fixture.rs | 15 +- .../crates/ide/src/goto_definition.rs | 54 +- .../crates/ide/src/goto_type_definition.rs | 89 +- .../crates/ide/src/highlight_related.rs | 351 +- src/tools/rust-analyzer/crates/ide/src/hover.rs | 44 +- .../rust-analyzer/crates/ide/src/hover/render.rs | 333 +- .../rust-analyzer/crates/ide/src/hover/tests.rs | 897 +- .../rust-analyzer/crates/ide/src/inlay_hints.rs | 146 +- .../crates/ide/src/inlay_hints/adjustment.rs | 113 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 450 +- .../crates/ide/src/inlay_hints/binding_mode.rs | 27 +- .../crates/ide/src/inlay_hints/chaining.rs | 93 +- .../crates/ide/src/inlay_hints/closing_brace.rs | 8 +- .../crates/ide/src/inlay_hints/closure_captures.rs | 207 + .../crates/ide/src/inlay_hints/closure_ret.rs | 80 +- .../crates/ide/src/inlay_hints/discriminant.rs | 144 +- .../crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 14 +- .../crates/ide/src/inlay_hints/implicit_static.rs | 6 +- .../crates/ide/src/inlay_hints/param_name.rs | 17 +- .../crates/ide/src/interpret_function.rs | 46 + src/tools/rust-analyzer/crates/ide/src/lib.rs | 61 +- src/tools/rust-analyzer/crates/ide/src/moniker.rs | 122 +- .../crates/ide/src/navigation_target.rs | 213 +- .../rust-analyzer/crates/ide/src/prime_caches.rs | 11 +- .../rust-analyzer/crates/ide/src/references.rs | 26 +- .../rust-analyzer/crates/ide/src/runnables.rs | 46 +- .../crates/ide/src/shuffle_crate_graph.rs | 11 +- .../rust-analyzer/crates/ide/src/signature_help.rs | 502 +- src/tools/rust-analyzer/crates/ide/src/ssr.rs | 3 +- .../rust-analyzer/crates/ide/src/static_index.rs | 4 +- src/tools/rust-analyzer/crates/ide/src/status.rs | 241 +- .../crates/ide/src/syntax_highlighting.rs | 163 +- .../crates/ide/src/syntax_highlighting/escape.rs | 24 +- .../ide/src/syntax_highlighting/highlight.rs | 10 +- .../crates/ide/src/syntax_highlighting/inject.rs | 29 +- .../crates/ide/src/syntax_highlighting/tags.rs | 8 +- .../test_data/highlight_doctest.html | 6 +- .../test_data/highlight_extern_crate.html | 2 +- .../test_data/highlight_general.html | 6 +- .../test_data/highlight_injection.html | 24 +- .../test_data/highlight_keywords.html | 2 +- .../test_data/highlight_macros.html | 28 +- .../test_data/highlight_strings.html | 124 +- .../test_data/highlight_unsafe.html | 10 +- .../crates/ide/src/syntax_highlighting/tests.rs | 16 +- .../rust-analyzer/crates/ide/src/syntax_tree.rs | 6 +- .../crates/ide/src/view_crate_graph.rs | 10 +- .../rust-analyzer/crates/ide/src/view_item_tree.rs | 2 +- src/tools/rust-analyzer/crates/intern/Cargo.toml | 1 + src/tools/rust-analyzer/crates/intern/src/lib.rs | 95 +- src/tools/rust-analyzer/crates/limit/src/lib.rs | 1 + .../rust-analyzer/crates/mbe/src/benchmark.rs | 15 +- src/tools/rust-analyzer/crates/mbe/src/expander.rs | 5 +- .../crates/mbe/src/expander/matcher.rs | 34 +- .../crates/mbe/src/expander/transcriber.rs | 128 +- src/tools/rust-analyzer/crates/mbe/src/lib.rs | 49 +- src/tools/rust-analyzer/crates/mbe/src/parser.rs | 36 +- .../rust-analyzer/crates/mbe/src/syntax_bridge.rs | 74 +- src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs | 7 - src/tools/rust-analyzer/crates/parser/Cargo.toml | 2 +- .../rust-analyzer/crates/parser/src/grammar.rs | 15 +- .../crates/parser/src/grammar/expressions.rs | 91 +- .../crates/parser/src/grammar/expressions/atom.rs | 13 + .../crates/parser/src/grammar/generic_args.rs | 26 +- .../crates/parser/src/grammar/items.rs | 2 +- .../crates/parser/src/grammar/paths.rs | 1 + .../crates/parser/src/grammar/patterns.rs | 103 +- .../crates/parser/src/grammar/types.rs | 24 +- .../rust-analyzer/crates/parser/src/lexed_str.rs | 56 +- src/tools/rust-analyzer/crates/parser/src/lib.rs | 2 + .../rust-analyzer/crates/parser/src/parser.rs | 2 +- .../rust-analyzer/crates/parser/src/shortcuts.rs | 6 +- .../crates/parser/src/syntax_kind/generated.rs | 4 +- .../crates/parser/src/tests/prefix_entries.rs | 3 +- .../lexer/err/unclosed_raw_byte_string_at_eof.rast | 2 +- ...unclosed_raw_byte_string_with_ascii_escape.rast | 2 +- .../err/unclosed_raw_byte_string_with_ferris.rast | 2 +- .../err/unclosed_raw_byte_string_with_slash.rast | 2 +- .../err/unclosed_raw_byte_string_with_slash_n.rast | 2 +- .../err/unclosed_raw_byte_string_with_space.rast | 2 +- ...closed_raw_byte_string_with_unicode_escape.rast | 2 +- .../lexer/err/unclosed_raw_string_at_eof.rast | 2 +- .../err/unclosed_raw_string_with_ascii_escape.rast | 2 +- .../lexer/err/unclosed_raw_string_with_ferris.rast | 2 +- .../lexer/err/unclosed_raw_string_with_slash.rast | 2 +- .../err/unclosed_raw_string_with_slash_n.rast | 2 +- .../lexer/err/unclosed_raw_string_with_space.rast | 2 +- .../unclosed_raw_string_with_unicode_escape.rast | 2 +- .../err/unstarted_raw_byte_string_at_eof.rast | 2 +- .../err/unstarted_raw_byte_string_with_ascii.rast | 2 +- .../lexer/err/unstarted_raw_string_at_eof.rast | 2 +- .../lexer/err/unstarted_raw_string_with_ascii.rast | 2 +- .../parser/err/0027_incomplere_where_for.rast | 29 - .../parser/err/0027_incomplere_where_for.rs | 3 - .../parser/err/0027_incomplete_where_for.rast | 29 + .../parser/err/0027_incomplete_where_for.rs | 3 + .../parser/err/0047_repated_extern_modifier.rast | 15 - .../parser/err/0047_repated_extern_modifier.rs | 1 - .../parser/err/0047_repeated_extern_modifier.rast | 15 + .../parser/err/0047_repeated_extern_modifier.rs | 1 + .../err/0018_crate_visibility_empty_recover.rast | 18 + .../err/0018_crate_visibility_empty_recover.rs | 1 + .../inline/err/0019_tuple_expr_leading_comma.rast | 24 + .../inline/err/0019_tuple_expr_leading_comma.rs | 3 + .../inline/err/0020_tuple_pat_leading_comma.rast | 26 + .../inline/err/0020_tuple_pat_leading_comma.rs | 3 + .../parser/inline/ok/0017_array_type.rast | 5 +- .../parser/inline/ok/0085_expr_literals.rast | 24 + .../parser/inline/ok/0085_expr_literals.rs | 2 + .../parser/inline/ok/0156_const_block_pat.rast | 120 + .../parser/inline/ok/0156_const_block_pat.rs | 8 + .../parser/inline/ok/0196_pub_tuple_field.rast | 39 + .../parser/inline/ok/0196_pub_tuple_field.rs | 2 + .../inline/ok/0202_typepathfn_with_coloncolon.rast | 38 + .../inline/ok/0202_typepathfn_with_coloncolon.rs | 1 + .../parser/inline/ok/0207_exclusive_range_pat.rast | 58 + .../parser/inline/ok/0207_exclusive_range_pat.rs | 6 + .../ok/0208_associated_return_type_bounds.rast | 102 + .../ok/0208_associated_return_type_bounds.rs | 1 + .../0208_bare_dyn_types_with_leading_lifetime.rast | 58 + .../0208_bare_dyn_types_with_leading_lifetime.rs | 2 + ..._bare_dyn_types_with_paren_as_generic_args.rast | 175 + ...09_bare_dyn_types_with_paren_as_generic_args.rs | 4 + .../parser/ok/0028_operator_binding_power.rast | 269 + .../parser/ok/0028_operator_binding_power.rs | 13 + .../parser/test_data/parser/ok/0030_traits.rast | 5 +- .../parser/ok/0043_complex_assignment.rast | 5 +- .../test_data/parser/ok/0045_block_attrs.rast | 2 +- .../parser/test_data/parser/ok/0045_block_attrs.rs | 2 +- .../parser/ok/0072_destructuring_assignment.rast | 76 +- .../parser/ok/0072_destructuring_assignment.rs | 2 +- src/tools/rust-analyzer/crates/paths/Cargo.toml | 2 +- src/tools/rust-analyzer/crates/paths/src/lib.rs | 16 + .../rust-analyzer/crates/proc-macro-api/Cargo.toml | 5 +- .../rust-analyzer/crates/proc-macro-api/src/lib.rs | 37 +- .../rust-analyzer/crates/proc-macro-api/src/msg.rs | 10 +- .../crates/proc-macro-api/src/msg/flat.rs | 60 +- .../crates/proc-macro-api/src/process.rs | 28 +- .../crates/proc-macro-api/src/version.rs | 2 +- .../crates/proc-macro-srv-cli/Cargo.toml | 1 + .../crates/proc-macro-srv-cli/src/main.rs | 38 +- .../rust-analyzer/crates/proc-macro-srv/Cargo.toml | 1 + .../crates/proc-macro-srv/src/abis/abi_1_63/mod.rs | 106 - .../src/abis/abi_1_63/proc_macro/bridge/buffer.rs | 156 - .../src/abis/abi_1_63/proc_macro/bridge/client.rs | 510 - .../src/abis/abi_1_63/proc_macro/bridge/closure.rs | 32 - .../src/abis/abi_1_63/proc_macro/bridge/handle.rs | 89 - .../src/abis/abi_1_63/proc_macro/bridge/mod.rs | 451 - .../src/abis/abi_1_63/proc_macro/bridge/rpc.rs | 304 - .../abis/abi_1_63/proc_macro/bridge/scoped_cell.rs | 81 - .../abi_1_63/proc_macro/bridge/selfless_reify.rs | 83 - .../src/abis/abi_1_63/proc_macro/bridge/server.rs | 332 - .../src/abis/abi_1_63/proc_macro/diagnostic.rs | 166 - .../src/abis/abi_1_63/proc_macro/mod.rs | 1106 -- .../src/abis/abi_1_63/proc_macro/quote.rs | 139 - .../proc-macro-srv/src/abis/abi_1_63/ra_server.rs | 840 -- .../proc-macro-srv/src/abis/abi_sysroot/mod.rs | 104 - .../src/abis/abi_sysroot/ra_server.rs | 473 - .../src/abis/abi_sysroot/ra_server/symbol.rs | 46 - .../src/abis/abi_sysroot/ra_server/token_stream.rs | 183 - .../crates/proc-macro-srv/src/abis/mod.rs | 146 - .../rust-analyzer/crates/proc-macro-srv/src/cli.rs | 34 - .../crates/proc-macro-srv/src/dylib.rs | 28 +- .../rust-analyzer/crates/proc-macro-srv/src/lib.rs | 57 +- .../crates/proc-macro-srv/src/proc_macros.rs | 127 + .../crates/proc-macro-srv/src/server.rs | 484 + .../crates/proc-macro-srv/src/server/symbol.rs | 48 + .../proc-macro-srv/src/server/token_stream.rs | 183 + .../crates/proc-macro-srv/src/tests/utils.rs | 4 +- src/tools/rust-analyzer/crates/profile/Cargo.toml | 2 +- .../crates/profile/src/memory_usage.rs | 6 + .../rust-analyzer/crates/project-model/Cargo.toml | 6 +- .../crates/project-model/src/build_scripts.rs | 29 +- .../crates/project-model/src/cargo_workspace.rs | 92 +- .../crates/project-model/src/cfg_flag.rs | 8 + .../rust-analyzer/crates/project-model/src/lib.rs | 2 +- .../crates/project-model/src/manifest_path.rs | 4 + .../crates/project-model/src/project_json.rs | 39 +- .../crates/project-model/src/sysroot.rs | 64 +- .../crates/project-model/src/target_data_layout.rs | 2 +- .../crates/project-model/src/tests.rs | 1881 +-- .../crates/project-model/src/workspace.rs | 657 +- .../output/cargo_hello_world_project_model.txt | 344 + ...orld_project_model_with_selective_overrides.txt | 344 + ...world_project_model_with_wildcard_overrides.txt | 340 + .../rust_project_hello_world_project_model.txt | 462 + .../project-model/test_data/regex-metadata.json | 6420 ++++++++++ .../project-model/test_data/ripgrep-metadata.json | 12816 +++++++++++++++++++ .../rust-analyzer/crates/rust-analyzer/Cargo.toml | 26 +- .../crates/rust-analyzer/src/bin/main.rs | 100 +- .../rust-analyzer/crates/rust-analyzer/src/caps.rs | 11 +- .../crates/rust-analyzer/src/cargo_target_spec.rs | 18 +- .../rust-analyzer/crates/rust-analyzer/src/cli.rs | 17 +- .../crates/rust-analyzer/src/cli/analysis_stats.rs | 421 +- .../crates/rust-analyzer/src/cli/diagnostics.rs | 8 +- .../crates/rust-analyzer/src/cli/flags.rs | 29 +- .../crates/rust-analyzer/src/cli/load_cargo.rs | 74 +- .../rust-analyzer/src/cli/progress_report.rs | 41 +- .../crates/rust-analyzer/src/cli/scip.rs | 19 +- .../crates/rust-analyzer/src/config.rs | 293 +- .../crates/rust-analyzer/src/diagnostics.rs | 17 +- .../rust-analyzer/src/diagnostics/to_proto.rs | 43 +- .../crates/rust-analyzer/src/dispatch.rs | 90 +- .../crates/rust-analyzer/src/from_proto.rs | 22 +- .../crates/rust-analyzer/src/global_state.rs | 134 +- .../crates/rust-analyzer/src/handlers.rs | 1910 --- .../rust-analyzer/src/handlers/notification.rs | 334 + .../crates/rust-analyzer/src/handlers/request.rs | 1989 +++ .../rust-analyzer/src/integrated_benchmarks.rs | 9 +- .../rust-analyzer/crates/rust-analyzer/src/lib.rs | 6 +- .../crates/rust-analyzer/src/line_index.rs | 3 +- .../crates/rust-analyzer/src/lsp_ext.rs | 71 +- .../crates/rust-analyzer/src/lsp_utils.rs | 38 +- .../crates/rust-analyzer/src/main_loop.rs | 655 +- .../crates/rust-analyzer/src/markdown.rs | 10 +- .../crates/rust-analyzer/src/op_queue.rs | 14 +- .../crates/rust-analyzer/src/reload.rs | 319 +- .../crates/rust-analyzer/src/semantic_tokens.rs | 59 +- .../crates/rust-analyzer/src/task_pool.rs | 33 +- .../crates/rust-analyzer/src/to_proto.rs | 200 +- .../crates/rust-analyzer/tests/slow-tests/main.rs | 89 +- .../rust-analyzer/tests/slow-tests/support.rs | 32 +- .../crates/rust-analyzer/tests/slow-tests/tidy.rs | 2 + .../rust-analyzer/crates/sourcegen/src/lib.rs | 26 +- src/tools/rust-analyzer/crates/stdx/Cargo.toml | 2 + src/tools/rust-analyzer/crates/stdx/src/hash.rs | 80 - src/tools/rust-analyzer/crates/stdx/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/stdx/src/thread.rs | 102 + .../rust-analyzer/crates/stdx/src/thread/intent.rs | 287 + .../rust-analyzer/crates/stdx/src/thread/pool.rs | 92 + src/tools/rust-analyzer/crates/syntax/Cargo.toml | 8 +- src/tools/rust-analyzer/crates/syntax/rust.ungram | 10 +- .../crates/syntax/src/ast/edit_in_place.rs | 17 + .../crates/syntax/src/ast/expr_ext.rs | 7 +- .../crates/syntax/src/ast/generated/nodes.rs | 5 +- .../crates/syntax/src/ast/generated/tokens.rs | 21 + .../rust-analyzer/crates/syntax/src/ast/make.rs | 155 +- .../crates/syntax/src/ast/token_ext.rs | 71 +- src/tools/rust-analyzer/crates/syntax/src/lib.rs | 3 +- .../crates/syntax/src/parsing/reparsing.rs | 8 +- .../crates/syntax/src/tests/ast_src.rs | 3 +- .../crates/syntax/src/tests/sourcegen_ast.rs | 10 +- .../rust-analyzer/crates/syntax/src/token_text.rs | 7 + .../rust-analyzer/crates/syntax/src/validation.rs | 56 +- .../syntax/test_data/parser/fuzz-failures/0000.rs | 4 +- .../rust-analyzer/crates/test-utils/Cargo.toml | 2 +- .../rust-analyzer/crates/test-utils/src/fixture.rs | 96 +- .../rust-analyzer/crates/test-utils/src/lib.rs | 4 +- .../crates/test-utils/src/minicore.rs | 565 +- .../rust-analyzer/crates/text-edit/Cargo.toml | 2 +- .../rust-analyzer/crates/text-edit/src/lib.rs | 52 + src/tools/rust-analyzer/crates/tt/Cargo.toml | 2 +- src/tools/rust-analyzer/crates/tt/src/lib.rs | 6 + .../rust-analyzer/crates/vfs-notify/Cargo.toml | 2 +- .../rust-analyzer/crates/vfs-notify/src/lib.rs | 4 +- src/tools/rust-analyzer/crates/vfs/Cargo.toml | 1 + src/tools/rust-analyzer/crates/vfs/src/file_set.rs | 4 +- src/tools/rust-analyzer/crates/vfs/src/lib.rs | 23 +- src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs | 5 +- 587 files changed, 64330 insertions(+), 23118 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/adt.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/expander.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/expr.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/hir.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/keys.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/layout.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/lower.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs delete mode 100644 src/tools/rust-analyzer/crates/ide-db/src/line_index.rs create mode 100644 src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt create mode 100644 src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs create mode 100644 src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs create mode 100644 src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs create mode 100644 src/tools/rust-analyzer/crates/ide/src/interpret_function.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/cli.rs create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/server/symbol.rs create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/regex-metadata.json create mode 100644 src/tools/rust-analyzer/crates/project-model/test_data/ripgrep-metadata.json delete mode 100644 src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs create mode 100644 src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs create mode 100644 src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs delete mode 100644 src/tools/rust-analyzer/crates/stdx/src/hash.rs create mode 100644 src/tools/rust-analyzer/crates/stdx/src/thread.rs create mode 100644 src/tools/rust-analyzer/crates/stdx/src/thread/intent.rs create mode 100644 src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs (limited to 'src/tools/rust-analyzer/crates') diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index f6a1075c1..6001772c8 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -15,6 +15,10 @@ doctest = false salsa = "0.17.0-pre.2" rustc-hash = "1.1.0" +triomphe.workspace = true + +la-arena = { version = "0.3.0", path = "../../lib/la-arena" } + # local deps cfg.workspace = true profile.workspace = true 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 b57f23457..6a3b36b23 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -1,19 +1,21 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use std::{fmt, sync::Arc}; +use std::fmt; use salsa::Durability; +use triomphe::Arc; use vfs::FileId; -use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId}; +use crate::{CrateGraph, ProcMacros, SourceDatabaseExt, SourceRoot, SourceRootId}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] pub struct Change { pub roots: Option>, - pub files_changed: Vec<(FileId, Option>)>, + pub files_changed: Vec<(FileId, Option>)>, pub crate_graph: Option, + pub proc_macros: Option, } impl fmt::Debug for Change { @@ -33,7 +35,7 @@ impl fmt::Debug for Change { } impl Change { - pub fn new() -> Change { + pub fn new() -> Self { Change::default() } @@ -41,7 +43,7 @@ impl Change { self.roots = Some(roots); } - pub fn change_file(&mut self, file_id: FileId, new_text: Option>) { + pub fn change_file(&mut self, file_id: FileId, new_text: Option>) { self.files_changed.push((file_id, new_text)) } @@ -49,6 +51,10 @@ impl Change { self.crate_graph = Some(graph); } + pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + self.proc_macros = Some(proc_macros); + } + pub fn apply(self, db: &mut dyn SourceDatabaseExt) { let _p = profile::span("RootDatabase::apply_change"); if let Some(roots) = self.roots { @@ -67,11 +73,14 @@ impl Change { let source_root = db.source_root(source_root_id); let durability = durability(&source_root); // XXX: can't actually remove the file, just reset the text - let text = text.unwrap_or_default(); + let text = text.unwrap_or_else(|| Arc::from("")); db.set_file_text_with_durability(file_id, text, durability) } if let Some(crate_graph) = self.crate_graph { - db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) + db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH); + } + if let Some(proc_macros) = self.proc_macros { + db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); } } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs index 8a7e9dfad..d3abc3870 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs @@ -1,24 +1,27 @@ //! A set of high-level utility fixture methods to use in tests. -use std::{mem, str::FromStr, sync::Arc}; +use std::{mem, str::FromStr, sync}; use cfg::CfgOptions; use rustc_hash::FxHashMap; use test_utils::{ - extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, + extract_range_or_offset, Fixture, FixtureWithProjectMeta, RangeOrOffset, CURSOR_MARKER, + ESCAPED_CURSOR_MARKER, }; +use triomphe::Arc; use tt::token_id::{Leaf, Subtree, TokenTree}; use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt, - SourceRoot, SourceRootId, + FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel, + SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); pub trait WithFixture: Default + SourceDatabaseExt + 'static { + #[track_caller] fn with_single_file(ra_fixture: &str) -> (Self, FileId) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -27,6 +30,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { (db, fixture.files[0]) } + #[track_caller] fn with_many_files(ra_fixture: &str) -> (Self, Vec) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -35,6 +39,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { (db, fixture.files) } + #[track_caller] fn with_files(ra_fixture: &str) -> Self { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -43,6 +48,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { db } + #[track_caller] fn with_files_extra_proc_macros( ra_fixture: &str, proc_macros: Vec<(String, ProcMacro)>, @@ -54,18 +60,21 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { db } + #[track_caller] fn with_position(ra_fixture: &str) -> (Self, FilePosition) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let offset = range_or_offset.expect_offset(); (db, FilePosition { file_id, offset }) } + #[track_caller] fn with_range(ra_fixture: &str) -> (Self, FileRange) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let range = range_or_offset.expect_range(); (db, FileRange { file_id, range }) } + #[track_caller] fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -100,9 +109,16 @@ impl ChangeFixture { pub fn parse_with_proc_macros( ra_fixture: &str, - mut proc_macros: Vec<(String, ProcMacro)>, + mut proc_macro_defs: Vec<(String, ProcMacro)>, ) -> ChangeFixture { - let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture); + let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } = + FixtureWithProjectMeta::parse(ra_fixture); + let toolchain = toolchain + .map(|it| { + ReleaseChannel::from_str(&it) + .unwrap_or_else(|| panic!("unknown release channel found: {it}")) + }) + .unwrap_or(ReleaseChannel::Stable); let mut change = Change::new(); let mut files = Vec::new(); @@ -157,16 +173,16 @@ impl ChangeFixture { meta.edition, Some(crate_name.clone().into()), version, - meta.cfg.clone(), meta.cfg, + Default::default(), meta.env, - Ok(Vec::new()), false, origin, meta.target_data_layout .as_deref() .map(Arc::from) .ok_or_else(|| "target_data_layout unset".into()), + Some(toolchain), ); let prev = crates.insert(crate_name.clone(), crate_id); assert!(prev.is_none()); @@ -182,7 +198,7 @@ impl ChangeFixture { default_target_data_layout = meta.target_data_layout; } - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); let path = VfsPath::new_virtual_path(meta.path); file_set.insert(file_id, path); files.push(file_id); @@ -197,15 +213,15 @@ impl ChangeFixture { Edition::CURRENT, Some(CrateName::new("test").unwrap().into()), None, - default_cfg.clone(), default_cfg, - Env::default(), - Ok(Vec::new()), + Default::default(), + Env::new_for_test_fixture(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, default_target_data_layout .map(|x| x.into()) .ok_or_else(|| "target_data_layout unset".into()), + Some(toolchain), ); } else { for (from, to, prelude) in crate_deps { @@ -232,7 +248,7 @@ impl ChangeFixture { fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string())); roots.push(SourceRoot::new_library(fs)); - change.change_file(core_file, Some(Arc::new(mini_core.source_code()))); + change.change_file(core_file, Some(Arc::from(mini_core.source_code()))); let all_crates = crate_graph.crates_in_topological_order(); @@ -241,13 +257,13 @@ impl ChangeFixture { Edition::Edition2021, Some(CrateDisplayName::from_canonical_name("core".to_string())), None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(Vec::new()), + Default::default(), + Default::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), + Some(toolchain), ); for krate in all_crates { @@ -257,12 +273,13 @@ impl ChangeFixture { } } + let mut proc_macros = ProcMacros::default(); if !proc_macro_names.is_empty() { let proc_lib_file = file_id; file_id.0 += 1; - proc_macros.extend(default_test_proc_macros()); - let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macros); + proc_macro_defs.extend(default_test_proc_macros()); + let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macro_defs); let mut fs = FileSet::default(); fs.insert( proc_lib_file, @@ -270,7 +287,7 @@ impl ChangeFixture { ); roots.push(SourceRoot::new_library(fs)); - change.change_file(proc_lib_file, Some(Arc::new(source))); + change.change_file(proc_lib_file, Some(Arc::from(source))); let all_crates = crate_graph.crates_in_topological_order(); @@ -279,14 +296,15 @@ impl ChangeFixture { Edition::Edition2021, Some(CrateDisplayName::from_canonical_name("proc_macros".to_string())), None, - CfgOptions::default(), - CfgOptions::default(), - Env::default(), - Ok(proc_macro), + Default::default(), + Default::default(), + Env::new_for_test_fixture(), true, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, target_layout, + Some(toolchain), ); + proc_macros.insert(proc_macros_crate, Ok(proc_macro)); for krate in all_crates { crate_graph @@ -305,6 +323,7 @@ impl ChangeFixture { roots.push(root); change.set_roots(roots); change.set_crate_graph(crate_graph); + change.set_proc_macros(proc_macros); ChangeFixture { file_position, files, change } } @@ -323,7 +342,7 @@ pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream { ProcMacro { name: "identity".into(), kind: crate::ProcMacroKind::Attr, - expander: Arc::new(IdentityProcMacroExpander), + expander: sync::Arc::new(IdentityProcMacroExpander), }, ), ( @@ -337,7 +356,7 @@ pub fn derive_identity(item: TokenStream) -> TokenStream { ProcMacro { name: "DeriveIdentity".into(), kind: crate::ProcMacroKind::CustomDerive, - expander: Arc::new(IdentityProcMacroExpander), + expander: sync::Arc::new(IdentityProcMacroExpander), }, ), ( @@ -351,7 +370,7 @@ pub fn input_replace(attr: TokenStream, _item: TokenStream) -> TokenStream { ProcMacro { name: "input_replace".into(), kind: crate::ProcMacroKind::Attr, - expander: Arc::new(AttributeInputReplaceProcMacroExpander), + expander: sync::Arc::new(AttributeInputReplaceProcMacroExpander), }, ), ( @@ -365,7 +384,7 @@ pub fn mirror(input: TokenStream) -> TokenStream { ProcMacro { name: "mirror".into(), kind: crate::ProcMacroKind::FuncLike, - expander: Arc::new(MirrorProcMacroExpander), + expander: sync::Arc::new(MirrorProcMacroExpander), }, ), ( @@ -379,7 +398,7 @@ pub fn shorten(input: TokenStream) -> TokenStream { ProcMacro { name: "shorten".into(), kind: crate::ProcMacroKind::FuncLike, - expander: Arc::new(ShortenProcMacroExpander), + expander: sync::Arc::new(ShortenProcMacroExpander), }, ), ] @@ -428,7 +447,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { let (version, origin) = match b.split_once(':') { Some(("CratesIo", data)) => match data.split_once(',') { Some((version, url)) => { - (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None }) + (version, CrateOrigin::Local { repo: Some(url.to_owned()), name: None }) } _ => panic!("Bad crates.io parameter: {data}"), }, @@ -436,10 +455,9 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { }; (a.to_owned(), origin, Some(version.to_string())) } else { - let crate_origin = match &*crate_str { - "std" => CrateOrigin::Lang(LangCrateOrigin::Std), - "core" => CrateOrigin::Lang(LangCrateOrigin::Core), - _ => CrateOrigin::CratesIo { repo: None, name: None }, + let crate_origin = match LangCrateOrigin::from(&*crate_str) { + LangCrateOrigin::Other => CrateOrigin::Local { repo: None, name: None }, + origin => CrateOrigin::Lang(origin), }; (crate_str, crate_origin, None) } 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 43388e915..f2e523675 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -6,14 +6,20 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; +use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync}; use cfg::CfgOptions; -use rustc_hash::FxHashMap; -use stdx::hash::{NoHashHashMap, NoHashHashSet}; +use la_arena::{Arena, Idx}; +use rustc_hash::{FxHashMap, FxHashSet}; use syntax::SmolStr; +use triomphe::Arc; use tt::token_id::Subtree; -use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; +use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; + +// Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`, +// then the crate for the proc-macro hasn't been build yet as the build data is missing. +pub type ProcMacroPaths = FxHashMap, AbsPathBuf), String>>; +pub type ProcMacros = FxHashMap; /// Files are grouped into source roots. A source root is a directory on the /// file systems which is watched for changes. Typically it corresponds to a @@ -79,17 +85,22 @@ impl SourceRoot { /// /// `CrateGraph` is `!Serialize` by design, see /// -#[derive(Debug, Clone, Default /* Serialize, Deserialize */)] +#[derive(Clone, Default)] pub struct CrateGraph { - arena: NoHashHashMap, + arena: Arena, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CrateId(pub u32); +impl fmt::Debug for CrateGraph { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map() + .entries(self.arena.iter().map(|(id, data)| (u32::from(id.into_raw()), data))) + .finish() + } +} -impl stdx::hash::NoHashHashable for CrateId {} +pub type CrateId = Idx; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct CrateName(SmolStr); impl CrateName { @@ -130,12 +141,22 @@ impl ops::Deref for CrateName { /// Origin of the crates. It is used in emitting monikers. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CrateOrigin { - /// Crates that are from crates.io official registry, - CratesIo { repo: Option, name: Option }, + /// Crates that are from the rustc workspace + Rustc { name: String }, + /// Crates that are workspace members, + Local { repo: Option, name: Option }, + /// Crates that are non member libraries. + Library { repo: Option, name: String }, /// Crates that are provided by the language, like std, core, proc-macro, ... Lang(LangCrateOrigin), } +impl CrateOrigin { + pub fn is_local(&self) -> bool { + matches!(self, CrateOrigin::Local { .. }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LangCrateOrigin { Alloc, @@ -173,7 +194,7 @@ impl fmt::Display for LangCrateOrigin { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct CrateDisplayName { // The name we use to display various paths (with `_`). crate_name: CrateName, @@ -249,10 +270,36 @@ pub type TargetLayoutLoadResult = Result, Arc>; pub struct ProcMacro { pub name: SmolStr, pub kind: ProcMacroKind, - pub expander: Arc, + pub expander: sync::Arc, } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ReleaseChannel { + Stable, + Beta, + Nightly, +} + +impl ReleaseChannel { + pub fn as_str(self) -> &'static str { + match self { + ReleaseChannel::Stable => "stable", + ReleaseChannel::Beta => "beta", + ReleaseChannel::Nightly => "nightly", + } + } + + pub fn from_str(str: &str) -> Option { + Some(match str { + "" => ReleaseChannel::Stable, + "nightly" => ReleaseChannel::Nightly, + _ if str.starts_with("beta") => ReleaseChannel::Beta, + _ => return None, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CrateData { pub root_file_id: FileId, pub edition: Edition, @@ -265,13 +312,15 @@ pub struct CrateData { /// `Dependency` matters), this name should only be used for UI. pub display_name: Option, pub cfg_options: CfgOptions, - pub potential_cfg_options: CfgOptions, - pub target_layout: TargetLayoutLoadResult, + /// The cfg options that could be used by the crate + pub potential_cfg_options: Option, pub env: Env, pub dependencies: Vec, - pub proc_macro: ProcMacroLoadResult, pub origin: CrateOrigin, pub is_proc_macro: bool, + // FIXME: These things should not be per crate! These are more per workspace crate graph level things + pub target_layout: TargetLayoutLoadResult, + pub channel: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -290,7 +339,18 @@ pub struct Env { entries: FxHashMap, } -#[derive(Debug, Clone, PartialEq, Eq)] +impl Env { + pub fn new_for_test_fixture() -> Self { + Env { + entries: FxHashMap::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, @@ -320,12 +380,12 @@ impl CrateGraph { display_name: Option, version: Option, cfg_options: CfgOptions, - potential_cfg_options: CfgOptions, + potential_cfg_options: Option, env: Env, - proc_macro: ProcMacroLoadResult, is_proc_macro: bool, origin: CrateOrigin, target_layout: Result, Arc>, + channel: Option, ) -> CrateId { let data = CrateData { root_file_id, @@ -335,16 +395,44 @@ impl CrateGraph { cfg_options, potential_cfg_options, env, - proc_macro, dependencies: Vec::new(), origin, target_layout, is_proc_macro, + channel, }; - let crate_id = CrateId(self.arena.len() as u32); - let prev = self.arena.insert(crate_id, data); - assert!(prev.is_none()); - crate_id + self.arena.alloc(data) + } + + /// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced + /// with the second input. + pub fn remove_and_replace( + &mut self, + id: CrateId, + replace_with: CrateId, + ) -> Result<(), CyclicDependenciesError> { + for (x, data) in self.arena.iter() { + if x == id { + continue; + } + for edge in &data.dependencies { + if edge.crate_id == id { + self.check_cycle_after_dependency(edge.crate_id, replace_with)?; + } + } + } + // if everything was ok, start to replace + for (x, data) in self.arena.iter_mut() { + if x == id { + continue; + } + for edge in &mut data.dependencies { + if edge.crate_id == id { + edge.crate_id = replace_with; + } + } + } + Ok(()) } pub fn add_dep( @@ -354,17 +442,26 @@ impl CrateGraph { ) -> Result<(), CyclicDependenciesError> { let _p = profile::span("add_dep"); - // Check if adding a dep from `from` to `to` creates a cycle. To figure - // that out, look for a path in the *opposite* direction, from `to` to - // `from`. - if let Some(path) = self.find_path(&mut NoHashHashSet::default(), dep.crate_id, from) { + self.check_cycle_after_dependency(from, dep.crate_id)?; + + self.arena[from].add_dep(dep); + Ok(()) + } + + /// Check if adding a dep from `from` to `to` creates a cycle. To figure + /// that out, look for a path in the *opposite* direction, from `to` to + /// `from`. + fn check_cycle_after_dependency( + &self, + from: CrateId, + to: CrateId, + ) -> Result<(), CyclicDependenciesError> { + if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) { let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); let err = CyclicDependenciesError { path }; - assert!(err.from().0 == from && err.to().0 == dep.crate_id); + assert!(err.from().0 == from && err.to().0 == to); return Err(err); } - - self.arena.get_mut(&from).unwrap().add_dep(dep); Ok(()) } @@ -373,14 +470,20 @@ impl CrateGraph { } pub fn iter(&self) -> impl Iterator + '_ { - self.arena.keys().copied() + self.arena.iter().map(|(idx, _)| idx) + } + + // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + #[doc(hidden)] + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + self.arena.iter_mut() } /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut deps = NoHashHashSet::default(); + let mut deps = FxHashSet::default(); while let Some(krate) = worklist.pop() { if !deps.insert(krate) { @@ -397,11 +500,11 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut rev_deps = NoHashHashSet::default(); + let mut rev_deps = FxHashSet::default(); rev_deps.insert(of); - let mut inverted_graph = NoHashHashMap::<_, Vec<_>>::default(); - self.arena.iter().for_each(|(&krate, data)| { + let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + self.arena.iter().for_each(|(krate, data)| { data.dependencies .iter() .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) @@ -424,9 +527,9 @@ impl CrateGraph { /// come before the crate itself). pub fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); - let mut visited = NoHashHashSet::default(); + let mut visited = FxHashSet::default(); - for krate in self.arena.keys().copied() { + for krate in self.iter() { go(self, &mut visited, &mut res, krate); } @@ -434,7 +537,7 @@ impl CrateGraph { fn go( graph: &CrateGraph, - visited: &mut NoHashHashSet, + visited: &mut FxHashSet, res: &mut Vec, source: CrateId, ) { @@ -450,31 +553,56 @@ impl CrateGraph { // FIXME: this only finds one crate with the given root; we could have multiple pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { - let (&crate_id, _) = + let (crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?; Some(crate_id) } + pub fn sort_deps(&mut self) { + self.arena + .iter_mut() + .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id)); + } + /// Extends this crate graph by adding a complete disjoint second crate - /// graph. + /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly. /// - /// The ids of the crates in the `other` graph are shifted by the return - /// amount. - pub fn extend(&mut self, other: CrateGraph) -> u32 { - let start = self.arena.len() as u32; - self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { - let new_id = id.shift(start); - for dep in &mut data.dependencies { - dep.crate_id = dep.crate_id.shift(start); + /// This will deduplicate the crates of the graph where possible. + /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. + /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. + pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { + let topo = other.crates_in_topological_order(); + let mut id_map: FxHashMap = FxHashMap::default(); + + for topo in topo { + let crate_data = &mut other.arena[topo]; + crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); + crate_data.dependencies.sort_by_key(|dep| dep.crate_id); + + let res = self.arena.iter().find_map( + |(id, data)| { + if data == crate_data { + Some(id) + } else { + None + } + }, + ); + if let Some(res) = res { + id_map.insert(topo, res); + } else { + let id = self.arena.alloc(crate_data.clone()); + id_map.insert(topo, id); } - (new_id, data) - })); - start + } + + *proc_macros = + mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect(); } fn find_path( &self, - visited: &mut NoHashHashSet, + visited: &mut FxHashSet, from: CrateId, to: CrateId, ) -> Option> { @@ -500,14 +628,14 @@ impl CrateGraph { // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038. // As hacky as it gets. pub fn patch_cfg_if(&mut self) -> bool { - let cfg_if = self.hacky_find_crate("cfg_if"); - let std = self.hacky_find_crate("std"); + // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works + let cfg_if = + self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone()); + let std = self.hacky_find_crate("std").next(); match (cfg_if, std) { (Some(cfg_if), Some(std)) => { - self.arena.get_mut(&cfg_if).unwrap().dependencies.clear(); - self.arena - .get_mut(&std) - .unwrap() + self.arena[cfg_if].dependencies.clear(); + self.arena[std] .dependencies .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); true @@ -516,21 +644,15 @@ impl CrateGraph { } } - fn hacky_find_crate(&self, display_name: &str) -> Option { - self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name)) + fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a { + self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name)) } } impl ops::Index for CrateGraph { type Output = CrateData; fn index(&self, crate_id: CrateId) -> &CrateData { - &self.arena[&crate_id] - } -} - -impl CrateId { - fn shift(self, amount: u32) -> CrateId { - CrateId(self.0 + amount) + &self.arena[crate_id] } } @@ -632,7 +754,7 @@ impl fmt::Display for CyclicDependenciesError { mod tests { use crate::CrateOrigin; - use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; + use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; #[test] fn detect_cyclic_dependency_indirect() { @@ -642,39 +764,39 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -695,26 +817,26 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -732,39 +854,39 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -782,26 +904,26 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep( 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 9720db9d8..af204e44e 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -6,18 +6,19 @@ mod input; mod change; pub mod fixture; -use std::{panic, sync::Arc}; +use std::panic; -use stdx::hash::NoHashHashSet; +use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; +use triomphe::Arc; pub use crate::{ change::Change, input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, - TargetLayoutLoadResult, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, + ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult, }, }; pub use salsa::{self, Cancelled}; @@ -53,13 +54,13 @@ pub struct FileRange { pub range: TextRange, } -pub const DEFAULT_LRU_CAP: usize = 128; +pub const DEFAULT_PARSE_LRU_CAP: usize = 128; pub trait FileLoader { /// Text of the file. - fn file_text(&self, file_id: FileId) -> Arc; + fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc>; } /// Database which stores all significant input facts: source code and project @@ -73,6 +74,10 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { /// The crate graph. #[salsa::input] fn crate_graph(&self) -> Arc; + + /// The crate graph. + #[salsa::input] + fn proc_macros(&self) -> Arc; } fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { @@ -86,7 +91,7 @@ fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse Arc; + fn file_text(&self, file_id: FileId) -> Arc; /// Path to a file, relative to the root of its source root. /// Source root of the file. #[salsa::input] @@ -95,10 +100,10 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; } -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { let graph = db.crate_graph(); let res = graph .iter() @@ -114,7 +119,7 @@ fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc(pub T); impl FileLoader for FileLoaderDelegate<&'_ T> { - fn file_text(&self, file_id: FileId) -> Arc { + fn file_text(&self, file_id: FileId) -> Arc { SourceDatabaseExt::file_text(self.0, file_id) } fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { @@ -124,7 +129,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { source_root.resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { let _p = profile::span("relevant_crates"); 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/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 30709c968..495119d55 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -86,7 +86,7 @@ impl CfgOptions { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct CfgDiff { // Invariants: No duplicates, no atom that's both in `enable` and `disable`. enable: Vec, diff --git a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml index 609d18c4e..3f6671b1c 100644 --- a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml +++ b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml @@ -16,9 +16,8 @@ crossbeam-channel = "0.5.5" tracing = "0.1.37" cargo_metadata = "0.15.0" rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.86" -jod-thread = "0.1.2" +serde_json.workspace = true +serde.workspace = true command-group = "2.0.1" # local deps diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index accb14a51..fbb943ccb 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -77,7 +77,7 @@ impl fmt::Display for FlycheckConfig { pub struct FlycheckHandle { // XXX: drop order is significant sender: Sender, - _thread: jod_thread::JoinHandle, + _thread: stdx::thread::JoinHandle, id: usize, } @@ -90,7 +90,7 @@ impl FlycheckHandle { ) -> FlycheckHandle { let actor = FlycheckActor::new(id, sender, config, workspace_root); let (sender, receiver) = unbounded::(); - let thread = jod_thread::Builder::new() + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("Flycheck".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); @@ -395,7 +395,7 @@ struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with /// a read syscall dropping and therefore terminating the process is our best option. child: JodGroupChild, - thread: jod_thread::JoinHandle>, + thread: stdx::thread::JoinHandle>, receiver: Receiver, } @@ -409,7 +409,7 @@ impl CargoHandle { let (sender, receiver) = unbounded(); let actor = CargoActor::new(sender, stdout, stderr); - let thread = jod_thread::Builder::new() + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("CargoHandle".to_owned()) .spawn(move || actor.run()) .expect("failed to spawn thread"); @@ -485,7 +485,7 @@ impl CargoActor { error.push_str(line); error.push('\n'); - return false; + false }; let output = streaming_output( self.stdout, diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index 31d4018d2..83c705164 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] anymap = "1.0.0-beta.2" arrayvec = "0.7.2" -bitflags = "1.3.2" +bitflags = "2.1.0" cov-mark = "2.0.0-pre.1" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.4.0", features = ["raw-api"] } @@ -29,6 +29,7 @@ once_cell = "1.17.0" rustc-hash = "1.1.0" smallvec.workspace = true tracing = "0.1.35" +triomphe.workspace = true rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false } rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs deleted file mode 100644 index b336f59ff..000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs +++ /dev/null @@ -1,554 +0,0 @@ -//! Defines hir-level representation of structs, enums and unions - -use std::sync::Arc; - -use base_db::CrateId; -use cfg::CfgOptions; -use either::Either; - -use hir_expand::{ - name::{AsName, Name}, - HirFileId, InFile, -}; -use intern::Interned; -use la_arena::{Arena, ArenaMap}; -use rustc_abi::{Integer, IntegerType}; -use syntax::ast::{self, HasName, HasVisibility}; - -use crate::{ - body::{CfgExpander, LowerCtx}, - builtin_type::{BuiltinInt, BuiltinUint}, - db::DefDatabase, - item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, - layout::{Align, ReprFlags, ReprOptions}, - nameres::diagnostics::DefDiagnostic, - src::HasChildSource, - src::HasSource, - trace::Trace, - tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, - type_ref::TypeRef, - visibility::RawVisibility, - EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId, - VariantId, -}; - -/// Note that we use `StructData` for unions as well! -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructData { - pub name: Name, - pub variant_data: Arc, - pub repr: Option, - pub visibility: RawVisibility, - pub rustc_has_incoherent_inherent_impls: bool, - pub fundamental: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumData { - pub name: Name, - pub variants: Arena, - pub repr: Option, - pub visibility: RawVisibility, - pub rustc_has_incoherent_inherent_impls: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumVariantData { - pub name: Name, - pub variant_data: Arc, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VariantData { - Record(Arena), - Tuple(Arena), - Unit, -} - -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldData { - pub name: Name, - pub type_ref: Interned, - pub visibility: RawVisibility, -} - -fn repr_from_value( - db: &dyn DefDatabase, - krate: CrateId, - item_tree: &ItemTree, - of: AttrOwner, -) -> Option { - item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt) -} - -fn parse_repr_tt(tt: &Subtree) -> Option { - match tt.delimiter { - Delimiter { kind: DelimiterKind::Parenthesis, .. } => {} - _ => return None, - } - - let mut flags = ReprFlags::empty(); - let mut int = None; - let mut max_align: Option = None; - let mut min_pack: Option = None; - - let mut tts = tt.token_trees.iter().peekable(); - while let Some(tt) = tts.next() { - if let TokenTree::Leaf(Leaf::Ident(ident)) = tt { - flags.insert(match &*ident.text { - "packed" => { - let pack = if let Some(TokenTree::Subtree(tt)) = tts.peek() { - tts.next(); - if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() { - lit.text.parse().unwrap_or_default() - } else { - 0 - } - } else { - 0 - }; - let pack = Align::from_bytes(pack).unwrap(); - min_pack = - Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack }); - ReprFlags::empty() - } - "align" => { - if let Some(TokenTree::Subtree(tt)) = tts.peek() { - tts.next(); - if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() { - if let Ok(align) = lit.text.parse() { - let align = Align::from_bytes(align).ok(); - max_align = max_align.max(align); - } - } - } - ReprFlags::empty() - } - "C" => ReprFlags::IS_C, - "transparent" => ReprFlags::IS_TRANSPARENT, - repr => { - if let Some(builtin) = BuiltinInt::from_suffix(repr) - .map(Either::Left) - .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right)) - { - int = Some(match builtin { - Either::Left(bi) => match bi { - BuiltinInt::Isize => IntegerType::Pointer(true), - BuiltinInt::I8 => IntegerType::Fixed(Integer::I8, true), - BuiltinInt::I16 => IntegerType::Fixed(Integer::I16, true), - BuiltinInt::I32 => IntegerType::Fixed(Integer::I32, true), - BuiltinInt::I64 => IntegerType::Fixed(Integer::I64, true), - BuiltinInt::I128 => IntegerType::Fixed(Integer::I128, true), - }, - Either::Right(bu) => match bu { - BuiltinUint::Usize => IntegerType::Pointer(false), - BuiltinUint::U8 => IntegerType::Fixed(Integer::I8, false), - BuiltinUint::U16 => IntegerType::Fixed(Integer::I16, false), - BuiltinUint::U32 => IntegerType::Fixed(Integer::I32, false), - BuiltinUint::U64 => IntegerType::Fixed(Integer::I64, false), - BuiltinUint::U128 => IntegerType::Fixed(Integer::I128, false), - }, - }); - } - ReprFlags::empty() - } - }) - } - } - - Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: 0 }) -} - -impl StructData { - pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc { - db.struct_data_with_diagnostics(id).0 - } - - pub(crate) fn struct_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: StructId, - ) -> (Arc, Arc<[DefDiagnostic]>) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let fundamental = attrs.by_key("fundamental").exists(); - - let strukt = &item_tree[loc.id.value]; - let (variant_data, diagnostics) = lower_fields( - db, - krate, - loc.id.file_id(), - loc.container.local_id, - &item_tree, - &cfg_options, - &strukt.fields, - None, - ); - ( - Arc::new(StructData { - name: strukt.name.clone(), - variant_data: Arc::new(variant_data), - repr, - visibility: item_tree[strukt.visibility].clone(), - rustc_has_incoherent_inherent_impls, - fundamental, - }), - diagnostics.into(), - ) - } - - pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc { - db.union_data_with_diagnostics(id).0 - } - - pub(crate) fn union_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: UnionId, - ) -> (Arc, Arc<[DefDiagnostic]>) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let fundamental = attrs.by_key("fundamental").exists(); - - let union = &item_tree[loc.id.value]; - let (variant_data, diagnostics) = lower_fields( - db, - krate, - loc.id.file_id(), - loc.container.local_id, - &item_tree, - &cfg_options, - &union.fields, - None, - ); - ( - Arc::new(StructData { - name: union.name.clone(), - variant_data: Arc::new(variant_data), - repr, - visibility: item_tree[union.visibility].clone(), - rustc_has_incoherent_inherent_impls, - fundamental, - }), - diagnostics.into(), - ) - } -} - -impl EnumData { - pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc { - db.enum_data_with_diagnostics(e).0 - } - - pub(crate) fn enum_data_with_diagnostics_query( - db: &dyn DefDatabase, - e: EnumId, - ) -> (Arc, Arc<[DefDiagnostic]>) { - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); - - let enum_ = &item_tree[loc.id.value]; - let mut variants = Arena::new(); - let mut diagnostics = Vec::new(); - for tree_id in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, tree_id.into()); - let var = &item_tree[tree_id]; - if attrs.is_cfg_enabled(&cfg_options) { - let (var_data, field_diagnostics) = lower_fields( - db, - krate, - loc.id.file_id(), - loc.container.local_id, - &item_tree, - &cfg_options, - &var.fields, - Some(enum_.visibility), - ); - diagnostics.extend(field_diagnostics); - - variants.alloc(EnumVariantData { - name: var.name.clone(), - variant_data: Arc::new(var_data), - }); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - loc.container.local_id, - InFile::new(loc.id.file_id(), var.ast_id.upcast()), - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - - ( - Arc::new(EnumData { - name: enum_.name.clone(), - variants, - repr, - visibility: item_tree[enum_.visibility].clone(), - rustc_has_incoherent_inherent_impls, - }), - diagnostics.into(), - ) - } - - pub fn variant(&self, name: &Name) -> Option { - let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?; - Some(id) - } - - pub fn variant_body_type(&self) -> IntegerType { - match self.repr { - Some(ReprOptions { int: Some(builtin), .. }) => builtin, - _ => IntegerType::Pointer(true), - } - } -} - -impl HasChildSource for EnumId { - type Value = ast::Variant; - fn child_source( - &self, - db: &dyn DefDatabase, - ) -> InFile> { - let src = self.lookup(db).source(db); - let mut trace = Trace::new_for_map(); - lower_enum(db, &mut trace, &src, self.lookup(db).container); - src.with_value(trace.into_map()) - } -} - -fn lower_enum( - db: &dyn DefDatabase, - trace: &mut Trace, - ast: &InFile, - module_id: ModuleId, -) { - let expander = CfgExpander::new(db, ast.file_id, module_id.krate); - let variants = ast - .value - .variant_list() - .into_iter() - .flat_map(|it| it.variants()) - .filter(|var| expander.is_cfg_enabled(db, var)); - for var in variants { - trace.alloc( - || var.clone(), - || EnumVariantData { - name: var.name().map_or_else(Name::missing, |it| it.as_name()), - variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)), - }, - ); - } -} - -impl VariantData { - fn new(db: &dyn DefDatabase, flavor: InFile, module_id: ModuleId) -> Self { - let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); - let mut trace = Trace::new_for_arena(); - match lower_struct(db, &mut expander, &mut trace, &flavor) { - StructKind::Tuple => VariantData::Tuple(trace.into_arena()), - StructKind::Record => VariantData::Record(trace.into_arena()), - StructKind::Unit => VariantData::Unit, - } - } - - pub fn fields(&self) -> &Arena { - const EMPTY: &Arena = &Arena::new(); - match &self { - VariantData::Record(fields) | VariantData::Tuple(fields) => fields, - _ => EMPTY, - } - } - - pub fn field(&self, name: &Name) -> Option { - self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) - } - - pub fn kind(&self) -> StructKind { - match self { - VariantData::Record(_) => StructKind::Record, - VariantData::Tuple(_) => StructKind::Tuple, - VariantData::Unit => StructKind::Unit, - } - } -} - -impl HasChildSource for VariantId { - type Value = Either; - - fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - let (src, module_id) = match self { - VariantId::EnumVariantId(it) => { - // I don't really like the fact that we call into parent source - // here, this might add to more queries then necessary. - let src = it.parent.child_source(db); - (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container) - } - VariantId::StructId(it) => { - (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container) - } - VariantId::UnionId(it) => ( - it.lookup(db).source(db).map(|it| { - it.record_field_list() - .map(ast::StructKind::Record) - .unwrap_or(ast::StructKind::Unit) - }), - it.lookup(db).container, - ), - }; - let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); - let mut trace = Trace::new_for_map(); - lower_struct(db, &mut expander, &mut trace, &src); - src.with_value(trace.into_map()) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum StructKind { - Tuple, - Record, - Unit, -} - -fn lower_struct( - db: &dyn DefDatabase, - expander: &mut CfgExpander, - trace: &mut Trace>, - ast: &InFile, -) -> StructKind { - let ctx = LowerCtx::new(db, ast.file_id); - - match &ast.value { - ast::StructKind::Tuple(fl) => { - for (i, fd) in fl.fields().enumerate() { - if !expander.is_cfg_enabled(db, &fd) { - continue; - } - - trace.alloc( - || Either::Left(fd.clone()), - || FieldData { - name: Name::new_tuple_field(i), - type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), - }, - ); - } - StructKind::Tuple - } - ast::StructKind::Record(fl) => { - for fd in fl.fields() { - if !expander.is_cfg_enabled(db, &fd) { - continue; - } - - trace.alloc( - || Either::Right(fd.clone()), - || FieldData { - name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), - type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), - visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), - }, - ); - } - StructKind::Record - } - ast::StructKind::Unit => StructKind::Unit, - } -} - -fn lower_fields( - db: &dyn DefDatabase, - krate: CrateId, - current_file_id: HirFileId, - container: LocalModuleId, - item_tree: &ItemTree, - cfg_options: &CfgOptions, - fields: &Fields, - override_visibility: Option, -) -> (VariantData, Vec) { - let mut diagnostics = Vec::new(); - match fields { - Fields::Record(flds) => { - let mut arena = Arena::new(); - for field_id in flds.clone() { - let attrs = item_tree.attrs(db, krate, field_id.into()); - let field = &item_tree[field_id]; - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, field, override_visibility)); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - container, - InFile::new( - current_file_id, - match field.ast_id { - FieldAstId::Record(it) => it.upcast(), - FieldAstId::Tuple(it) => it.upcast(), - }, - ), - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - (VariantData::Record(arena), diagnostics) - } - Fields::Tuple(flds) => { - let mut arena = Arena::new(); - for field_id in flds.clone() { - let attrs = item_tree.attrs(db, krate, field_id.into()); - let field = &item_tree[field_id]; - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, field, override_visibility)); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - container, - InFile::new( - current_file_id, - match field.ast_id { - FieldAstId::Record(it) => it.upcast(), - FieldAstId::Tuple(it) => it.upcast(), - }, - ), - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - (VariantData::Tuple(arena), diagnostics) - } - Fields::Unit => (VariantData::Unit, diagnostics), - } -} - -fn lower_field( - item_tree: &ItemTree, - field: &Field, - override_visibility: Option, -) -> FieldData { - FieldData { - name: field.name.clone(), - type_ref: field.type_ref.clone(), - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - } -} 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 200072c17..bab3bbc23 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,6 +1,11 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{hash::Hash, ops, sync::Arc}; +pub mod builtin; + +#[cfg(test)] +mod tests; + +use std::{hash::Hash, ops}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; @@ -16,14 +21,16 @@ use syntax::{ ast::{self, HasAttrs, IsString}, AstPtr, AstToken, SmolStr, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, + lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId, - VariantId, + AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId, + LocalFieldId, Lookup, MacroId, VariantId, }; /// Holds documentation @@ -88,6 +95,7 @@ impl Attrs { db: &dyn DefDatabase, e: EnumId, ) -> Arc> { + let _p = profile::span("variants_attrs_query"); // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids let mut res = ArenaMap::default(); @@ -114,6 +122,7 @@ impl Attrs { db: &dyn DefDatabase, v: VariantId, ) -> Arc> { + let _p = profile::span("fields_attrs_query"); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); @@ -175,13 +184,13 @@ impl Attrs { Arc::new(res) } +} +impl Attrs { pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { AttrQuery { attrs: self, key } } -} -impl Attrs { pub fn cfg(&self) -> Option { let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse); let first = cfgs.next()?; @@ -193,6 +202,7 @@ impl Attrs { None => Some(first), } } + pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { match self.cfg() { None => true, @@ -204,6 +214,10 @@ impl Attrs { self.by_key("lang").string_value() } + pub fn lang_item(&self) -> Option { + self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it)) + } + pub fn docs(&self) -> Option { let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value()); let indent = doc_indent(self); @@ -238,6 +252,14 @@ impl Attrs { }) } + pub fn doc_exprs(&self) -> impl Iterator + '_ { + self.by_key("doc").tt_values().map(DocExpr::parse) + } + + pub fn doc_aliases(&self) -> impl Iterator + '_ { + self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec()) + } + pub fn is_proc_macro(&self) -> bool { self.by_key("proc_macro").exists() } @@ -249,10 +271,120 @@ impl Attrs { pub fn is_proc_macro_derive(&self) -> bool { self.by_key("proc_macro_derive").exists() } + + pub fn is_unstable(&self) -> bool { + self.by_key("unstable").exists() + } +} + +use std::slice::Iter as SliceIter; +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum DocAtom { + /// eg. `#[doc(hidden)]` + Flag(SmolStr), + /// eg. `#[doc(alias = "x")]` + /// + /// Note that a key can have multiple values that are all considered "active" at the same time. + /// For example, `#[doc(alias = "x")]` and `#[doc(alias = "y")]`. + KeyValue { key: SmolStr, value: SmolStr }, +} + +// Adapted from `CfgExpr` parsing code +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +// #[cfg_attr(test, derive(derive_arbitrary::Arbitrary))] +pub enum DocExpr { + Invalid, + /// eg. `#[doc(hidden)]`, `#[doc(alias = "x")]` + Atom(DocAtom), + /// eg. `#[doc(alias("x", "y"))]` + Alias(Vec), +} + +impl From for DocExpr { + fn from(atom: DocAtom) -> Self { + DocExpr::Atom(atom) + } +} + +impl DocExpr { + fn parse(tt: &tt::Subtree) -> DocExpr { + next_doc_expr(&mut tt.token_trees.iter()).unwrap_or(DocExpr::Invalid) + } + + pub fn aliases(&self) -> &[SmolStr] { + match self { + DocExpr::Atom(DocAtom::KeyValue { key, value }) if key == "alias" => { + std::slice::from_ref(value) + } + DocExpr::Alias(aliases) => aliases, + _ => &[], + } + } +} + +fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { + let name = match it.next() { + None => return None, + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), + Some(_) => return Some(DocExpr::Invalid), + }; + + // Peek + let ret = match it.as_slice().first() { + Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => { + match it.as_slice().get(1) { + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { + it.next(); + it.next(); + // FIXME: escape? raw string? + let value = + SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); + DocAtom::KeyValue { key: name, value }.into() + } + _ => return Some(DocExpr::Invalid), + } + } + Some(tt::TokenTree::Subtree(subtree)) => { + it.next(); + let subs = parse_comma_sep(subtree); + match name.as_str() { + "alias" => DocExpr::Alias(subs), + _ => DocExpr::Invalid, + } + } + _ => DocAtom::Flag(name).into(), + }; + + // Eat comma separator + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = it.as_slice().first() { + if punct.char == ',' { + it.next(); + } + } + Some(ret) +} + +fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { + subtree + .token_trees + .iter() + .filter_map(|tt| match tt { + tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { + // FIXME: escape? raw string? + Some(SmolStr::new(lit.text.trim_start_matches('"').trim_end_matches('"'))) + } + _ => None, + }) + .collect() } impl AttrsWithOwner { - pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self { + pub(crate) fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self { + Self { attrs: db.attrs(owner), owner } + } + + pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { + let _p = profile::span("attrs_query"); // FIXME: this should use `Trace` to avoid duplication in `source_map` below let raw_attrs = match def { AttrDefId::ModuleId(module) => { @@ -286,31 +418,29 @@ impl AttrsWithOwner { } } AttrDefId::FieldId(it) => { - return Self { attrs: db.fields_attrs(it.parent)[it.local_id].clone(), owner: def }; + return db.fields_attrs(it.parent)[it.local_id].clone(); } AttrDefId::EnumVariantId(it) => { - return Self { - attrs: db.variants_attrs(it.parent)[it.local_id].clone(), - owner: def, - }; + return db.variants_attrs(it.parent)[it.local_id].clone(); } + // FIXME: DRY this up AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), + AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), + AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it), }, - AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::TraitAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it), AttrDefId::MacroId(it) => match it { - MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::ProcMacroId(it) => attrs_from_item_tree(it.lookup(db).id, db), + MacroId::Macro2Id(it) => attrs_from_item_tree(db, it.lookup(db).id), + MacroId::MacroRulesId(it) => attrs_from_item_tree(db, it.lookup(db).id), + MacroId::ProcMacroId(it) => attrs_from_item_tree(db, it.lookup(db).id), }, - AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::ConstId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::StaticId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::FunctionId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::TypeAliasId(it) => attrs_from_item_tree_assoc(db, it), AttrDefId::GenericParamId(it) => match it { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); @@ -331,11 +461,11 @@ impl AttrsWithOwner { RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id])) } }, - AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), }; let attrs = raw_attrs.filter(db.upcast(), def.krate(db)); - Self { attrs: Attrs(attrs), owner: def } + Attrs(attrs) } pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { @@ -371,7 +501,7 @@ impl AttrsWithOwner { AttrDefId::FieldId(id) => { let map = db.fields_attrs_source_map(id.parent); let file_id = id.parent.file_id(db); - let root = db.parse_or_expand(file_id).unwrap(); + let root = db.parse_or_expand(file_id); let owner = match &map[id.local_id] { Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)), Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)), @@ -379,28 +509,28 @@ impl AttrsWithOwner { InFile::new(file_id, owner) } AttrDefId::AdtId(adt) => match adt { - AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AdtId::StructId(id) => any_has_attrs(db, id), + AdtId::UnionId(id) => any_has_attrs(db, id), + AdtId::EnumId(id) => any_has_attrs(db, id), }, - AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::FunctionId(id) => any_has_attrs(db, id), AttrDefId::EnumVariantId(id) => { let map = db.variants_attrs_source_map(id.parent); let file_id = id.parent.lookup(db).id.file_id(); - let root = db.parse_or_expand(file_id).unwrap(); + let root = db.parse_or_expand(file_id); InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root))) } - AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TraitAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::StaticId(id) => any_has_attrs(db, id), + AttrDefId::ConstId(id) => any_has_attrs(db, id), + AttrDefId::TraitId(id) => any_has_attrs(db, id), + AttrDefId::TraitAliasId(id) => any_has_attrs(db, id), + AttrDefId::TypeAliasId(id) => any_has_attrs(db, id), AttrDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::MacroRulesId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::ProcMacroId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + MacroId::Macro2Id(id) => any_has_attrs(db, id), + MacroId::MacroRulesId(id) => any_has_attrs(db, id), + MacroId::ProcMacroId(id) => any_has_attrs(db, id), }, - AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::ImplId(id) => any_has_attrs(db, id), AttrDefId::GenericParamId(id) => match id { GenericParamId::ConstParamId(id) => id .parent() @@ -415,7 +545,7 @@ impl AttrsWithOwner { .child_source(db) .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())), }, - AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::ExternBlockId(id) => any_has_attrs(db, id), }; AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs)) @@ -635,19 +765,42 @@ impl<'attr> AttrQuery<'attr> { .nth(2); match name { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ref text, ..}))) => Some(text), + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ ref text, ..}))) => Some(text), _ => None } }) } } -fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase) -> RawAttrs { +fn any_has_attrs( + db: &dyn DefDatabase, + id: impl Lookup>, +) -> InFile { + id.lookup(db).source(db).map(ast::AnyHasAttrs::new) +} + +fn attrs_from_item_tree(db: &dyn DefDatabase, id: ItemTreeId) -> RawAttrs { let tree = id.item_tree(db); let mod_item = N::id_to_mod_item(id.value); tree.raw_attrs(mod_item.into()).clone() } +fn attrs_from_item_tree_loc( + db: &dyn DefDatabase, + lookup: impl Lookup>, +) -> RawAttrs { + let id = lookup.lookup(db).id; + attrs_from_item_tree(db, id) +} + +fn attrs_from_item_tree_assoc( + db: &dyn DefDatabase, + lookup: impl Lookup>, +) -> RawAttrs { + let id = lookup.lookup(db).id; + attrs_from_item_tree(db, id) +} + pub(crate) fn variants_attrs_source_map( db: &dyn DefDatabase, def: EnumId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs new file mode 100644 index 000000000..cead64a33 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs @@ -0,0 +1,693 @@ +//! Builtin attributes resolved by nameres. +//! +//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. +//! +//! It was last synchronized with upstream commit e29821ff85a2a3000d226f99f62f89464028d5d6. +//! +//! The macros were adjusted to only expand to the attribute name, since that is all we need to do +//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to +//! ease updating. + +use once_cell::sync::OnceCell; +use rustc_hash::FxHashMap; + +/// Ignored attribute namespaces used by tools. +pub const TOOL_MODULES: &[&str] = &["rustfmt", "clippy"]; + +pub struct BuiltinAttribute { + pub name: &'static str, + pub template: AttributeTemplate, +} + +/// A template that the attribute input must match. +/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. +#[derive(Clone, Copy)] +pub struct AttributeTemplate { + pub word: bool, + pub list: Option<&'static str>, + pub name_value_str: Option<&'static str>, +} + +pub fn find_builtin_attr_idx(name: &str) -> Option { + static BUILTIN_LOOKUP_TABLE: OnceCell> = OnceCell::new(); + BUILTIN_LOOKUP_TABLE + .get_or_init(|| { + INERT_ATTRIBUTES.iter().map(|attr| attr.name).enumerate().map(|(a, b)| (b, a)).collect() + }) + .get(name) + .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)]`. +macro_rules! template { + (Word) => { template!(@ true, None, None) }; + (List: $descr: expr) => { template!(@ false, Some($descr), None) }; + (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; + (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; + (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; + (List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ false, Some($descr1), Some($descr2)) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ true, Some($descr1), Some($descr2)) + }; + (@ $word: expr, $list: expr, $name_value_str: expr) => { + AttributeTemplate { + word: $word, list: $list, name_value_str: $name_value_str + } + }; +} + +macro_rules! ungated { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)? $(,)?) => { + BuiltinAttribute { name: stringify!($attr), template: $tpl } + }; +} + +macro_rules! gated { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $gate:ident, $msg:expr $(,)?) => { + BuiltinAttribute { name: stringify!($attr), template: $tpl } + }; + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { + BuiltinAttribute { name: stringify!($attr), template: $tpl } + }; +} + +macro_rules! rustc_attr { + (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(, @only_local: $only_local:expr)? $(,)?) => { + rustc_attr!( + $attr, + $typ, + $tpl, + $duplicate, + $(@only_local: $only_local,)? + concat!( + "the `#[", + stringify!($attr), + "]` attribute is just used for rustc unit tests \ + and will never be stable", + ), + ) + }; + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { + BuiltinAttribute { name: stringify!($attr), template: $tpl } + }; +} + +#[allow(unused_macros)] +macro_rules! experimental { + ($attr:ident) => { + concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature") + }; +} + +/// Attributes that have a special meaning to rustc or rustdoc. +#[rustfmt::skip] +pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ + // ========================================================================== + // Stable attributes: + // ========================================================================== + + // Conditional compilation: + ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk), + + // Testing: + ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing), + ungated!( + should_panic, Normal, + template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing, + ), + // FIXME(Centril): This can be used on stable but shouldn't. + ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing), + + // Macros: + ungated!(automatically_derived, Normal, template!(Word), WarnFollowing), + ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly), + ungated!(macro_escape, Normal, template!(Word), WarnFollowing), // Deprecated synonym for `macro_use`. + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing), + ungated!(proc_macro, Normal, template!(Word), ErrorFollowing), + ungated!( + proc_macro_derive, Normal, + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, + ), + ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing), + + // Lints: + ungated!( + warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, + ), + ungated!( + allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, + ), + gated!( + expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, + lint_reasons, experimental!(expect) + ), + ungated!( + forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, + ), + ungated!( + deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, + ), + ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), + gated!( + must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, + experimental!(must_not_suspend) + ), + ungated!( + deprecated, Normal, + template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ), + ErrorFollowing + ), + + // Crate properties: + ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing), + ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk), + // crate_id is deprecated + ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing), + + // ABI, linking, symbols, and FFI + ungated!( + link, Normal, + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#), + DuplicatesOk, + ), + ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), + ungated!(no_link, Normal, template!(Word), WarnFollowing), + ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), + ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), + ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), + ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), + ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), + ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding), + + // Limits: + ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), + ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), + gated!( + move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing, + large_assignments, experimental!(move_size_limit) + ), + + // Entry point: + gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)), + ungated!(start, Normal, template!(Word), WarnFollowing), + ungated!(no_start, CrateLevel, template!(Word), WarnFollowing), + ungated!(no_main, CrateLevel, template!(Word), WarnFollowing), + + // Modules, prelude, and resolution: + ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing), + ungated!(no_std, CrateLevel, template!(Word), WarnFollowing), + ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing), + ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing), + + // Runtime + ungated!( + windows_subsystem, CrateLevel, + template!(NameValueStr: "windows|console"), FutureWarnFollowing + ), + ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070 + + // Code generation: + ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), + ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), + ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), + ungated!( + target_feature, Normal, template!(List: r#"enable = "name""#), + DuplicatesOk, @only_local: true, + ), + ungated!(track_caller, Normal, template!(Word), WarnFollowing), + ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding), + gated!( + no_sanitize, Normal, + template!(List: "address, kcfi, memory, thread"), DuplicatesOk, + experimental!(no_sanitize) + ), + gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)), + + ungated!( + doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk + ), + + // Debugging + ungated!( + debugger_visualizer, Normal, + template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk + ), + + // ========================================================================== + // Unstable attributes: + // ========================================================================== + + // Linking: + gated!( + naked, Normal, template!(Word), WarnFollowing, @only_local: true, + naked_functions, experimental!(naked) + ), + + // Plugins: + // BuiltinAttribute { + // name: sym::plugin, + // only_local: false, + // type_: CrateLevel, + // template: template!(List: "name"), + // duplicates: DuplicatesOk, + // gate: Gated( + // Stability::Deprecated( + // "https://github.com/rust-lang/rust/pull/64675", + // Some("may be removed in a future compiler version"), + // ), + // sym::plugin, + // "compiler plugins are deprecated", + // cfg_fn!(plugin) + // ), + // }, + + // Testing: + gated!( + test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks, + "custom test frameworks are an unstable feature", + ), + // RFC #1268 + gated!( + marker, Normal, template!(Word), WarnFollowing, @only_local: true, + marker_trait_attr, experimental!(marker) + ), + gated!( + thread_local, Normal, template!(Word), WarnFollowing, + "`#[thread_local]` is an experimental feature, and does not currently handle destructors", + ), + gated!(no_core, CrateLevel, template!(Word), WarnFollowing, experimental!(no_core)), + // RFC 2412 + gated!( + optimize, Normal, template!(List: "size|speed"), ErrorPreceding, optimize_attribute, + experimental!(optimize), + ), + + gated!( + ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice) + ), + gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)), + gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)), + gated!( + register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk, + experimental!(register_tool), + ), + + gated!( + cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing, + experimental!(cmse_nonsecure_entry) + ), + // RFC 2632 + gated!( + const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl, + "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ + `impls` and all default bodies as `const`, which may be removed or renamed in the \ + future." + ), + // lang-team MCP 147 + gated!( + deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing, + experimental!(deprecated_safe), + ), + + // `#[collapse_debuginfo]` + gated!( + collapse_debuginfo, Normal, template!(Word), WarnFollowing, + experimental!(collapse_debuginfo) + ), + + // RFC 2397 + gated!(do_not_recommend, Normal, template!(Word), WarnFollowing, experimental!(do_not_recommend)), + + // `#[cfi_encoding = ""]` + gated!( + cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding, + experimental!(cfi_encoding) + ), + + // ========================================================================== + // Internal attributes: Stability, deprecation, and unsafe: + // ========================================================================== + + ungated!( + feature, CrateLevel, + template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true, + ), + // DuplicatesOk since it has its own validation + ungated!( + stable, Normal, + template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true, + ), + ungated!( + unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, + ), + ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), + ungated!( + rustc_const_stable, Normal, + template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true, + ), + ungated!( + rustc_default_body_unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk + ), + gated!( + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, + "allow_internal_unstable side-steps feature gating and stability checks", + ), + gated!( + rustc_allow_const_fn_unstable, Normal, + template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, + "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" + ), + gated!( + allow_internal_unsafe, Normal, template!(Word), WarnFollowing, + "allow_internal_unsafe side-steps the unsafe_code lint", + ), + ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), + rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing, + "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ + through unstable paths"), + + // ========================================================================== + // Internal attributes: Type system related: + // ========================================================================== + + gated!(fundamental, Normal, template!(Word), WarnFollowing, experimental!(fundamental)), + gated!( + may_dangle, Normal, template!(Word), WarnFollowing, dropck_eyepatch, + "`may_dangle` has unstable semantics and may be removed in the future", + ), + + // ========================================================================== + // Internal attributes: Runtime related: + // ========================================================================== + + rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + gated!( + default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, + experimental!(default_lib_allocator), + ), + gated!( + needs_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, + experimental!(needs_allocator), + ), + gated!(panic_runtime, Normal, template!(Word), WarnFollowing, experimental!(panic_runtime)), + gated!( + needs_panic_runtime, Normal, template!(Word), WarnFollowing, + experimental!(needs_panic_runtime) + ), + gated!( + compiler_builtins, Normal, template!(Word), WarnFollowing, + "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ + which contains compiler-rt intrinsics and will never be stable", + ), + gated!( + profiler_runtime, Normal, template!(Word), WarnFollowing, + "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ + which contains the profiler runtime and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Linkage: + // ========================================================================== + + gated!( + linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, @only_local: true, + "the `linkage` attribute is experimental and not portable across platforms", + ), + rustc_attr!( + rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, @only_local: true, INTERNAL_UNSTABLE + ), + + // ========================================================================== + // Internal attributes, Macro related: + // ========================================================================== + + rustc_attr!( + rustc_builtin_macro, Normal, + template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, + IMPL_DETAIL, + ), + rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + rustc_attr!( + rustc_macro_transparency, Normal, + template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, + "used internally for testing macro hygiene", + ), + + // ========================================================================== + // Internal attributes, Diagnostics related: + // ========================================================================== + + rustc_attr!( + rustc_on_unimplemented, Normal, + template!( + List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message" + ), + ErrorFollowing, + INTERNAL_UNSTABLE + ), + // Enumerates "identity-like" conversion methods to suggest on type mismatch. + rustc_attr!( + rustc_conversion_suggestion, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + ), + // Prevents field reads in the marked trait or method to be considered + // during dead code analysis. + rustc_attr!( + rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + ), + // Used by the `rustc::potential_query_instability` lint to warn methods which + // might not be stable during incremental compilation. + rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints + // to assist in changes to diagnostic APIs. + rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` + // types (as well as any others in future). + rustc_attr!(rustc_lint_opt_ty, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::bad_opt_access` lint on fields + // types (as well as any others in future). + rustc_attr!(rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), WarnFollowing, INTERNAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Const related: + // ========================================================================== + + rustc_attr!(rustc_promotable, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!( + rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, + INTERNAL_UNSTABLE + ), + // Do not const-check this function's body. It will always get replaced during CTFE. + rustc_attr!( + rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + ), + + // ========================================================================== + // Internal attributes, Layout related: + // ========================================================================== + + rustc_attr!( + rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing, + "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ + niche optimizations in libcore and libstd and will never be stable", + ), + rustc_attr!( + rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing, + "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ + niche optimizations in libcore and libstd and will never be stable", + ), + rustc_attr!( + rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ + niche optimizations in libcore and libstd and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Misc: + // ========================================================================== + gated!( + lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, @only_local: true, lang_items, + "language items are subject to change", + ), + rustc_attr!( + rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, + "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." + ), + rustc_attr!( + rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true, + "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." + ), + rustc_attr!( + rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: true, + "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." + ), + rustc_attr!( + rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, + "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." + ), + rustc_attr!( + rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + ), + rustc_attr!( + rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, + "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ + the given type by annotating all impl items with #[rustc_allow_incoherent_impl]." + ), + rustc_attr!( + rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, + "#[rustc_box] allows creating boxes \ + and it is only intended to be used in `alloc`." + ), + + BuiltinAttribute { + // name: sym::rustc_diagnostic_item, + name: "rustc_diagnostic_item", + // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. + // only_local: false, + // type_: Normal, + template: template!(NameValueStr: "name"), + // duplicates: ErrorFollowing, + // gate: Gated( + // Stability::Unstable, + // sym::rustc_attrs, + // "diagnostic items compiler internal support for linting", + // cfg_fn!(rustc_attrs), + // ), + }, + gated!( + // Used in resolve: + prelude_import, Normal, template!(Word), WarnFollowing, + "`#[prelude_import]` is for use by rustc only", + ), + gated!( + rustc_paren_sugar, Normal, template!(Word), WarnFollowing, unboxed_closures, + "unboxed_closures are still evolving", + ), + rustc_attr!( + rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true, + "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ + overflow checking behavior of several libcore functions that are inlined \ + across crates and will never be stable", + ), + rustc_attr!( + rustc_reservation_impl, Normal, + template!(NameValueStr: "reservation message"), ErrorFollowing, + "the `#[rustc_reservation_impl]` attribute is internally used \ + for reserving for `for From for T` impl" + ), + rustc_attr!( + rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, + "the `#[rustc_test_marker]` attribute is used internally to track tests", + ), + rustc_attr!( + rustc_unsafe_specialization_marker, Normal, template!(Word), WarnFollowing, + "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations" + ), + rustc_attr!( + rustc_specialization_trait, Normal, template!(Word), WarnFollowing, + "the `#[rustc_specialization_trait]` attribute is used to check specializations" + ), + rustc_attr!( + rustc_main, Normal, template!(Word), WarnFollowing, + "the `#[rustc_main]` attribute is used internally to specify test entry point function", + ), + rustc_attr!( + rustc_skip_array_during_method_dispatch, Normal, template!(Word), WarnFollowing, + "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \ + from method dispatch when the receiver is an array, for compatibility in editions < 2021." + ), + rustc_attr!( + rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing, + "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \ + definition of a trait, it's currently in experimental form and should be changed before \ + being exposed outside of the std" + ), + rustc_attr!( + rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, + r#"`rustc_doc_primitive` is a rustc internal attribute"#, + ), + + // ========================================================================== + // Internal attributes, Testing: + // ========================================================================== + + rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), + rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), + rustc_attr!( + TEST, rustc_error, Normal, + template!(Word, List: "delay_span_bug_from_inside_query"), WarnFollowingWordOnly + ), + rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), + rustc_attr!( + TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk + ), + rustc_attr!( + TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk + ), + rustc_attr!( + TEST, rustc_clean, Normal, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + DuplicatesOk, + ), + rustc_attr!( + TEST, rustc_partition_reused, Normal, + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, + ), + rustc_attr!( + TEST, rustc_partition_codegened, Normal, + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, + ), + rustc_attr!( + TEST, rustc_expected_cgu_reuse, Normal, + template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk, + ), + rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk), + gated!( + custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#), + ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite", + ), + rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk), + gated!( + omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing, + "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", + ), +]; 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 new file mode 100644 index 000000000..e4c8d446a --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs @@ -0,0 +1,40 @@ +//! This module contains tests for doc-expression parsing. +//! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. + +use mbe::syntax_node_to_token_tree; +use syntax::{ast, AstNode}; + +use crate::attr::{DocAtom, DocExpr}; + +fn assert_parse_result(input: &str, expected: DocExpr) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + syntax_node_to_token_tree(tt.syntax()) + }; + 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 b70e658ef..94dc39b11 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -6,267 +6,30 @@ mod tests; pub mod scope; mod pretty; -use std::{ops::Index, sync::Arc}; +use std::ops::Index; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use drop_bomb::DropBomb; use either::Either; -use hir_expand::{ - attrs::RawAttrs, hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId, -}; +use hir_expand::{name::Name, HirFileId, InFile}; use la_arena::{Arena, ArenaMap}; -use limit::Limit; use profile::Count; use rustc_hash::FxHashMap; -use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr}; +use syntax::{ast, AstPtr, SyntaxNodePtr}; +use triomphe::Arc; use crate::{ - attr::Attrs, db::DefDatabase, - expr::{ + expander::Expander, + hir::{ dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, }, - item_scope::BuiltinShadowMode, - macro_id_to_def_id, nameres::DefMap, path::{ModPath, Path}, src::{HasChildSource, HasSource}, - AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, - UnresolvedMacro, + BlockId, DefWithBodyId, HasModule, Lookup, }; -pub use lower::LowerCtx; - -/// A subset of Expander that only deals with cfg attributes. We only need it to -/// avoid cyclic queries in crate def map during enum processing. -#[derive(Debug)] -pub(crate) struct CfgExpander { - cfg_options: CfgOptions, - hygiene: Hygiene, - krate: CrateId, -} - -#[derive(Debug)] -pub struct Expander { - cfg_expander: CfgExpander, - def_map: Arc, - current_file_id: HirFileId, - module: LocalModuleId, - /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. - recursion_depth: usize, -} - -impl CfgExpander { - pub(crate) fn new( - db: &dyn DefDatabase, - current_file_id: HirFileId, - krate: CrateId, - ) -> CfgExpander { - let hygiene = Hygiene::new(db.upcast(), current_file_id); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - CfgExpander { cfg_options, hygiene, krate } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) - } - - pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { - let attrs = self.parse_attrs(db, owner); - attrs.is_cfg_enabled(&self.cfg_options) - } -} - -impl Expander { - pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { - let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); - let def_map = module.def_map(db); - Expander { - cfg_expander, - def_map, - current_file_id, - module: module.local_id, - recursion_depth: 0, - } - } - - pub fn enter_expand( - &mut self, - db: &dyn DefDatabase, - macro_call: ast::MacroCall, - ) -> Result>, UnresolvedMacro> { - let mut unresolved_macro_err = None; - - let result = self.within_limit(db, |this| { - let macro_call = InFile::new(this.current_file_id, ¯o_call); - - let resolver = - |path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it)); - - let mut err = None; - let call_id = match macro_call.as_call_id_with_errors( - db, - this.def_map.krate(), - resolver, - &mut |e| { - err.get_or_insert(e); - }, - ) { - Ok(call_id) => call_id, - Err(resolve_err) => { - unresolved_macro_err = Some(resolve_err); - return ExpandResult { value: None, err: None }; - } - }; - ExpandResult { value: call_id.ok(), err } - }); - - if let Some(err) = unresolved_macro_err { - Err(err) - } else { - Ok(result) - } - } - - pub fn enter_expand_id( - &mut self, - db: &dyn DefDatabase, - call_id: MacroCallId, - ) -> ExpandResult> { - self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) - } - - fn enter_expand_inner( - db: &dyn DefDatabase, - call_id: MacroCallId, - mut err: Option, - ) -> ExpandResult> { - if err.is_none() { - err = db.macro_expand_error(call_id); - } - - let file_id = call_id.as_file(); - - let raw_node = match db.parse_or_expand(file_id) { - Some(it) => it, - None => { - // Only `None` if the macro expansion produced no usable AST. - if err.is_none() { - tracing::warn!("no error despite `parse_or_expand` failing"); - } - - return ExpandResult::only_err(err.unwrap_or_else(|| { - ExpandError::Other("failed to parse macro invocation".into()) - })); - } - }; - - ExpandResult { value: Some((file_id, raw_node)), err } - } - - pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); - self.current_file_id = mark.file_id; - if self.recursion_depth == usize::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. Reset the - // depth only when we get out of the tree. - if !self.current_file_id.is_macro() { - self.recursion_depth = 0; - } - } else { - self.recursion_depth -= 1; - } - mark.bomb.defuse(); - } - - pub(crate) fn to_source(&self, value: T) -> InFile { - InFile { file_id: self.current_file_id, value } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - self.cfg_expander.parse_attrs(db, owner) - } - - pub(crate) fn cfg_options(&self) -> &CfgOptions { - &self.cfg_expander.cfg_options - } - - pub fn current_file_id(&self) -> HirFileId { - self.current_file_id - } - - fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); - Path::from_src(path, &ctx) - } - - fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros() - } - - fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit { - let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _; - - #[cfg(not(test))] - return Limit::new(limit); - - // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug - #[cfg(test)] - return Limit::new(std::cmp::min(32, limit)); - } - - fn within_limit( - &mut self, - db: &dyn DefDatabase, - op: F, - ) -> ExpandResult> - where - F: FnOnce(&mut Self) -> ExpandResult>, - { - if self.recursion_depth == usize::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. We should - // stop expanding other macro calls in this tree, or else this may result in - // exponential number of macro expansions, leading to a hang. - // - // The overflow error should have been reported when it occurred (see the next branch), - // so don't return overflow error here to avoid diagnostics duplication. - cov_mark::hit!(overflow_but_not_me); - return ExpandResult::only_err(ExpandError::RecursionOverflowPosioned); - } else if self.recursion_limit(db).check(self.recursion_depth + 1).is_err() { - self.recursion_depth = usize::MAX; - cov_mark::hit!(your_stack_belongs_to_me); - return ExpandResult::only_err(ExpandError::Other( - "reached recursion limit during macro expansion".into(), - )); - } - - let ExpandResult { value, err } = op(self); - let Some(call_id) = value else { - return ExpandResult { value: None, err }; - }; - - Self::enter_expand_inner(db, call_id, err).map(|value| { - value.and_then(|(new_file_id, node)| { - let node = T::cast(node)?; - - self.recursion_depth += 1; - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), new_file_id); - let old_file_id = std::mem::replace(&mut self.current_file_id, new_file_id); - let mark = - Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") }; - Some((mark, node)) - }) - }) - } -} - -#[derive(Debug)] -pub struct Mark { - file_id: HirFileId, - bomb: DropBomb, -} - /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] pub struct Body { @@ -274,6 +37,9 @@ pub struct Body { pub pats: Arena, pub bindings: Arena, pub labels: Arena