aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock23
-rw-r--r--Cargo.toml1
-rw-r--r--crates/base_db/src/fixture.rs2
-rw-r--r--crates/base_db/src/lib.rs3
-rw-r--r--crates/cfg/src/cfg_expr.rs2
-rw-r--r--crates/cfg/src/lib.rs2
-rw-r--r--crates/hir/Cargo.toml1
-rw-r--r--crates/hir/src/diagnostics.rs297
-rw-r--r--crates/hir/src/lib.rs407
-rw-r--r--crates/hir/src/semantics.rs109
-rw-r--r--crates/hir/src/semantics/source_to_def.rs121
-rw-r--r--crates/hir/src/source_analyzer.rs6
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_def/src/attr.rs32
-rw-r--r--crates/hir_def/src/body/lower.rs8
-rw-r--r--crates/hir_def/src/body/scope.rs2
-rw-r--r--crates/hir_def/src/body/tests.rs149
-rw-r--r--crates/hir_def/src/body/tests/block.rs10
-rw-r--r--crates/hir_def/src/builtin_attr.rs38
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/data.rs17
-rw-r--r--crates/hir_def/src/db.rs3
-rw-r--r--crates/hir_def/src/generics.rs4
-rw-r--r--crates/hir_def/src/import_map.rs169
-rw-r--r--crates/hir_def/src/item_scope.rs19
-rw-r--r--crates/hir_def/src/item_tree/lower.rs17
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs2
-rw-r--r--crates/hir_def/src/item_tree/tests.rs38
-rw-r--r--crates/hir_def/src/keys.rs3
-rw-r--r--crates/hir_def/src/lang_item.rs1
-rw-r--r--crates/hir_def/src/lib.rs86
-rw-r--r--crates/hir_def/src/nameres/collector.rs82
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs12
-rw-r--r--crates/hir_def/src/nameres/tests.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs229
-rw-r--r--crates/hir_def/src/path/lower.rs4
-rw-r--r--crates/hir_def/src/per_ns.rs2
-rw-r--r--crates/hir_def/src/resolver.rs10
-rw-r--r--crates/hir_def/src/test_db.rs161
-rw-r--r--crates/hir_def/src/type_ref.rs16
-rw-r--r--crates/hir_expand/src/builtin_attr.rs67
-rw-r--r--crates/hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/hir_expand/src/builtin_macro.rs14
-rw-r--r--crates/hir_expand/src/db.rs27
-rw-r--r--crates/hir_expand/src/eager.rs20
-rw-r--r--crates/hir_expand/src/hygiene.rs1
-rw-r--r--crates/hir_expand/src/input.rs25
-rw-r--r--crates/hir_expand/src/lib.rs30
-rw-r--r--crates/hir_expand/src/name.rs9
-rw-r--r--crates/hir_expand/src/proc_macro.rs8
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/hir_ty/src/builder.rs2
-rw-r--r--crates/hir_ty/src/chalk_db.rs39
-rw-r--r--crates/hir_ty/src/consteval.rs2
-rw-r--r--crates/hir_ty/src/db.rs7
-rw-r--r--crates/hir_ty/src/diagnostics.rs772
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs357
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs507
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs955
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs13
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs151
-rw-r--r--crates/hir_ty/src/diagnostics_sink.rs109
-rw-r--r--crates/hir_ty/src/infer.rs98
-rw-r--r--crates/hir_ty/src/infer/coerce.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs23
-rw-r--r--crates/hir_ty/src/infer/pat.rs15
-rw-r--r--crates/hir_ty/src/infer/path.rs6
-rw-r--r--crates/hir_ty/src/interner.rs6
-rw-r--r--crates/hir_ty/src/lib.rs3
-rw-r--r--crates/hir_ty/src/lower.rs10
-rw-r--r--crates/hir_ty/src/method_resolution.rs98
-rw-r--r--crates/hir_ty/src/test_db.rs10
-rw-r--r--crates/hir_ty/src/tests.rs98
-rw-r--r--crates/hir_ty/src/tests/coercion.rs43
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs49
-rw-r--r--crates/hir_ty/src/tests/patterns.rs104
-rw-r--r--crates/hir_ty/src/tests/traits.rs67
-rw-r--r--crates/ide/Cargo.toml3
-rw-r--r--crates/ide/src/diagnostics.rs544
-rw-r--r--crates/ide/src/diagnostics/break_outside_of_loop.rs30
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs33
-rw-r--r--crates/ide/src/diagnostics/fixes.rs31
-rw-r--r--crates/ide/src/diagnostics/fixes/change_case.rs155
-rw-r--r--crates/ide/src/diagnostics/fixes/fill_missing_fields.rs217
-rw-r--r--crates/ide/src/diagnostics/fixes/remove_semicolon.rs41
-rw-r--r--crates/ide/src/diagnostics/fixes/replace_with_find_map.rs84
-rw-r--r--crates/ide/src/diagnostics/inactive_code.rs119
-rw-r--r--crates/ide/src/diagnostics/incorrect_case.rs488
-rw-r--r--crates/ide/src/diagnostics/macro_error.rs173
-rw-r--r--crates/ide/src/diagnostics/mismatched_arg_count.rs272
-rw-r--r--crates/ide/src/diagnostics/missing_fields.rs327
-rw-r--r--crates/ide/src/diagnostics/missing_match_arms.rs929
-rw-r--r--crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs (renamed from crates/ide/src/diagnostics/fixes/wrap_tail_expr.rs)65
-rw-r--r--crates/ide/src/diagnostics/missing_unsafe.rs101
-rw-r--r--crates/ide/src/diagnostics/no_such_field.rs (renamed from crates/ide/src/diagnostics/fixes/create_field.rs)164
-rw-r--r--crates/ide/src/diagnostics/remove_this_semicolon.rs64
-rw-r--r--crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs182
-rw-r--r--crates/ide/src/diagnostics/unimplemented_builtin_macro.rs19
-rw-r--r--crates/ide/src/diagnostics/unlinked_file.rs259
-rw-r--r--crates/ide/src/diagnostics/unresolved_extern_crate.rs49
-rw-r--r--crates/ide/src/diagnostics/unresolved_import.rs90
-rw-r--r--crates/ide/src/diagnostics/unresolved_macro_call.rs84
-rw-r--r--crates/ide/src/diagnostics/unresolved_module.rs (renamed from crates/ide/src/diagnostics/fixes/unresolved_module.rs)88
-rw-r--r--crates/ide/src/diagnostics/unresolved_proc_macro.rs30
-rw-r--r--crates/ide/src/doc_links.rs22
-rw-r--r--crates/ide/src/expand_macro.rs32
-rw-r--r--crates/ide/src/extend_selection.rs2
-rw-r--r--crates/ide/src/fixture.rs12
-rw-r--r--crates/ide/src/goto_definition.rs153
-rw-r--r--crates/ide/src/goto_implementation.rs6
-rw-r--r--crates/ide/src/hover.rs184
-rw-r--r--crates/ide/src/inlay_hints.rs1131
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/lib.rs12
-rw-r--r--crates/ide/src/prime_caches.rs7
-rw-r--r--crates/ide/src/references.rs22
-rw-r--r--crates/ide/src/references/rename.rs208
-rw-r--r--crates/ide/src/runnables.rs8
-rw-r--r--crates/ide/src/syntax_highlighting.rs34
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs15
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html9
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs9
-rw-r--r--crates/ide/src/typing/on_enter.rs6
-rw-r--r--crates/ide_assists/Cargo.toml2
-rw-r--r--crates/ide_assists/src/assist_context.rs3
-rw-r--r--crates/ide_assists/src/handlers/apply_demorgan.rs4
-rw-r--r--crates/ide_assists/src/handlers/change_visibility.rs11
-rw-r--r--crates/ide_assists/src/handlers/convert_comment_block.rs4
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs352
-rw-r--r--crates/ide_assists/src/handlers/early_return.rs4
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs10
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs169
-rw-r--r--crates/ide_assists/src/handlers/extract_type_alias.rs68
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs33
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ide_assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_is_method.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_projection_method.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs8
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_new.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_setter.rs2
-rw-r--r--crates/ide_assists/src/handlers/inline_local_variable.rs17
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs2
-rw-r--r--crates/ide_assists/src/handlers/remove_unused_param.rs30
-rw-r--r--crates/ide_assists/src/handlers/reorder_fields.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_if_let_with_match.rs2
-rw-r--r--crates/ide_assists/src/handlers/wrap_return_type_in_result.rs2
-rw-r--r--crates/ide_assists/src/lib.rs8
-rw-r--r--crates/ide_assists/src/tests.rs2
-rw-r--r--crates/ide_assists/src/utils.rs2
-rw-r--r--crates/ide_assists/src/utils/suggest_name.rs2
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions.rs62
-rw-r--r--crates/ide_completion/src/completions/attribute.rs28
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs80
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs139
-rw-r--r--crates/ide_completion/src/completions/dot.rs8
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs27
-rw-r--r--crates/ide_completion/src/completions/keyword.rs25
-rw-r--r--crates/ide_completion/src/completions/macro_in_item_position.rs48
-rw-r--r--crates/ide_completion/src/completions/pattern.rs24
-rw-r--r--crates/ide_completion/src/completions/postfix.rs22
-rw-r--r--crates/ide_completion/src/completions/postfix/format_like.rs22
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs84
-rw-r--r--crates/ide_completion/src/completions/snippet.rs14
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs18
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs130
-rw-r--r--crates/ide_completion/src/context.rs174
-rw-r--r--crates/ide_completion/src/lib.rs2
-rw-r--r--crates/ide_completion/src/patterns.rs30
-rw-r--r--crates/ide_completion/src/render.rs400
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs12
-rw-r--r--crates/ide_completion/src/render/function.rs26
-rw-r--r--crates/ide_completion/src/render/macro_.rs4
-rw-r--r--crates/ide_completion/src/render/pattern.rs6
-rw-r--r--crates/ide_completion/src/render/type_alias.rs23
-rw-r--r--crates/ide_db/Cargo.toml2
-rw-r--r--crates/ide_db/src/call_info.rs5
-rw-r--r--crates/ide_db/src/defs.rs10
-rw-r--r--crates/ide_db/src/helpers.rs1
-rw-r--r--crates/ide_db/src/helpers/generated_lints.rs (renamed from crates/ide_completion/src/generated_lint_completions.rs)8108
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs4
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs18
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs15
-rw-r--r--crates/ide_db/src/helpers/merge_imports.rs2
-rw-r--r--crates/ide_db/src/lib.rs1
-rw-r--r--crates/ide_db/src/search.rs61
-rw-r--r--crates/ide_db/src/symbol_index.rs2
-rw-r--r--crates/ide_ssr/Cargo.toml2
-rw-r--r--crates/ide_ssr/src/matching.rs6
-rw-r--r--crates/ide_ssr/src/replacing.rs10
-rw-r--r--crates/ide_ssr/src/resolving.rs2
-rw-r--r--crates/ide_ssr/src/search.rs2
-rw-r--r--crates/ide_ssr/src/tests.rs4
-rw-r--r--crates/mbe/Cargo.toml2
-rw-r--r--crates/mbe/src/benchmark.rs2
-rw-r--r--crates/mbe/src/expander/matcher.rs41
-rw-r--r--crates/mbe/src/expander/transcriber.rs8
-rw-r--r--crates/mbe/src/lib.rs16
-rw-r--r--crates/mbe/src/parser.rs16
-rw-r--r--crates/mbe/src/subtree_source.rs6
-rw-r--r--crates/mbe/src/syntax_bridge.rs7
-rw-r--r--crates/mbe/src/tests/expand.rs44
-rw-r--r--crates/mbe/src/tt_iter.rs4
-rw-r--r--crates/parser/src/grammar/attributes.rs3
-rw-r--r--crates/parser/src/grammar/expressions.rs2
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs8
-rw-r--r--crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--crates/paths/src/lib.rs2
-rw-r--r--crates/proc_macro_api/src/msg.rs4
-rw-r--r--crates/proc_macro_api/src/process.rs4
-rw-r--r--crates/proc_macro_api/src/version.rs2
-rw-r--r--crates/proc_macro_srv/src/dylib.rs11
-rw-r--r--crates/proc_macro_srv/src/lib.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/client.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/closure.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/handle.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/mod.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/server.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/diagnostic.rs11
-rw-r--r--crates/proc_macro_srv/src/proc_macro/mod.rs2
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs4
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs29
-rw-r--r--crates/proc_macro_test/Cargo.toml6
-rw-r--r--crates/proc_macro_test/build.rs48
-rw-r--r--crates/proc_macro_test/imp/.gitignore2
-rw-r--r--crates/proc_macro_test/imp/Cargo.toml17
-rw-r--r--crates/proc_macro_test/imp/src/lib.rs48
-rw-r--r--crates/proc_macro_test/src/lib.rs48
-rw-r--r--crates/profile/Cargo.toml3
-rw-r--r--crates/profile/src/lib.rs6
-rw-r--r--crates/profile/src/memory_usage.rs51
-rw-r--r--crates/project_model/src/build_data.rs2
-rw-r--r--crates/project_model/src/cargo_workspace.rs2
-rw-r--r--crates/project_model/src/sysroot.rs4
-rw-r--r--crates/project_model/src/workspace.rs12
-rw-r--r--crates/rust-analyzer/src/bin/flags.rs24
-rw-r--r--crates/rust-analyzer/src/bin/main.rs6
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs2
-rw-r--r--crates/rust-analyzer/src/cli.rs1
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs9
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs8
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs23
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs9
-rw-r--r--crates/rust-analyzer/src/config.rs11
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs6
-rw-r--r--crates/rust-analyzer/src/dispatch.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs19
-rw-r--r--crates/rust-analyzer/src/handlers.rs52
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs4
-rw-r--r--crates/rust-analyzer/src/reload.rs6
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs10
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs6
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs2
-rw-r--r--crates/stdx/src/panic_context.rs2
-rw-r--r--crates/stdx/src/process.rs4
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/edit.rs4
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs31
-rw-r--r--crates/syntax/src/ast/make.rs5
-rw-r--r--crates/syntax/src/ast/node_ext.rs24
-rw-r--r--crates/syntax/src/ast/token_ext.rs2
-rw-r--r--crates/syntax/src/parsing.rs4
-rw-r--r--crates/syntax/src/parsing/lexer.rs2
-rw-r--r--crates/syntax/src/parsing/reparsing.rs14
-rw-r--r--crates/syntax/src/tests.rs6
-rw-r--r--crates/syntax/test_data/parser/err/0005_attribute_recover.rast66
-rw-r--r--crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast68
-rw-r--r--crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast18
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast51
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast125
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast34
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast45
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast18
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast23
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/ok/0006_inner_attributes.rast258
-rw-r--r--crates/syntax/test_data/parser/ok/0008_mod_item.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0011_outer_attribute.rast45
-rw-r--r--crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast19
-rw-r--r--crates/syntax/test_data/parser/ok/0035_weird_exprs.rast87
-rw-r--r--crates/syntax/test_data/parser/ok/0044_let_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rast102
-rw-r--r--crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast17
-rw-r--r--crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast135
-rw-r--r--crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0062_macro_2.0.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0063_variadic_fun.rast17
-rw-r--r--crates/test_utils/src/lib.rs58
-rw-r--r--crates/tt/src/buffer.rs2
-rw-r--r--crates/tt/src/lib.rs4
-rw-r--r--crates/vfs/src/file_set.rs2
-rw-r--r--docs/dev/README.md16
-rw-r--r--docs/dev/architecture.md2
-rw-r--r--docs/user/generated_config.adoc12
-rw-r--r--docs/user/manual.adoc14
-rw-r--r--editors/code/package.json12
-rw-r--r--editors/code/src/config.ts1
-rw-r--r--editors/code/src/ctx.ts1
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/ast_src.rs2
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs94
-rw-r--r--xtask/src/codegen/gen_syntax.rs26
-rw-r--r--xtask/src/main.rs2
-rw-r--r--xtask/src/metrics.rs7
-rw-r--r--xtask/src/release/changelog.rs4
-rw-r--r--xtask/src/tidy.rs70
330 files changed, 14039 insertions, 11266 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 505263c64..e47b87964 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -245,9 +245,9 @@ dependencies = [
245 245
246[[package]] 246[[package]]
247name = "cov-mark" 247name = "cov-mark"
248version = "1.1.0" 248version = "2.0.0-pre.1"
249source = "registry+https://github.com/rust-lang/crates.io-index" 249source = "registry+https://github.com/rust-lang/crates.io-index"
250checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3" 250checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a"
251 251
252[[package]] 252[[package]]
253name = "crc32fast" 253name = "crc32fast"
@@ -482,6 +482,7 @@ dependencies = [
482 "hir_ty", 482 "hir_ty",
483 "itertools", 483 "itertools",
484 "log", 484 "log",
485 "once_cell",
485 "profile", 486 "profile",
486 "rustc-hash", 487 "rustc-hash",
487 "smallvec", 488 "smallvec",
@@ -765,9 +766,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
765 766
766[[package]] 767[[package]]
767name = "libc" 768name = "libc"
768version = "0.2.95" 769version = "0.2.97"
769source = "registry+https://github.com/rust-lang/crates.io-index" 770source = "registry+https://github.com/rust-lang/crates.io-index"
770checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" 771checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
771 772
772[[package]] 773[[package]]
773name = "libloading" 774name = "libloading"
@@ -1158,6 +1159,15 @@ dependencies = [
1158[[package]] 1159[[package]]
1159name = "proc_macro_test" 1160name = "proc_macro_test"
1160version = "0.0.0" 1161version = "0.0.0"
1162dependencies = [
1163 "cargo_metadata",
1164 "proc_macro_test_impl",
1165 "toolchain",
1166]
1167
1168[[package]]
1169name = "proc_macro_test_impl"
1170version = "0.0.0"
1161 1171
1162[[package]] 1172[[package]]
1163name = "profile" 1173name = "profile"
@@ -1170,6 +1180,7 @@ dependencies = [
1170 "once_cell", 1180 "once_cell",
1171 "perf-event", 1181 "perf-event",
1172 "tikv-jemalloc-ctl", 1182 "tikv-jemalloc-ctl",
1183 "winapi",
1173] 1184]
1174 1185
1175[[package]] 1186[[package]]
@@ -1792,9 +1803,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1792 1803
1793[[package]] 1804[[package]]
1794name = "ungrammar" 1805name = "ungrammar"
1795version = "1.13.0" 1806version = "1.14.0"
1796source = "registry+https://github.com/rust-lang/crates.io-index" 1807source = "registry+https://github.com/rust-lang/crates.io-index"
1797checksum = "76760314176cc2b94047af2f921b92c39f11a34dc05c43a3c2b0fc91cb22959f" 1808checksum = "50ef6d7335c77ec3e4a7c4be74c2b9e4642569e94a4004c836f8cca71fede3a7"
1798 1809
1799[[package]] 1810[[package]]
1800name = "unicase" 1811name = "unicase"
diff --git a/Cargo.toml b/Cargo.toml
index 32ba3923b..4d6908fa9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,7 @@
1[workspace] 1[workspace]
2resolver = "2" 2resolver = "2"
3members = ["xtask/", "lib/*", "crates/*"] 3members = ["xtask/", "lib/*", "crates/*"]
4exclude = ["crates/proc_macro_test/imp"]
4 5
5[profile.dev] 6[profile.dev]
6# Disabling debug info speeds up builds a bunch, 7# Disabling debug info speeds up builds a bunch,
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 69ceba735..da4afb5eb 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -190,7 +190,7 @@ impl From<Fixture> for FileMeta {
190 edition: f 190 edition: f
191 .edition 191 .edition
192 .as_ref() 192 .as_ref()
193 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), 193 .map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()),
194 env: f.env.into_iter().collect(), 194 env: f.env.into_iter().collect(),
195 introduce_new_source_root: f.introduce_new_source_root, 195 introduce_new_source_root: f.introduce_new_source_root,
196 } 196 }
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 62bf2a4b2..d26f8f180 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -42,7 +42,7 @@ pub struct FilePosition {
42 pub offset: TextSize, 42 pub offset: TextSize,
43} 43}
44 44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)] 45#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
46pub struct FileRange { 46pub struct FileRange {
47 pub file_id: FileId, 47 pub file_id: FileId,
48 pub range: TextRange, 48 pub range: TextRange,
@@ -120,6 +120,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
120 } 120 }
121 121
122 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 122 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
123 let _p = profile::span("relevant_crates");
123 let source_root = self.0.file_source_root(file_id); 124 let source_root = self.0.file_source_root(file_id);
124 self.0.source_root_crates(source_root) 125 self.0.source_root_crates(source_root)
125 } 126 }
diff --git a/crates/cfg/src/cfg_expr.rs b/crates/cfg/src/cfg_expr.rs
index 069fc01d0..8a1a51e6e 100644
--- a/crates/cfg/src/cfg_expr.rs
+++ b/crates/cfg/src/cfg_expr.rs
@@ -1,6 +1,6 @@
1//! The condition expression used in `#[cfg(..)]` attributes. 1//! The condition expression used in `#[cfg(..)]` attributes.
2//! 2//!
3//! See: https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation 3//! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation>
4 4
5use std::{fmt, slice::Iter as SliceIter}; 5use std::{fmt, slice::Iter as SliceIter};
6 6
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 59fd38880..03b8dd767 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -22,7 +22,7 @@ pub use dnf::DnfExpr;
22/// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple 22/// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple
23/// of key and value in `key_values`. 23/// of key and value in `key_values`.
24/// 24///
25/// See: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options 25/// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
26#[derive(Debug, Clone, PartialEq, Eq, Default)] 26#[derive(Debug, Clone, PartialEq, Eq, Default)]
27pub struct CfgOptions { 27pub struct CfgOptions {
28 enabled: FxHashSet<CfgAtom>, 28 enabled: FxHashSet<CfgAtom>,
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 560b15238..7c148fd40 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -16,6 +16,7 @@ either = "1.5.3"
16arrayvec = "0.7" 16arrayvec = "0.7"
17itertools = "0.10.0" 17itertools = "0.10.0"
18smallvec = "1.4.0" 18smallvec = "1.4.0"
19once_cell = "1"
19 20
20stdx = { path = "../stdx", version = "0.0.0" } 21stdx = { path = "../stdx", version = "0.0.0" }
21syntax = { path = "../syntax", version = "0.0.0" } 22syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 2cdbd172a..b4c505898 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -3,251 +3,152 @@
3//! 3//!
4//! This probably isn't the best way to do this -- ideally, diagnistics should 4//! This probably isn't the best way to do this -- ideally, diagnistics should
5//! be expressed in terms of hir types themselves. 5//! be expressed in terms of hir types themselves.
6use std::any::Any; 6use cfg::{CfgExpr, CfgOptions};
7 7use either::Either;
8use cfg::{CfgExpr, CfgOptions, DnfExpr};
9use hir_def::path::ModPath; 8use hir_def::path::ModPath;
10use hir_expand::{HirFileId, InFile}; 9use hir_expand::{name::Name, HirFileId, InFile};
11use stdx::format_to;
12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 10use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
13 11
14pub use hir_ty::{ 12macro_rules! diagnostics {
15 diagnostics::{ 13 ($($diag:ident,)*) => {
16 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, 14 pub enum AnyDiagnostic {$(
17 MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon, 15 $diag(Box<$diag>),
18 ReplaceFilterMapNextWithFindMap, 16 )*}
19 }, 17
20 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, 18 $(
21}; 19 impl From<$diag> for AnyDiagnostic {
22 20 fn from(d: $diag) -> AnyDiagnostic {
23// Diagnostic: unresolved-module 21 AnyDiagnostic::$diag(Box::new(d))
24// 22 }
25// This diagnostic is triggered if rust-analyzer is unable to discover referred module. 23 }
24 )*
25 };
26}
27
28diagnostics![
29 BreakOutsideOfLoop,
30 InactiveCode,
31 IncorrectCase,
32 MacroError,
33 MismatchedArgCount,
34 MissingFields,
35 MissingMatchArms,
36 MissingOkOrSomeInTailExpr,
37 MissingUnsafe,
38 NoSuchField,
39 RemoveThisSemicolon,
40 ReplaceFilterMapNextWithFindMap,
41 UnimplementedBuiltinMacro,
42 UnresolvedExternCrate,
43 UnresolvedImport,
44 UnresolvedMacroCall,
45 UnresolvedModule,
46 UnresolvedProcMacro,
47];
48
26#[derive(Debug)] 49#[derive(Debug)]
27pub struct UnresolvedModule { 50pub struct UnresolvedModule {
28 pub file: HirFileId, 51 pub decl: InFile<AstPtr<ast::Module>>,
29 pub decl: AstPtr<ast::Module>,
30 pub candidate: String, 52 pub candidate: String,
31} 53}
32 54
33impl Diagnostic for UnresolvedModule {
34 fn code(&self) -> DiagnosticCode {
35 DiagnosticCode("unresolved-module")
36 }
37 fn message(&self) -> String {
38 "unresolved module".to_string()
39 }
40 fn display_source(&self) -> InFile<SyntaxNodePtr> {
41 InFile::new(self.file, self.decl.clone().into())
42 }
43 fn as_any(&self) -> &(dyn Any + Send + 'static) {
44 self
45 }
46}
47
48// Diagnostic: unresolved-extern-crate
49//
50// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
51#[derive(Debug)] 55#[derive(Debug)]
52pub struct UnresolvedExternCrate { 56pub struct UnresolvedExternCrate {
53 pub file: HirFileId, 57 pub decl: InFile<AstPtr<ast::ExternCrate>>,
54 pub item: AstPtr<ast::ExternCrate>,
55}
56
57impl Diagnostic for UnresolvedExternCrate {
58 fn code(&self) -> DiagnosticCode {
59 DiagnosticCode("unresolved-extern-crate")
60 }
61 fn message(&self) -> String {
62 "unresolved extern crate".to_string()
63 }
64 fn display_source(&self) -> InFile<SyntaxNodePtr> {
65 InFile::new(self.file, self.item.clone().into())
66 }
67 fn as_any(&self) -> &(dyn Any + Send + 'static) {
68 self
69 }
70} 58}
71 59
72#[derive(Debug)] 60#[derive(Debug)]
73pub struct UnresolvedImport { 61pub struct UnresolvedImport {
74 pub file: HirFileId, 62 pub decl: InFile<AstPtr<ast::UseTree>>,
75 pub node: AstPtr<ast::UseTree>, 63}
76} 64
77
78impl Diagnostic for UnresolvedImport {
79 fn code(&self) -> DiagnosticCode {
80 DiagnosticCode("unresolved-import")
81 }
82 fn message(&self) -> String {
83 "unresolved import".to_string()
84 }
85 fn display_source(&self) -> InFile<SyntaxNodePtr> {
86 InFile::new(self.file, self.node.clone().into())
87 }
88 fn as_any(&self) -> &(dyn Any + Send + 'static) {
89 self
90 }
91 fn is_experimental(&self) -> bool {
92 // This currently results in false positives in the following cases:
93 // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
94 // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
95 // - proc macros and/or proc macro generated code
96 true
97 }
98}
99
100// Diagnostic: unresolved-macro-call
101//
102// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
103// macro in a macro invocation.
104#[derive(Debug, Clone, Eq, PartialEq)] 65#[derive(Debug, Clone, Eq, PartialEq)]
105pub struct UnresolvedMacroCall { 66pub struct UnresolvedMacroCall {
106 pub file: HirFileId, 67 pub macro_call: InFile<AstPtr<ast::MacroCall>>,
107 pub node: AstPtr<ast::MacroCall>,
108 pub path: ModPath, 68 pub path: ModPath,
109} 69}
110 70
111impl Diagnostic for UnresolvedMacroCall {
112 fn code(&self) -> DiagnosticCode {
113 DiagnosticCode("unresolved-macro-call")
114 }
115 fn message(&self) -> String {
116 format!("unresolved macro `{}!`", self.path)
117 }
118 fn display_source(&self) -> InFile<SyntaxNodePtr> {
119 InFile::new(self.file, self.node.clone().into())
120 }
121 fn as_any(&self) -> &(dyn Any + Send + 'static) {
122 self
123 }
124 fn is_experimental(&self) -> bool {
125 true
126 }
127}
128
129// Diagnostic: inactive-code
130//
131// This diagnostic is shown for code with inactive `#[cfg]` attributes.
132#[derive(Debug, Clone, Eq, PartialEq)] 71#[derive(Debug, Clone, Eq, PartialEq)]
133pub struct InactiveCode { 72pub struct InactiveCode {
134 pub file: HirFileId, 73 pub node: InFile<SyntaxNodePtr>,
135 pub node: SyntaxNodePtr,
136 pub cfg: CfgExpr, 74 pub cfg: CfgExpr,
137 pub opts: CfgOptions, 75 pub opts: CfgOptions,
138} 76}
139 77
140impl Diagnostic for InactiveCode {
141 fn code(&self) -> DiagnosticCode {
142 DiagnosticCode("inactive-code")
143 }
144 fn message(&self) -> String {
145 let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts);
146 let mut buf = "code is inactive due to #[cfg] directives".to_string();
147
148 if let Some(inactive) = inactive {
149 format_to!(buf, ": {}", inactive);
150 }
151
152 buf
153 }
154 fn display_source(&self) -> InFile<SyntaxNodePtr> {
155 InFile::new(self.file, self.node.clone())
156 }
157 fn as_any(&self) -> &(dyn Any + Send + 'static) {
158 self
159 }
160}
161
162// Diagnostic: unresolved-proc-macro
163//
164// This diagnostic is shown when a procedural macro can not be found. This usually means that
165// procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
166// but can also indicate project setup problems.
167//
168// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
169// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
170// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
171#[derive(Debug, Clone, Eq, PartialEq)] 78#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct UnresolvedProcMacro { 79pub struct UnresolvedProcMacro {
173 pub file: HirFileId, 80 pub node: InFile<SyntaxNodePtr>,
174 pub node: SyntaxNodePtr,
175 /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` 81 /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
176 /// to use instead. 82 /// to use instead.
177 pub precise_location: Option<TextRange>, 83 pub precise_location: Option<TextRange>,
178 pub macro_name: Option<String>, 84 pub macro_name: Option<String>,
179} 85}
180 86
181impl Diagnostic for UnresolvedProcMacro { 87#[derive(Debug, Clone, Eq, PartialEq)]
182 fn code(&self) -> DiagnosticCode { 88pub struct MacroError {
183 DiagnosticCode("unresolved-proc-macro") 89 pub node: InFile<SyntaxNodePtr>,
184 } 90 pub message: String,
91}
185 92
186 fn message(&self) -> String { 93#[derive(Debug)]
187 match &self.macro_name { 94pub struct UnimplementedBuiltinMacro {
188 Some(name) => format!("proc macro `{}` not expanded", name), 95 pub node: InFile<SyntaxNodePtr>,
189 None => "proc macro not expanded".to_string(), 96}
190 }
191 }
192 97
193 fn display_source(&self) -> InFile<SyntaxNodePtr> { 98#[derive(Debug)]
194 InFile::new(self.file, self.node.clone()) 99pub struct NoSuchField {
195 } 100 pub field: InFile<AstPtr<ast::RecordExprField>>,
101}
196 102
197 fn as_any(&self) -> &(dyn Any + Send + 'static) { 103#[derive(Debug)]
198 self 104pub struct BreakOutsideOfLoop {
199 } 105 pub expr: InFile<AstPtr<ast::Expr>>,
200} 106}
201 107
202// Diagnostic: macro-error 108#[derive(Debug)]
203// 109pub struct MissingUnsafe {
204// This diagnostic is shown for macro expansion errors. 110 pub expr: InFile<AstPtr<ast::Expr>>,
205#[derive(Debug, Clone, Eq, PartialEq)]
206pub struct MacroError {
207 pub file: HirFileId,
208 pub node: SyntaxNodePtr,
209 pub message: String,
210} 111}
211 112
212impl Diagnostic for MacroError { 113#[derive(Debug)]
213 fn code(&self) -> DiagnosticCode { 114pub struct MissingFields {
214 DiagnosticCode("macro-error") 115 pub file: HirFileId,
215 } 116 pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
216 fn message(&self) -> String { 117 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
217 self.message.clone() 118 pub missed_fields: Vec<Name>,
218 }
219 fn display_source(&self) -> InFile<SyntaxNodePtr> {
220 InFile::new(self.file, self.node.clone())
221 }
222 fn as_any(&self) -> &(dyn Any + Send + 'static) {
223 self
224 }
225 fn is_experimental(&self) -> bool {
226 // Newly added and not very well-tested, might contain false positives.
227 true
228 }
229} 119}
230 120
231#[derive(Debug)] 121#[derive(Debug)]
232pub struct UnimplementedBuiltinMacro { 122pub struct ReplaceFilterMapNextWithFindMap {
233 pub file: HirFileId, 123 pub file: HirFileId,
234 pub node: SyntaxNodePtr, 124 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
125 pub next_expr: AstPtr<ast::Expr>,
235} 126}
236 127
237impl Diagnostic for UnimplementedBuiltinMacro { 128#[derive(Debug)]
238 fn code(&self) -> DiagnosticCode { 129pub struct MismatchedArgCount {
239 DiagnosticCode("unimplemented-builtin-macro") 130 pub call_expr: InFile<AstPtr<ast::Expr>>,
240 } 131 pub expected: usize,
132 pub found: usize,
133}
241 134
242 fn message(&self) -> String { 135#[derive(Debug)]
243 "unimplemented built-in macro".to_string() 136pub struct RemoveThisSemicolon {
244 } 137 pub expr: InFile<AstPtr<ast::Expr>>,
138}
245 139
246 fn display_source(&self) -> InFile<SyntaxNodePtr> { 140#[derive(Debug)]
247 InFile::new(self.file, self.node.clone()) 141pub struct MissingOkOrSomeInTailExpr {
248 } 142 pub expr: InFile<AstPtr<ast::Expr>>,
143 // `Some` or `Ok` depending on whether the return type is Result or Option
144 pub required: String,
145}
249 146
250 fn as_any(&self) -> &(dyn Any + Send + 'static) { 147#[derive(Debug)]
251 self 148pub struct MissingMatchArms {
252 } 149 pub file: HirFileId,
150 pub match_expr: AstPtr<ast::Expr>,
151 pub arms: AstPtr<ast::MatchArmList>,
253} 152}
153
154pub use hir_ty::diagnostics::IncorrectCase;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d3ef29db4..5bc0b2338 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -15,7 +15,7 @@
15//! 15//!
16//! `hir` is what insulates the "we don't know how to actually write an incremental compiler" 16//! `hir` is what insulates the "we don't know how to actually write an incremental compiler"
17//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: 17//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
18//! https://www.tedinski.com/2018/02/06/system-boundaries.html. 18//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
19 19
20#![recursion_limit = "512"] 20#![recursion_limit = "512"]
21 21
@@ -35,14 +35,10 @@ use std::{iter, sync::Arc};
35 35
36use arrayvec::ArrayVec; 36use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 37use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40 UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
41};
42use either::Either; 38use either::Either;
43use hir_def::{ 39use hir_def::{
44 adt::{ReprKind, VariantData}, 40 adt::{ReprKind, VariantData},
45 body::BodyDiagnostic, 41 body::{BodyDiagnostic, SyntheticSyntax},
46 expr::{BindingAnnotation, LabelId, Pat, PatId}, 42 expr::{BindingAnnotation, LabelId, Pat, PatId},
47 item_tree::ItemTreeNode, 43 item_tree::ItemTreeNode,
48 lang_item::LangItemTarget, 44 lang_item::LangItemTarget,
@@ -50,7 +46,6 @@ use hir_def::{
50 per_ns::PerNs, 46 per_ns::PerNs,
51 resolver::{HasResolver, Resolver}, 47 resolver::{HasResolver, Resolver},
52 src::HasSource as _, 48 src::HasSource as _,
53 type_ref::TraitRef,
54 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, 49 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
55 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, 50 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
56 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 51 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
@@ -61,8 +56,8 @@ use hir_ty::{
61 autoderef, 56 autoderef,
62 consteval::ConstExt, 57 consteval::ConstExt,
63 could_unify, 58 could_unify,
64 diagnostics_sink::DiagnosticSink, 59 diagnostics::BodyValidationDiagnostic,
65 method_resolution::{self, def_crates, TyFingerprint}, 60 method_resolution::{self, TyFingerprint},
66 primitive::UintTy, 61 primitive::UintTy,
67 subst_prefix, 62 subst_prefix,
68 traits::FnTrait, 63 traits::FnTrait,
@@ -73,6 +68,7 @@ use hir_ty::{
73}; 68};
74use itertools::Itertools; 69use itertools::Itertools;
75use nameres::diagnostics::DefDiagnosticKind; 70use nameres::diagnostics::DefDiagnosticKind;
71use once_cell::unsync::Lazy;
76use rustc_hash::FxHashSet; 72use rustc_hash::FxHashSet;
77use stdx::{format_to, impl_from}; 73use stdx::{format_to, impl_from};
78use syntax::{ 74use syntax::{
@@ -85,6 +81,13 @@ use crate::db::{DefDatabase, HirDatabase};
85 81
86pub use crate::{ 82pub use crate::{
87 attrs::{HasAttrs, Namespace}, 83 attrs::{HasAttrs, Namespace},
84 diagnostics::{
85 AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, MacroError,
86 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
87 MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
88 UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
89 UnresolvedModule, UnresolvedProcMacro,
90 },
88 has_source::HasSource, 91 has_source::HasSource,
89 semantics::{PathResolution, Semantics, SemanticsScope}, 92 semantics::{PathResolution, Semantics, SemanticsScope},
90}; 93};
@@ -192,6 +195,7 @@ impl Crate {
192 db: &dyn DefDatabase, 195 db: &dyn DefDatabase,
193 query: import_map::Query, 196 query: import_map::Query,
194 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { 197 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
198 let _p = profile::span("query_external_importables");
195 import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { 199 import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item {
196 ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), 200 ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()),
197 ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), 201 ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()),
@@ -332,7 +336,7 @@ impl ModuleDef {
332 } 336 }
333 } 337 }
334 338
335 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 339 pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
336 let id = match self { 340 let id = match self {
337 ModuleDef::Adt(it) => match it { 341 ModuleDef::Adt(it) => match it {
338 Adt::Struct(it) => it.id.into(), 342 Adt::Struct(it) => it.id.into(),
@@ -345,15 +349,19 @@ impl ModuleDef {
345 ModuleDef::Module(it) => it.id.into(), 349 ModuleDef::Module(it) => it.id.into(),
346 ModuleDef::Const(it) => it.id.into(), 350 ModuleDef::Const(it) => it.id.into(),
347 ModuleDef::Static(it) => it.id.into(), 351 ModuleDef::Static(it) => it.id.into(),
348 _ => return, 352 _ => return Vec::new(),
349 }; 353 };
350 354
351 let module = match self.module(db) { 355 let module = match self.module(db) {
352 Some(it) => it, 356 Some(it) => it,
353 None => return, 357 None => return Vec::new(),
354 }; 358 };
355 359
356 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) 360 let mut acc = Vec::new();
361 for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) {
362 acc.push(diag.into())
363 }
364 acc
357 } 365 }
358} 366}
359 367
@@ -442,10 +450,10 @@ impl Module {
442 } 450 }
443 451
444 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { 452 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
445 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) 453 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of((*def).into())
446 } 454 }
447 455
448 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 456 pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
449 let _p = profile::span("Module::diagnostics").detail(|| { 457 let _p = profile::span("Module::diagnostics").detail(|| {
450 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 458 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
451 }); 459 });
@@ -458,18 +466,22 @@ impl Module {
458 match &diag.kind { 466 match &diag.kind {
459 DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { 467 DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
460 let decl = declaration.to_node(db.upcast()); 468 let decl = declaration.to_node(db.upcast());
461 sink.push(UnresolvedModule { 469 acc.push(
462 file: declaration.file_id, 470 UnresolvedModule {
463 decl: AstPtr::new(&decl), 471 decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
464 candidate: candidate.clone(), 472 candidate: candidate.clone(),
465 }) 473 }
474 .into(),
475 )
466 } 476 }
467 DefDiagnosticKind::UnresolvedExternCrate { ast } => { 477 DefDiagnosticKind::UnresolvedExternCrate { ast } => {
468 let item = ast.to_node(db.upcast()); 478 let item = ast.to_node(db.upcast());
469 sink.push(UnresolvedExternCrate { 479 acc.push(
470 file: ast.file_id, 480 UnresolvedExternCrate {
471 item: AstPtr::new(&item), 481 decl: InFile::new(ast.file_id, AstPtr::new(&item)),
472 }); 482 }
483 .into(),
484 );
473 } 485 }
474 486
475 DefDiagnosticKind::UnresolvedImport { id, index } => { 487 DefDiagnosticKind::UnresolvedImport { id, index } => {
@@ -478,25 +490,30 @@ impl Module {
478 let import = &item_tree[id.value]; 490 let import = &item_tree[id.value];
479 491
480 let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); 492 let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
481 sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) }); 493 acc.push(
494 UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }
495 .into(),
496 );
482 } 497 }
483 498
484 DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { 499 DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
485 let item = ast.to_node(db.upcast()); 500 let item = ast.to_node(db.upcast());
486 sink.push(InactiveCode { 501 acc.push(
487 file: ast.file_id, 502 InactiveCode {
488 node: AstPtr::new(&item).into(), 503 node: ast.with_value(AstPtr::new(&item).into()),
489 cfg: cfg.clone(), 504 cfg: cfg.clone(),
490 opts: opts.clone(), 505 opts: opts.clone(),
491 }); 506 }
507 .into(),
508 );
492 } 509 }
493 510
494 DefDiagnosticKind::UnresolvedProcMacro { ast } => { 511 DefDiagnosticKind::UnresolvedProcMacro { ast } => {
495 let mut precise_location = None; 512 let mut precise_location = None;
496 let (file, ast, name) = match ast { 513 let (node, name) = match ast {
497 MacroCallKind::FnLike { ast_id, .. } => { 514 MacroCallKind::FnLike { ast_id, .. } => {
498 let node = ast_id.to_node(db.upcast()); 515 let node = ast_id.to_node(db.upcast());
499 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 516 (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
500 } 517 }
501 MacroCallKind::Derive { ast_id, derive_name, .. } => { 518 MacroCallKind::Derive { ast_id, derive_name, .. } => {
502 let node = ast_id.to_node(db.upcast()); 519 let node = ast_id.to_node(db.upcast());
@@ -529,71 +546,84 @@ impl Module {
529 } 546 }
530 547
531 ( 548 (
532 ast_id.file_id, 549 ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
533 SyntaxNodePtr::from(AstPtr::new(&node)),
534 Some(derive_name.clone()), 550 Some(derive_name.clone()),
535 ) 551 )
536 } 552 }
553 MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
554 let node = ast_id.to_node(db.upcast());
555 let attr =
556 node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else(
557 || panic!("cannot find attribute #{}", invoc_attr_index),
558 );
559 (
560 ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
561 Some(attr_name.clone()),
562 )
563 }
537 }; 564 };
538 sink.push(UnresolvedProcMacro { 565 acc.push(
539 file, 566 UnresolvedProcMacro { node, precise_location, macro_name: name }.into(),
540 node: ast, 567 );
541 precise_location,
542 macro_name: name,
543 });
544 } 568 }
545 569
546 DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { 570 DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
547 let node = ast.to_node(db.upcast()); 571 let node = ast.to_node(db.upcast());
548 sink.push(UnresolvedMacroCall { 572 acc.push(
549 file: ast.file_id, 573 UnresolvedMacroCall {
550 node: AstPtr::new(&node), 574 macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
551 path: path.clone(), 575 path: path.clone(),
552 }); 576 }
577 .into(),
578 );
553 } 579 }
554 580
555 DefDiagnosticKind::MacroError { ast, message } => { 581 DefDiagnosticKind::MacroError { ast, message } => {
556 let (file, ast) = match ast { 582 let node = match ast {
557 MacroCallKind::FnLike { ast_id, .. } => { 583 MacroCallKind::FnLike { ast_id, .. } => {
558 let node = ast_id.to_node(db.upcast()); 584 let node = ast_id.to_node(db.upcast());
559 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 585 ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
560 } 586 }
561 MacroCallKind::Derive { ast_id, .. } => { 587 MacroCallKind::Derive { ast_id, .. }
588 | MacroCallKind::Attr { ast_id, .. } => {
589 // FIXME: point to the attribute instead, this creates very large diagnostics
562 let node = ast_id.to_node(db.upcast()); 590 let node = ast_id.to_node(db.upcast());
563 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 591 ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
564 } 592 }
565 }; 593 };
566 sink.push(MacroError { file, node: ast, message: message.clone() }); 594 acc.push(MacroError { node, message: message.clone() }.into());
567 } 595 }
568 596
569 DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { 597 DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
570 let node = ast.to_node(db.upcast()); 598 let node = ast.to_node(db.upcast());
571 // Must have a name, otherwise we wouldn't emit it. 599 // Must have a name, otherwise we wouldn't emit it.
572 let name = node.name().expect("unimplemented builtin macro with no name"); 600 let name = node.name().expect("unimplemented builtin macro with no name");
573 let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); 601 acc.push(
574 sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr }); 602 UnimplementedBuiltinMacro {
603 node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
604 }
605 .into(),
606 );
575 } 607 }
576 } 608 }
577 } 609 }
578 for decl in self.declarations(db) { 610 for decl in self.declarations(db) {
579 match decl { 611 match decl {
580 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 612 ModuleDef::Function(f) => f.diagnostics(db, acc),
581 crate::ModuleDef::Module(m) => { 613 ModuleDef::Module(m) => {
582 // Only add diagnostics from inline modules 614 // Only add diagnostics from inline modules
583 if def_map[m.id.local_id].origin.is_inline() { 615 if def_map[m.id.local_id].origin.is_inline() {
584 m.diagnostics(db, sink) 616 m.diagnostics(db, acc)
585 } 617 }
586 } 618 }
587 _ => { 619 _ => acc.extend(decl.diagnostics(db)),
588 decl.diagnostics(db, sink);
589 }
590 } 620 }
591 } 621 }
592 622
593 for impl_def in self.impl_defs(db) { 623 for impl_def in self.impl_defs(db) {
594 for item in impl_def.items(db) { 624 for item in impl_def.items(db) {
595 if let AssocItem::Function(f) = item { 625 if let AssocItem::Function(f) = item {
596 f.diagnostics(db, sink); 626 f.diagnostics(db, acc);
597 } 627 }
598 } 628 }
599 } 629 }
@@ -995,41 +1025,191 @@ impl Function {
995 db.function_data(self.id).is_async() 1025 db.function_data(self.id).is_async()
996 } 1026 }
997 1027
998 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 1028 pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
999 let krate = self.module(db).id.krate(); 1029 let krate = self.module(db).id.krate();
1000 1030
1001 let source_map = db.body_with_source_map(self.id.into()).1; 1031 let source_map = db.body_with_source_map(self.id.into()).1;
1002 for diag in source_map.diagnostics() { 1032 for diag in source_map.diagnostics() {
1003 match diag { 1033 match diag {
1004 BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode { 1034 BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
1005 file: node.file_id, 1035 InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() }
1006 node: node.value.clone(), 1036 .into(),
1007 cfg: cfg.clone(), 1037 ),
1008 opts: opts.clone(), 1038 BodyDiagnostic::MacroError { node, message } => acc.push(
1009 }), 1039 MacroError {
1010 BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { 1040 node: node.clone().map(|it| it.into()),
1011 file: node.file_id, 1041 message: message.to_string(),
1012 node: node.value.clone().into(), 1042 }
1013 message: message.to_string(), 1043 .into(),
1014 }), 1044 ),
1015 BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro { 1045 BodyDiagnostic::UnresolvedProcMacro { node } => acc.push(
1016 file: node.file_id, 1046 UnresolvedProcMacro {
1017 node: node.value.clone().into(), 1047 node: node.clone().map(|it| it.into()),
1018 precise_location: None, 1048 precise_location: None,
1019 macro_name: None, 1049 macro_name: None,
1020 }), 1050 }
1021 BodyDiagnostic::UnresolvedMacroCall { node, path } => { 1051 .into(),
1022 sink.push(UnresolvedMacroCall { 1052 ),
1023 file: node.file_id, 1053 BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
1024 node: node.value.clone(), 1054 UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(),
1025 path: path.clone(), 1055 ),
1026 }) 1056 }
1057 }
1058
1059 let infer = db.infer(self.id.into());
1060 let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1);
1061 for d in &infer.diagnostics {
1062 match d {
1063 hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
1064 let field = source_map.field_syntax(*expr);
1065 acc.push(NoSuchField { field }.into())
1066 }
1067 hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
1068 let expr = source_map
1069 .expr_syntax(*expr)
1070 .expect("break outside of loop in synthetic syntax");
1071 acc.push(BreakOutsideOfLoop { expr }.into())
1072 }
1073 }
1074 }
1075
1076 for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) {
1077 match source_map.expr_syntax(expr) {
1078 Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
1079 Err(SyntheticSyntax) => {
1080 // FIXME: Here and eslwhere in this file, the `expr` was
1081 // desugared, report or assert that this doesn't happen.
1082 }
1083 }
1084 }
1085
1086 for diagnostic in BodyValidationDiagnostic::collect(db, self.id.into()) {
1087 match diagnostic {
1088 BodyValidationDiagnostic::RecordMissingFields {
1089 record,
1090 variant,
1091 missed_fields,
1092 } => {
1093 let variant_data = variant.variant_data(db.upcast());
1094 let missed_fields = missed_fields
1095 .into_iter()
1096 .map(|idx| variant_data.fields()[idx].name.clone())
1097 .collect();
1098
1099 match record {
1100 Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
1101 Ok(source_ptr) => {
1102 let root = source_ptr.file_syntax(db.upcast());
1103 if let ast::Expr::RecordExpr(record_expr) =
1104 &source_ptr.value.to_node(&root)
1105 {
1106 if let Some(_) = record_expr.record_expr_field_list() {
1107 acc.push(
1108 MissingFields {
1109 file: source_ptr.file_id,
1110 field_list_parent: Either::Left(AstPtr::new(
1111 record_expr,
1112 )),
1113 field_list_parent_path: record_expr
1114 .path()
1115 .map(|path| AstPtr::new(&path)),
1116 missed_fields,
1117 }
1118 .into(),
1119 )
1120 }
1121 }
1122 }
1123 Err(SyntheticSyntax) => (),
1124 },
1125 Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
1126 Ok(source_ptr) => {
1127 if let Some(expr) = source_ptr.value.as_ref().left() {
1128 let root = source_ptr.file_syntax(db.upcast());
1129 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
1130 if let Some(_) = record_pat.record_pat_field_list() {
1131 acc.push(
1132 MissingFields {
1133 file: source_ptr.file_id,
1134 field_list_parent: Either::Right(AstPtr::new(
1135 &record_pat,
1136 )),
1137 field_list_parent_path: record_pat
1138 .path()
1139 .map(|path| AstPtr::new(&path)),
1140 missed_fields,
1141 }
1142 .into(),
1143 )
1144 }
1145 }
1146 }
1147 }
1148 Err(SyntheticSyntax) => (),
1149 },
1150 }
1151 }
1152 BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
1153 if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
1154 acc.push(
1155 ReplaceFilterMapNextWithFindMap {
1156 file: next_source_ptr.file_id,
1157 next_expr: next_source_ptr.value,
1158 }
1159 .into(),
1160 );
1161 }
1162 }
1163 BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
1164 match source_map.expr_syntax(call_expr) {
1165 Ok(source_ptr) => acc.push(
1166 MismatchedArgCount { call_expr: source_ptr, expected, found }.into(),
1167 ),
1168 Err(SyntheticSyntax) => (),
1169 }
1170 }
1171 BodyValidationDiagnostic::RemoveThisSemicolon { expr } => {
1172 match source_map.expr_syntax(expr) {
1173 Ok(expr) => acc.push(RemoveThisSemicolon { expr }.into()),
1174 Err(SyntheticSyntax) => (),
1175 }
1176 }
1177 BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => {
1178 match source_map.expr_syntax(expr) {
1179 Ok(expr) => acc.push(MissingOkOrSomeInTailExpr { expr, required }.into()),
1180 Err(SyntheticSyntax) => (),
1181 }
1182 }
1183 BodyValidationDiagnostic::MissingMatchArms { match_expr } => {
1184 match source_map.expr_syntax(match_expr) {
1185 Ok(source_ptr) => {
1186 let root = source_ptr.file_syntax(db.upcast());
1187 if let ast::Expr::MatchExpr(match_expr) =
1188 &source_ptr.value.to_node(&root)
1189 {
1190 if let (Some(match_expr), Some(arms)) =
1191 (match_expr.expr(), match_expr.match_arm_list())
1192 {
1193 acc.push(
1194 MissingMatchArms {
1195 file: source_ptr.file_id,
1196 match_expr: AstPtr::new(&match_expr),
1197 arms: AstPtr::new(&arms),
1198 }
1199 .into(),
1200 )
1201 }
1202 }
1203 }
1204 Err(SyntheticSyntax) => (),
1205 }
1027 } 1206 }
1028 } 1207 }
1029 } 1208 }
1030 1209
1031 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 1210 for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
1032 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 1211 acc.push(diag.into())
1212 }
1033 } 1213 }
1034 1214
1035 /// Whether this function declaration has a definition. 1215 /// Whether this function declaration has a definition.
@@ -1331,6 +1511,7 @@ impl MacroDef {
1331 MacroDefKind::Declarative(_) => MacroKind::Declarative, 1511 MacroDefKind::Declarative(_) => MacroKind::Declarative,
1332 MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, 1512 MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn,
1333 MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, 1513 MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive,
1514 MacroDefKind::BuiltInAttr(_, _) => MacroKind::Attr,
1334 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { 1515 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => {
1335 MacroKind::Derive 1516 MacroKind::Derive
1336 } 1517 }
@@ -1338,6 +1519,13 @@ impl MacroDef {
1338 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, 1519 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro,
1339 } 1520 }
1340 } 1521 }
1522
1523 pub fn is_fn_like(&self) -> bool {
1524 match self.kind() {
1525 MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true,
1526 MacroKind::Attr | MacroKind::Derive => false,
1527 }
1528 }
1341} 1529}
1342 1530
1343/// Invariant: `inner.as_assoc_item(db).is_some()` 1531/// Invariant: `inner.as_assoc_item(db).is_some()`
@@ -1429,6 +1617,20 @@ impl AssocItem {
1429 _ => None, 1617 _ => None,
1430 } 1618 }
1431 } 1619 }
1620
1621 pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1622 match self.container(db) {
1623 AssocItemContainer::Impl(i) => i.trait_(db),
1624 _ => None,
1625 }
1626 }
1627
1628 pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1629 match self.container(db) {
1630 AssocItemContainer::Trait(t) => Some(t),
1631 AssocItemContainer::Impl(i) => i.trait_(db),
1632 }
1633 }
1432} 1634}
1433 1635
1434impl HasVisibility for AssocItem { 1636impl HasVisibility for AssocItem {
@@ -1726,7 +1928,7 @@ impl Impl {
1726 } 1928 }
1727 1929
1728 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { 1930 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> {
1729 let def_crates = match def_crates(db, &ty, krate) { 1931 let def_crates = match method_resolution::def_crates(db, &ty, krate) {
1730 Some(def_crates) => def_crates, 1932 Some(def_crates) => def_crates,
1731 None => return Vec::new(), 1933 None => return Vec::new(),
1732 }; 1934 };
@@ -1783,9 +1985,11 @@ impl Impl {
1783 } 1985 }
1784 1986
1785 // FIXME: the return type is wrong. This should be a hir version of 1987 // FIXME: the return type is wrong. This should be a hir version of
1786 // `TraitRef` (ie, resolved `TypeRef`). 1988 // `TraitRef` (to account for parameters and qualifiers)
1787 pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { 1989 pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
1788 db.impl_data(self.id).target_trait.as_deref().cloned() 1990 let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
1991 let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
1992 Some(Trait { id })
1789 } 1993 }
1790 1994
1791 pub fn self_ty(self, db: &dyn HirDatabase) -> Type { 1995 pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
@@ -2130,7 +2334,7 @@ impl Type {
2130 krate: Crate, 2334 krate: Crate,
2131 mut callback: impl FnMut(AssocItem) -> Option<T>, 2335 mut callback: impl FnMut(AssocItem) -> Option<T>,
2132 ) -> Option<T> { 2336 ) -> Option<T> {
2133 for krate in def_crates(db, &self.ty, krate.id)? { 2337 for krate in method_resolution::def_crates(db, &self.ty, krate.id)? {
2134 let impls = db.inherent_impls_in_crate(krate); 2338 let impls = db.inherent_impls_in_crate(krate);
2135 2339
2136 for impl_def in impls.for_self_ty(&self.ty) { 2340 for impl_def in impls.for_self_ty(&self.ty) {
@@ -2162,6 +2366,7 @@ impl Type {
2162 name: Option<&Name>, 2366 name: Option<&Name>,
2163 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 2367 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
2164 ) -> Option<T> { 2368 ) -> Option<T> {
2369 let _p = profile::span("iterate_method_candidates");
2165 // There should be no inference vars in types passed here 2370 // There should be no inference vars in types passed here
2166 // FIXME check that? 2371 // FIXME check that?
2167 // FIXME replace Unknown by bound vars here 2372 // FIXME replace Unknown by bound vars here
@@ -2195,6 +2400,7 @@ impl Type {
2195 name: Option<&Name>, 2400 name: Option<&Name>,
2196 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, 2401 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
2197 ) -> Option<T> { 2402 ) -> Option<T> {
2403 let _p = profile::span("iterate_path_candidates");
2198 let canonical = hir_ty::replace_errors_with_variables(&self.ty); 2404 let canonical = hir_ty::replace_errors_with_variables(&self.ty);
2199 2405
2200 let env = self.env.clone(); 2406 let env = self.env.clone();
@@ -2232,6 +2438,7 @@ impl Type {
2232 &'a self, 2438 &'a self,
2233 db: &'a dyn HirDatabase, 2439 db: &'a dyn HirDatabase,
2234 ) -> impl Iterator<Item = Trait> + 'a { 2440 ) -> impl Iterator<Item = Trait> + 'a {
2441 let _p = profile::span("applicable_inherent_traits");
2235 self.autoderef(db) 2442 self.autoderef(db)
2236 .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) 2443 .filter_map(|derefed_type| derefed_type.ty.dyn_trait())
2237 .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) 2444 .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
@@ -2304,13 +2511,13 @@ impl Type {
2304 match ty.kind(&Interner) { 2511 match ty.kind(&Interner) {
2305 TyKind::Adt(_, substs) => { 2512 TyKind::Adt(_, substs) => {
2306 cb(type_.derived(ty.clone())); 2513 cb(type_.derived(ty.clone()));
2307 walk_substs(db, type_, &substs, cb); 2514 walk_substs(db, type_, substs, cb);
2308 } 2515 }
2309 TyKind::AssociatedType(_, substs) => { 2516 TyKind::AssociatedType(_, substs) => {
2310 if let Some(_) = ty.associated_type_parent_trait(db) { 2517 if let Some(_) = ty.associated_type_parent_trait(db) {
2311 cb(type_.derived(ty.clone())); 2518 cb(type_.derived(ty.clone()));
2312 } 2519 }
2313 walk_substs(db, type_, &substs, cb); 2520 walk_substs(db, type_, substs, cb);
2314 } 2521 }
2315 TyKind::OpaqueType(_, subst) => { 2522 TyKind::OpaqueType(_, subst) => {
2316 if let Some(bounds) = ty.impl_trait_bounds(db) { 2523 if let Some(bounds) = ty.impl_trait_bounds(db) {
@@ -2350,7 +2557,7 @@ impl Type {
2350 TyKind::FnDef(_, substs) 2557 TyKind::FnDef(_, substs)
2351 | TyKind::Tuple(_, substs) 2558 | TyKind::Tuple(_, substs)
2352 | TyKind::Closure(.., substs) => { 2559 | TyKind::Closure(.., substs) => {
2353 walk_substs(db, type_, &substs, cb); 2560 walk_substs(db, type_, substs, cb);
2354 } 2561 }
2355 TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { 2562 TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
2356 walk_substs(db, type_, &substitution.0, cb); 2563 walk_substs(db, type_, &substitution.0, cb);
@@ -2481,6 +2688,18 @@ impl ScopeDef {
2481 2688
2482 items 2689 items
2483 } 2690 }
2691
2692 pub fn is_value_def(&self) -> bool {
2693 matches!(
2694 self,
2695 ScopeDef::ModuleDef(ModuleDef::Function(_))
2696 | ScopeDef::ModuleDef(ModuleDef::Variant(_))
2697 | ScopeDef::ModuleDef(ModuleDef::Const(_))
2698 | ScopeDef::ModuleDef(ModuleDef::Static(_))
2699 | ScopeDef::GenericParam(GenericParam::ConstParam(_))
2700 | ScopeDef::Local(_)
2701 )
2702 }
2484} 2703}
2485 2704
2486impl From<ItemInNs> for ScopeDef { 2705impl From<ItemInNs> for ScopeDef {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c7f2c02e4..613266e07 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -17,7 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
17use syntax::{ 17use syntax::{
18 algo::find_node_at_offset, 18 algo::find_node_at_offset,
19 ast::{self, GenericParamsOwner, LoopBodyOwner}, 19 ast::{self, GenericParamsOwner, LoopBodyOwner},
20 match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize, 20 match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
21}; 21};
22 22
23use crate::{ 23use crate::{
@@ -35,8 +35,9 @@ pub enum PathResolution {
35 Def(ModuleDef), 35 Def(ModuleDef),
36 /// A local binding (only value namespace) 36 /// A local binding (only value namespace)
37 Local(Local), 37 Local(Local),
38 /// A generic parameter 38 /// A type parameter
39 TypeParam(TypeParam), 39 TypeParam(TypeParam),
40 /// A const parameter
40 ConstParam(ConstParam), 41 ConstParam(ConstParam),
41 SelfType(Impl), 42 SelfType(Impl),
42 Macro(MacroDef), 43 Macro(MacroDef),
@@ -117,6 +118,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
117 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 118 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
118 self.imp.expand(macro_call) 119 self.imp.expand(macro_call)
119 } 120 }
121
122 /// If `item` has an attribute macro attached to it, expands it.
123 pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
124 self.imp.expand_attr_macro(item)
125 }
126
127 pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
128 self.imp.is_attr_macro_call(item)
129 }
130
120 pub fn speculative_expand( 131 pub fn speculative_expand(
121 &self, 132 &self,
122 actual_macro_call: &ast::MacroCall, 133 actual_macro_call: &ast::MacroCall,
@@ -181,7 +192,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
181 node: &SyntaxNode, 192 node: &SyntaxNode,
182 offset: TextSize, 193 offset: TextSize,
183 ) -> Option<N> { 194 ) -> Option<N> {
184 if let Some(it) = find_node_at_offset(&node, offset) { 195 if let Some(it) = find_node_at_offset(node, offset) {
185 return Some(it); 196 return Some(it);
186 } 197 }
187 198
@@ -332,6 +343,22 @@ impl<'db> SemanticsImpl<'db> {
332 Some(node) 343 Some(node)
333 } 344 }
334 345
346 fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
347 let sa = self.analyze(item.syntax());
348 let src = InFile::new(sa.file_id, item.clone());
349 let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
350 let file_id = macro_call_id.as_file();
351 let node = self.db.parse_or_expand(file_id)?;
352 self.cache(node.clone(), file_id);
353 Some(node)
354 }
355
356 fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
357 let sa = self.analyze(item.syntax());
358 let src = InFile::new(sa.file_id, item.clone());
359 self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
360 }
361
335 fn speculative_expand( 362 fn speculative_expand(
336 &self, 363 &self,
337 actual_macro_call: &ast::MacroCall, 364 actual_macro_call: &ast::MacroCall,
@@ -362,25 +389,65 @@ impl<'db> SemanticsImpl<'db> {
362 389
363 let token = successors(Some(InFile::new(sa.file_id, token)), |token| { 390 let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
364 self.db.unwind_if_cancelled(); 391 self.db.unwind_if_cancelled();
365 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 392
366 let tt = macro_call.token_tree()?; 393 for node in token.value.ancestors() {
367 if !tt.syntax().text_range().contains_range(token.value.text_range()) { 394 match_ast! {
368 return None; 395 match node {
369 } 396 ast::MacroCall(macro_call) => {
370 let file_id = sa.expand(self.db, token.with_value(&macro_call))?; 397 let tt = macro_call.token_tree()?;
371 let token = self 398 let l_delim = match tt.left_delimiter_token() {
372 .expansion_info_cache 399 Some(it) => it.text_range().end(),
373 .borrow_mut() 400 None => tt.syntax().text_range().start()
374 .entry(file_id) 401 };
375 .or_insert_with(|| file_id.expansion_info(self.db.upcast())) 402 let r_delim = match tt.right_delimiter_token() {
376 .as_ref()? 403 Some(it) => it.text_range().start(),
377 .map_token_down(token.as_ref())?; 404 None => tt.syntax().text_range().end()
378 405 };
379 if let Some(parent) = token.value.parent() { 406 if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) {
380 self.cache(find_root(&parent), token.file_id); 407 return None;
408 }
409 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
410 let token = self
411 .expansion_info_cache
412 .borrow_mut()
413 .entry(file_id)
414 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
415 .as_ref()?
416 .map_token_down(token.as_ref())?;
417
418 if let Some(parent) = token.value.parent() {
419 self.cache(find_root(&parent), token.file_id);
420 }
421
422 return Some(token);
423 },
424 ast::Item(item) => {
425 match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) {
426 Some(call_id) => {
427 let file_id = call_id.as_file();
428 let token = self
429 .expansion_info_cache
430 .borrow_mut()
431 .entry(file_id)
432 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
433 .as_ref()?
434 .map_token_down(token.as_ref())?;
435
436 if let Some(parent) = token.value.parent() {
437 self.cache(find_root(&parent), token.file_id);
438 }
439
440 return Some(token);
441 }
442 None => {}
443 }
444 },
445 _ => {}
446 }
447 }
381 } 448 }
382 449
383 Some(token) 450 None
384 }) 451 })
385 .last() 452 .last()
386 .unwrap(); 453 .unwrap();
@@ -677,7 +744,7 @@ impl<'db> SemanticsImpl<'db> {
677 return None; 744 return None;
678 } 745 }
679 746
680 let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; 747 let func = self.resolve_method_call(method_call_expr).map(Function::from)?;
681 let res = match func.self_param(self.db)?.access(self.db) { 748 let res = match func.self_param(self.db)?.access(self.db) {
682 Access::Shared | Access::Exclusive => true, 749 Access::Shared | Access::Exclusive => true,
683 Access::Owned => false, 750 Access::Owned => false,
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 9a5a2255f..e8c2ed48e 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, 10 ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
11 UnionId, VariantId, 11 UnionId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, AstId, MacroDefKind}; 13use hir_expand::{name::AsName, AstId, MacroCallId, MacroDefKind};
14use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
15use smallvec::SmallVec; 15use smallvec::SmallVec;
16use stdx::impl_from; 16use stdx::impl_from;
@@ -145,16 +145,25 @@ impl SourceToDefCtx<'_, '_> {
145 Some((container, label_id)) 145 Some((container, label_id))
146 } 146 }
147 147
148 pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> {
149 let map = self.dyn_map(src.as_ref())?;
150 map[keys::ATTR_MACRO].get(&src).copied()
151 }
152
148 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( 153 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
149 &mut self, 154 &mut self,
150 src: InFile<Ast>, 155 src: InFile<Ast>,
151 key: Key<Ast, ID>, 156 key: Key<Ast, ID>,
152 ) -> Option<ID> { 157 ) -> Option<ID> {
153 let container = self.find_container(src.as_ref().map(|it| it.syntax()))?; 158 self.dyn_map(src.as_ref())?[key].get(&src).copied()
159 }
160
161 fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> {
162 let container = self.find_container(src.map(|it| it.syntax()))?;
154 let db = self.db; 163 let db = self.db;
155 let dyn_map = 164 let dyn_map =
156 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); 165 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
157 dyn_map[key].get(&src).copied() 166 Some(dyn_map)
158 } 167 }
159 168
160 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { 169 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
@@ -202,62 +211,68 @@ impl SourceToDefCtx<'_, '_> {
202 211
203 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { 212 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
204 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 213 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
205 let res: ChildContainer = match_ast! { 214 if let Some(res) = self.container_to_def(container) {
206 match (container.value) { 215 return Some(res);
207 ast::Module(it) => { 216 }
208 let def = self.module_to_def(container.with_value(it))?;
209 def.into()
210 },
211 ast::Trait(it) => {
212 let def = self.trait_to_def(container.with_value(it))?;
213 def.into()
214 },
215 ast::Impl(it) => {
216 let def = self.impl_to_def(container.with_value(it))?;
217 def.into()
218 },
219 ast::Fn(it) => {
220 let def = self.fn_to_def(container.with_value(it))?;
221 DefWithBodyId::from(def).into()
222 },
223 ast::Struct(it) => {
224 let def = self.struct_to_def(container.with_value(it))?;
225 VariantId::from(def).into()
226 },
227 ast::Enum(it) => {
228 let def = self.enum_to_def(container.with_value(it))?;
229 def.into()
230 },
231 ast::Union(it) => {
232 let def = self.union_to_def(container.with_value(it))?;
233 VariantId::from(def).into()
234 },
235 ast::Static(it) => {
236 let def = self.static_to_def(container.with_value(it))?;
237 DefWithBodyId::from(def).into()
238 },
239 ast::Const(it) => {
240 let def = self.const_to_def(container.with_value(it))?;
241 DefWithBodyId::from(def).into()
242 },
243 ast::TypeAlias(it) => {
244 let def = self.type_alias_to_def(container.with_value(it))?;
245 def.into()
246 },
247 ast::Variant(it) => {
248 let def = self.enum_variant_to_def(container.with_value(it))?;
249 VariantId::from(def).into()
250 },
251 _ => continue,
252 }
253 };
254 return Some(res);
255 } 217 }
256 218
257 let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; 219 let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?;
258 Some(def.into()) 220 Some(def.into())
259 } 221 }
260 222
223 fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> {
224 let cont = match_ast! {
225 match (container.value) {
226 ast::Module(it) => {
227 let def = self.module_to_def(container.with_value(it))?;
228 def.into()
229 },
230 ast::Trait(it) => {
231 let def = self.trait_to_def(container.with_value(it))?;
232 def.into()
233 },
234 ast::Impl(it) => {
235 let def = self.impl_to_def(container.with_value(it))?;
236 def.into()
237 },
238 ast::Fn(it) => {
239 let def = self.fn_to_def(container.with_value(it))?;
240 DefWithBodyId::from(def).into()
241 },
242 ast::Struct(it) => {
243 let def = self.struct_to_def(container.with_value(it))?;
244 VariantId::from(def).into()
245 },
246 ast::Enum(it) => {
247 let def = self.enum_to_def(container.with_value(it))?;
248 def.into()
249 },
250 ast::Union(it) => {
251 let def = self.union_to_def(container.with_value(it))?;
252 VariantId::from(def).into()
253 },
254 ast::Static(it) => {
255 let def = self.static_to_def(container.with_value(it))?;
256 DefWithBodyId::from(def).into()
257 },
258 ast::Const(it) => {
259 let def = self.const_to_def(container.with_value(it))?;
260 DefWithBodyId::from(def).into()
261 },
262 ast::TypeAlias(it) => {
263 let def = self.type_alias_to_def(container.with_value(it))?;
264 def.into()
265 },
266 ast::Variant(it) => {
267 let def = self.enum_variant_to_def(container.with_value(it))?;
268 VariantId::from(def).into()
269 },
270 _ => return None,
271 }
272 };
273 Some(cont)
274 }
275
261 fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { 276 fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
262 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 277 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
263 let res: GenericDefId = match_ast! { 278 let res: GenericDefId = match_ast! {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 37a050415..c9744d81d 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -222,7 +222,7 @@ impl SourceAnalyzer {
222 Pat::Path(path) => path, 222 Pat::Path(path) => path,
223 _ => return None, 223 _ => return None,
224 }; 224 };
225 let res = resolve_hir_path(db, &self.resolver, &path)?; 225 let res = resolve_hir_path(db, &self.resolver, path)?;
226 match res { 226 match res {
227 PathResolution::Def(def) => Some(def), 227 PathResolution::Def(def) => Some(def),
228 _ => None, 228 _ => None,
@@ -329,7 +329,7 @@ impl SourceAnalyzer {
329 329
330 let (variant, missing_fields, _exhaustive) = 330 let (variant, missing_fields, _exhaustive) =
331 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; 331 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
332 let res = self.missing_fields(db, krate, &substs, variant, missing_fields); 332 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
333 Some(res) 333 Some(res)
334 } 334 }
335 335
@@ -347,7 +347,7 @@ impl SourceAnalyzer {
347 347
348 let (variant, missing_fields, _exhaustive) = 348 let (variant, missing_fields, _exhaustive) =
349 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; 349 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
350 let res = self.missing_fields(db, krate, &substs, variant, missing_fields); 350 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
351 Some(res) 351 Some(res)
352 } 352 }
353 353
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 43324d8d9..bb86f6a73 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14dashmap = { version = "4.0.2", features = ["raw-api"] } 14dashmap = { version = "4.0.2", features = ["raw-api"] }
15log = "0.4.8" 15log = "0.4.8"
16once_cell = "1.3.1" 16once_cell = "1.3.1"
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 385ba8c80..d07adb084 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -36,6 +36,10 @@ use crate::{
36pub struct Documentation(String); 36pub struct Documentation(String);
37 37
38impl Documentation { 38impl Documentation {
39 pub fn new(s: String) -> Self {
40 Documentation(s)
41 }
42
39 pub fn as_str(&self) -> &str { 43 pub fn as_str(&self) -> &str {
40 &self.0 44 &self.0
41 } 45 }
@@ -102,7 +106,9 @@ impl RawAttrs {
102 ) -> Self { 106 ) -> Self {
103 let entries = collect_attrs(owner) 107 let entries = collect_attrs(owner)
104 .flat_map(|(id, attr)| match attr { 108 .flat_map(|(id, attr)| match attr {
105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 109 Either::Left(attr) => {
110 attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id))
111 }
106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 112 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
107 id, 113 id,
108 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), 114 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
@@ -168,10 +174,9 @@ impl RawAttrs {
168 let index = attr.id; 174 let index = attr.id;
169 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 175 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
170 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 176 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
171 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
172 // FIXME hygiene 177 // FIXME hygiene
173 let hygiene = Hygiene::new_unhygienic(); 178 let hygiene = Hygiene::new_unhygienic();
174 Attr::from_src(db, attr, &hygiene, index) 179 Attr::from_tt(db, &tree, &hygiene, index)
175 }); 180 });
176 181
177 let cfg_options = &crate_graph[krate].cfg_options; 182 let cfg_options = &crate_graph[krate].cfg_options;
@@ -578,13 +583,13 @@ impl AttrSourceMap {
578 .get(id.ast_index as usize) 583 .get(id.ast_index as usize)
579 .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) 584 .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id))
580 .clone() 585 .clone()
581 .map(|attr| Either::Right(attr)) 586 .map(Either::Right)
582 } else { 587 } else {
583 self.attrs 588 self.attrs
584 .get(id.ast_index as usize) 589 .get(id.ast_index as usize)
585 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) 590 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id))
586 .clone() 591 .clone()
587 .map(|attr| Either::Left(attr)) 592 .map(Either::Left)
588 } 593 }
589 } 594 }
590} 595}
@@ -601,7 +606,7 @@ pub struct DocsRangeMap {
601impl DocsRangeMap { 606impl DocsRangeMap {
602 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { 607 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
603 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; 608 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
604 let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); 609 let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
605 if !line_docs_range.contains_range(range) { 610 if !line_docs_range.contains_range(range) {
606 return None; 611 return None;
607 } 612 }
@@ -660,7 +665,7 @@ impl fmt::Display for AttrInput {
660impl Attr { 665impl Attr {
661 fn from_src( 666 fn from_src(
662 db: &dyn DefDatabase, 667 db: &dyn DefDatabase,
663 ast: ast::Attr, 668 ast: ast::Meta,
664 hygiene: &Hygiene, 669 hygiene: &Hygiene,
665 id: AttrId, 670 id: AttrId,
666 ) -> Option<Attr> { 671 ) -> Option<Attr> {
@@ -679,6 +684,19 @@ impl Attr {
679 Some(Attr { id, path, input }) 684 Some(Attr { id, path, input })
680 } 685 }
681 686
687 fn from_tt(
688 db: &dyn DefDatabase,
689 tt: &tt::Subtree,
690 hygiene: &Hygiene,
691 id: AttrId,
692 ) -> Option<Attr> {
693 let (parse, _) =
694 mbe::token_tree_to_syntax_node(tt, hir_expand::FragmentKind::MetaItem).ok()?;
695 let ast = ast::Meta::cast(parse.syntax_node())?;
696
697 Self::from_src(db, ast, hygiene, id)
698 }
699
682 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 700 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
683 /// to derive macros. 701 /// to derive macros.
684 /// 702 ///
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index da1fdac33..bed4c4994 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1000,18 +1000,18 @@ impl From<ast::LiteralKind> for Literal {
1000 // FIXME: these should have actual values filled in, but unsure on perf impact 1000 // FIXME: these should have actual values filled in, but unsure on perf impact
1001 LiteralKind::IntNumber(lit) => { 1001 LiteralKind::IntNumber(lit) => {
1002 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { 1002 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
1003 return Literal::Float(Default::default(), builtin); 1003 Literal::Float(Default::default(), builtin)
1004 } else if let builtin @ Some(_) = 1004 } else if let builtin @ Some(_) =
1005 lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it)) 1005 lit.suffix().and_then(|it| BuiltinInt::from_suffix(it))
1006 { 1006 {
1007 Literal::Int(lit.value().unwrap_or(0) as i128, builtin) 1007 Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1008 } else { 1008 } else {
1009 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it)); 1009 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it));
1010 Literal::Uint(lit.value().unwrap_or(0), builtin) 1010 Literal::Uint(lit.value().unwrap_or(0), builtin)
1011 } 1011 }
1012 } 1012 }
1013 LiteralKind::FloatNumber(lit) => { 1013 LiteralKind::FloatNumber(lit) => {
1014 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); 1014 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it));
1015 Literal::Float(Default::default(), ty) 1015 Literal::Float(Default::default(), ty)
1016 } 1016 }
1017 LiteralKind::ByteString(bs) => { 1017 LiteralKind::ByteString(bs) => {
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs
index 6764de3a7..58a1fc81c 100644
--- a/crates/hir_def/src/body/scope.rs
+++ b/crates/hir_def/src/body/scope.rs
@@ -198,7 +198,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
198 } 198 }
199 Expr::Lambda { args, body: body_expr, .. } => { 199 Expr::Lambda { args, body: body_expr, .. } => {
200 let scope = scopes.new_scope(scope); 200 let scope = scopes.new_scope(scope);
201 scopes.add_params_bindings(body, scope, &args); 201 scopes.add_params_bindings(body, scope, args);
202 compute_expr_scopes(*body_expr, body, scopes, scope); 202 compute_expr_scopes(*body_expr, body, scopes, scope);
203 } 203 }
204 Expr::Match { expr, arms } => { 204 Expr::Match { expr, arms } => {
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index d4fae05a6..27d837d47 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -3,7 +3,7 @@ mod block;
3use base_db::{fixture::WithFixture, SourceDatabase}; 3use base_db::{fixture::WithFixture, SourceDatabase};
4use expect_test::Expect; 4use expect_test::Expect;
5 5
6use crate::{test_db::TestDB, ModuleDefId}; 6use crate::ModuleDefId;
7 7
8use super::*; 8use super::*;
9 9
@@ -28,11 +28,6 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
28 db.body(fn_def.unwrap().into()) 28 db.body(fn_def.unwrap().into())
29} 29}
30 30
31fn check_diagnostics(ra_fixture: &str) {
32 let db: TestDB = TestDB::with_files(ra_fixture);
33 db.check_diagnostics();
34}
35
36fn block_def_map_at(ra_fixture: &str) -> String { 31fn block_def_map_at(ra_fixture: &str) -> String {
37 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); 32 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
38 33
@@ -57,7 +52,7 @@ fn check_at(ra_fixture: &str, expect: Expect) {
57fn your_stack_belongs_to_me() { 52fn your_stack_belongs_to_me() {
58 cov_mark::check!(your_stack_belongs_to_me); 53 cov_mark::check!(your_stack_belongs_to_me);
59 lower( 54 lower(
60 " 55 r#"
61macro_rules! n_nuple { 56macro_rules! n_nuple {
62 ($e:tt) => (); 57 ($e:tt) => ();
63 ($($rest:tt)*) => {{ 58 ($($rest:tt)*) => {{
@@ -65,7 +60,7 @@ macro_rules! n_nuple {
65 }}; 60 }};
66} 61}
67fn main() { n_nuple!(1,2,3); } 62fn main() { n_nuple!(1,2,3); }
68", 63"#,
69 ); 64 );
70} 65}
71 66
@@ -73,7 +68,7 @@ fn main() { n_nuple!(1,2,3); }
73fn macro_resolve() { 68fn macro_resolve() {
74 // Regression test for a path resolution bug introduced with inner item handling. 69 // Regression test for a path resolution bug introduced with inner item handling.
75 lower( 70 lower(
76 r" 71 r#"
77macro_rules! vec { 72macro_rules! vec {
78 () => { () }; 73 () => { () };
79 ($elem:expr; $n:expr) => { () }; 74 ($elem:expr; $n:expr) => { () };
@@ -84,140 +79,6 @@ mod m {
84 let _ = vec![FileSet::default(); self.len()]; 79 let _ = vec![FileSet::default(); self.len()];
85 } 80 }
86} 81}
87 ", 82"#,
88 );
89}
90
91#[test]
92fn cfg_diagnostics() {
93 check_diagnostics(
94 r"
95fn f() {
96 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
97
98 #[cfg(a)] fn f() {} // Item statement
99 //^^^^^^^^^^^^^^^^^^^ InactiveCode
100 #[cfg(a)] {} // Expression statement
101 //^^^^^^^^^^^^ InactiveCode
102 #[cfg(a)] let x = 0; // let statement
103 //^^^^^^^^^^^^^^^^^^^^ InactiveCode
104
105 abc(#[cfg(a)] 0);
106 //^^^^^^^^^^^ InactiveCode
107 let x = Struct {
108 #[cfg(a)] f: 0,
109 //^^^^^^^^^^^^^^ InactiveCode
110 };
111 match () {
112 () => (),
113 #[cfg(a)] () => (),
114 //^^^^^^^^^^^^^^^^^^ InactiveCode
115 }
116
117 #[cfg(a)] 0 // Trailing expression of block
118 //^^^^^^^^^^^ InactiveCode
119}
120 ",
121 );
122}
123
124#[test]
125fn macro_diag_builtin() {
126 check_diagnostics(
127 r#"
128#[rustc_builtin_macro]
129macro_rules! env {}
130
131#[rustc_builtin_macro]
132macro_rules! include {}
133
134#[rustc_builtin_macro]
135macro_rules! compile_error {}
136
137#[rustc_builtin_macro]
138macro_rules! format_args {
139 () => {}
140}
141
142fn f() {
143 // Test a handful of built-in (eager) macros:
144
145 include!(invalid);
146 //^^^^^^^^^^^^^^^^^ could not convert tokens
147 include!("does not exist");
148 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
149
150 env!(invalid);
151 //^^^^^^^^^^^^^ could not convert tokens
152
153 env!("OUT_DIR");
154 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
155
156 compile_error!("compile_error works");
157 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
158
159 // Lazy:
160
161 format_args!();
162 //^^^^^^^^^^^^^^ no rule matches input tokens
163}
164 "#,
165 );
166}
167
168#[test]
169fn macro_rules_diag() {
170 check_diagnostics(
171 r#"
172macro_rules! m {
173 () => {};
174}
175fn f() {
176 m!();
177
178 m!(hi);
179 //^^^^^^ leftover tokens
180}
181 "#,
182 ); 83 );
183} 84}
184
185#[test]
186fn unresolved_macro_diag() {
187 check_diagnostics(
188 r#"
189fn f() {
190 m!();
191 //^^^^ UnresolvedMacroCall
192}
193 "#,
194 );
195}
196
197#[test]
198fn dollar_crate_in_builtin_macro() {
199 check_diagnostics(
200 r#"
201#[macro_export]
202#[rustc_builtin_macro]
203macro_rules! format_args {}
204
205#[macro_export]
206macro_rules! arg {
207 () => {}
208}
209
210#[macro_export]
211macro_rules! outer {
212 () => {
213 $crate::format_args!( "", $crate::arg!(1) )
214 };
215}
216
217fn f() {
218 outer!();
219 //^^^^^^^^ leftover tokens
220}
221 "#,
222 )
223}
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index bc3d0f138..15c10d053 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -163,14 +163,14 @@ fn legacy_macro_items() {
163 // correctly. 163 // correctly.
164 check_at( 164 check_at(
165 r#" 165 r#"
166macro_rules! hit { 166macro_rules! mark {
167 () => { 167 () => {
168 struct Hit {} 168 struct Hit {}
169 } 169 }
170} 170}
171 171
172fn f() { 172fn f() {
173 hit!(); 173 mark!();
174 $0 174 $0
175} 175}
176"#, 176"#,
@@ -193,20 +193,20 @@ use core::cov_mark;
193 193
194fn f() { 194fn f() {
195 fn nested() { 195 fn nested() {
196 cov_mark::hit!(Hit); 196 cov_mark::mark!(Hit);
197 $0 197 $0
198 } 198 }
199} 199}
200//- /core.rs crate:core 200//- /core.rs crate:core
201pub mod cov_mark { 201pub mod cov_mark {
202 #[macro_export] 202 #[macro_export]
203 macro_rules! _hit { 203 macro_rules! _mark {
204 ($name:ident) => { 204 ($name:ident) => {
205 struct $name {} 205 struct $name {}
206 } 206 }
207 } 207 }
208 208
209 pub use crate::_hit as hit; 209 pub use crate::_mark as mark;
210} 210}
211"#, 211"#,
212 expect![[r#" 212 expect![[r#"
diff --git a/crates/hir_def/src/builtin_attr.rs b/crates/hir_def/src/builtin_attr.rs
index d5d7f0f47..39c7f84f7 100644
--- a/crates/hir_def/src/builtin_attr.rs
+++ b/crates/hir_def/src/builtin_attr.rs
@@ -2,7 +2,7 @@
2//! 2//!
3//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. 3//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`.
4//! 4//!
5//! It was last synchronized with upstream commit 2225ee1b62ff089917434aefd9b2bf509cfa087f. 5//! It was last synchronized with upstream commit 835150e70288535bc57bb624792229b9dc94991d.
6//! 6//!
7//! The macros were adjusted to only expand to the attribute name, since that is all we need to do 7//! The macros were adjusted to only expand to the attribute name, since that is all we need to do
8//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to 8//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
@@ -58,7 +58,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
58 ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), 58 ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
59 59
60 // Macros: 60 // Macros:
61 ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
62 ungated!(automatically_derived, Normal, template!(Word)), 61 ungated!(automatically_derived, Normal, template!(Word)),
63 // FIXME(#14407) 62 // FIXME(#14407)
64 ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), 63 ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
@@ -98,8 +97,8 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
98 template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), 97 template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
99 ), 98 ),
100 ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), 99 ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")),
101 ungated!(no_link, Normal, template!(Word)), 100 ungated!(no_link, AssumedUsed, template!(Word)),
102 ungated!(repr, Normal, template!(List: "C")), 101 ungated!(repr, AssumedUsed, template!(List: "C")),
103 ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), 102 ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")),
104 ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), 103 ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")),
105 ungated!(no_mangle, AssumedUsed, template!(Word)), 104 ungated!(no_mangle, AssumedUsed, template!(Word)),
@@ -112,6 +111,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
112 const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, 111 const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
113 experimental!(const_eval_limit) 112 experimental!(const_eval_limit)
114 ), 113 ),
114 gated!(
115 move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments,
116 experimental!(move_size_limit)
117 ),
115 118
116 // Entry point: 119 // Entry point:
117 ungated!(main, Normal, template!(Word)), 120 ungated!(main, Normal, template!(Word)),
@@ -140,6 +143,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
140 template!(List: "address, memory, thread"), 143 template!(List: "address, memory, thread"),
141 experimental!(no_sanitize) 144 experimental!(no_sanitize)
142 ), 145 ),
146 gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
143 147
144 // FIXME: #14408 assume docs are used since rustdoc looks at them. 148 // FIXME: #14408 assume docs are used since rustdoc looks at them.
145 ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), 149 ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
@@ -151,11 +155,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
151 // Linking: 155 // Linking:
152 gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), 156 gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)),
153 gated!( 157 gated!(
154 link_args, Normal, template!(NameValueStr: "args"),
155 "the `link_args` attribute is experimental and not portable across platforms, \
156 it is recommended to use `#[link(name = \"foo\")] instead",
157 ),
158 gated!(
159 link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, 158 link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib,
160 experimental!(link_ordinal) 159 experimental!(link_ordinal)
161 ), 160 ),
@@ -172,7 +171,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
172 "custom test frameworks are an unstable feature", 171 "custom test frameworks are an unstable feature",
173 ), 172 ),
174 // RFC #1268 173 // RFC #1268
175 gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), 174 gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)),
176 gated!( 175 gated!(
177 thread_local, AssumedUsed, template!(Word), 176 thread_local, AssumedUsed, template!(Word),
178 "`#[thread_local]` is an experimental feature, and does not currently handle destructors", 177 "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
@@ -291,7 +290,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
291 // Internal attributes, Macro related: 290 // Internal attributes, Macro related:
292 // ========================================================================== 291 // ==========================================================================
293 292
294 rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word), IMPL_DETAIL), 293 rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL),
295 rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), 294 rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
296 rustc_attr!( 295 rustc_attr!(
297 rustc_macro_transparency, AssumedUsed, 296 rustc_macro_transparency, AssumedUsed,
@@ -319,7 +318,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
319 // ========================================================================== 318 // ==========================================================================
320 319
321 rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), 320 rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
322 rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), 321 rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
323 322
324 // ========================================================================== 323 // ==========================================================================
325 // Internal attributes, Layout related: 324 // Internal attributes, Layout related:
@@ -380,6 +379,15 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
380 rustc_specialization_trait, Normal, template!(Word), 379 rustc_specialization_trait, Normal, template!(Word),
381 "the `#[rustc_specialization_trait]` attribute is used to check specializations" 380 "the `#[rustc_specialization_trait]` attribute is used to check specializations"
382 ), 381 ),
382 rustc_attr!(
383 rustc_main, Normal, template!(Word),
384 "the `#[rustc_main]` attribute is used internally to specify test entry point function",
385 ),
386 rustc_attr!(
387 rustc_skip_array_during_method_dispatch, Normal, template!(Word),
388 "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
389 from method dispatch when the receiver is an array, for compatibility in editions < 2021."
390 ),
383 391
384 // ========================================================================== 392 // ==========================================================================
385 // Internal attributes, Testing: 393 // Internal attributes, Testing:
@@ -387,6 +395,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
387 395
388 rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), 396 rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
389 rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), 397 rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
398 rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
390 rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), 399 rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
391 rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), 400 rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
392 rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), 401 rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
@@ -395,13 +404,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
395 template!(Word, List: "delay_span_bug_from_inside_query") 404 template!(Word, List: "delay_span_bug_from_inside_query")
396 ), 405 ),
397 rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), 406 rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
407 rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
398 rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), 408 rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
399 rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), 409 rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
400 rustc_attr!( 410 rustc_attr!(
401 TEST, rustc_dirty, AssumedUsed,
402 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
403 ),
404 rustc_attr!(
405 TEST, rustc_clean, AssumedUsed, 411 TEST, rustc_clean, AssumedUsed,
406 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), 412 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
407 ), 413 ),
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index f2e809ca9..f22383e22 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -85,6 +85,10 @@ impl ChildBySource for ItemScope {
85 res[keys::CONST].insert(src, konst); 85 res[keys::CONST].insert(src, konst);
86 }); 86 });
87 self.impls().for_each(|imp| add_impl(db, res, imp)); 87 self.impls().for_each(|imp| add_impl(db, res, imp));
88 self.attr_macro_invocs().for_each(|(ast_id, call_id)| {
89 let item = ast_id.with_value(ast_id.to_node(db.upcast()));
90 res[keys::ATTR_MACRO].insert(item, call_id);
91 });
88 92
89 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 93 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
90 match item { 94 match item {
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index d2bb381be..52cb7777b 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -143,6 +143,10 @@ pub struct TraitData {
143 pub is_auto: bool, 143 pub is_auto: bool,
144 pub is_unsafe: bool, 144 pub is_unsafe: bool,
145 pub visibility: RawVisibility, 145 pub visibility: RawVisibility,
146 /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
147 /// method calls to this trait's methods when the receiver is an array and the crate edition is
148 /// 2015 or 2018.
149 pub skip_array_during_method_dispatch: bool,
146} 150}
147 151
148impl TraitData { 152impl TraitData {
@@ -157,6 +161,10 @@ impl TraitData {
157 let container = AssocContainerId::TraitId(tr); 161 let container = AssocContainerId::TraitId(tr);
158 let visibility = item_tree[tr_def.visibility].clone(); 162 let visibility = item_tree[tr_def.visibility].clone();
159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); 163 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
164 let skip_array_during_method_dispatch = item_tree
165 .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
166 .by_key("rustc_skip_array_during_method_dispatch")
167 .exists();
160 168
161 let items = collect_items( 169 let items = collect_items(
162 db, 170 db,
@@ -168,7 +176,14 @@ impl TraitData {
168 100, 176 100,
169 ); 177 );
170 178
171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) 179 Arc::new(TraitData {
180 name,
181 items,
182 is_auto,
183 is_unsafe,
184 visibility,
185 skip_array_during_method_dispatch,
186 })
172 } 187 }
173 188
174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 189 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 7eadc8e0d..c977971cd 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -51,6 +51,9 @@ pub trait InternDatabase: SourceDatabase {
51 51
52#[salsa::query_group(DefDatabaseStorage)] 52#[salsa::query_group(DefDatabaseStorage)]
53pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { 53pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
54 #[salsa::input]
55 fn enable_proc_attr_macros(&self) -> bool;
56
54 #[salsa::invoke(ItemTree::file_item_tree_query)] 57 #[salsa::invoke(ItemTree::file_item_tree_query)]
55 fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; 58 fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
56 59
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 44d22b918..6933f6e3c 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -280,7 +280,7 @@ impl GenericParams {
280 sm.type_params.insert(param_id, Either::Right(type_param.clone())); 280 sm.type_params.insert(param_id, Either::Right(type_param.clone()));
281 281
282 let type_ref = TypeRef::Path(name.into()); 282 let type_ref = TypeRef::Path(name.into());
283 self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref)); 283 self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
284 } 284 }
285 for lifetime_param in params.lifetime_params() { 285 for lifetime_param in params.lifetime_params() {
286 let name = 286 let name =
@@ -289,7 +289,7 @@ impl GenericParams {
289 let param_id = self.lifetimes.alloc(param); 289 let param_id = self.lifetimes.alloc(param);
290 sm.lifetime_params.insert(param_id, lifetime_param.clone()); 290 sm.lifetime_params.insert(param_id, lifetime_param.clone());
291 let lifetime_ref = LifetimeRef::new_name(name); 291 let lifetime_ref = LifetimeRef::new_name(name);
292 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); 292 self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
293 } 293 }
294 for const_param in params.const_params() { 294 for const_param in params.const_params() {
295 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); 295 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 960cabb5f..404e3e153 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -1,6 +1,6 @@
1//! A map of all publicly exported items in a crate. 1//! A map of all publicly exported items in a crate.
2 2
3use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; 3use std::{fmt, hash::BuildHasherDefault, sync::Arc};
4 4
5use base_db::CrateId; 5use base_db::CrateId;
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
@@ -69,81 +69,11 @@ pub struct ImportMap {
69impl ImportMap { 69impl ImportMap {
70 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 70 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
71 let _p = profile::span("import_map_query"); 71 let _p = profile::span("import_map_query");
72 let def_map = db.crate_def_map(krate);
73 let mut import_map = Self::default();
74
75 // We look only into modules that are public(ly reexported), starting with the crate root.
76 let empty = ImportPath { segments: vec![] };
77 let root = def_map.module_id(def_map.root());
78 let mut worklist = vec![(root, empty)];
79 while let Some((module, mod_path)) = worklist.pop() {
80 let ext_def_map;
81 let mod_data = if module.krate == krate {
82 &def_map[module.local_id]
83 } else {
84 // The crate might reexport a module defined in another crate.
85 ext_def_map = module.def_map(db);
86 &ext_def_map[module.local_id]
87 };
88
89 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
90 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
91 if per_ns.is_none() {
92 None
93 } else {
94 Some((name, per_ns))
95 }
96 });
97
98 for (name, per_ns) in visible_items {
99 let mk_path = || {
100 let mut path = mod_path.clone();
101 path.segments.push(name.clone());
102 path
103 };
104
105 for item in per_ns.iter_items() {
106 let path = mk_path();
107 let path_len = path.len();
108 let import_info =
109 ImportInfo { path, container: module, is_trait_assoc_item: false };
110
111 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
112 import_map.collect_trait_assoc_items(
113 db,
114 tr,
115 matches!(item, ItemInNs::Types(_)),
116 &import_info,
117 );
118 }
119 72
120 match import_map.map.entry(item) { 73 let mut import_map = collect_import_map(db, krate);
121 Entry::Vacant(entry) => {
122 entry.insert(import_info);
123 }
124 Entry::Occupied(mut entry) => {
125 // If the new path is shorter, prefer that one.
126 if path_len < entry.get().path.len() {
127 *entry.get_mut() = import_info;
128 } else {
129 continue;
130 }
131 }
132 }
133
134 // If we've just added a path to a module, descend into it. We might traverse
135 // modules multiple times, but only if the new path to it is shorter than the
136 // first (else we `continue` above).
137 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
138 worklist.push((mod_id, mk_path()));
139 }
140 }
141 }
142 }
143 74
144 let mut importables = import_map.map.iter().collect::<Vec<_>>(); 75 let mut importables = import_map.map.iter().collect::<Vec<_>>();
145 76 importables.sort_by_cached_key(|(_, import_info)| fst_path(&import_info.path));
146 importables.sort_by(cmp);
147 77
148 // Build the FST, taking care not to insert duplicate values. 78 // Build the FST, taking care not to insert duplicate values.
149 79
@@ -151,13 +81,13 @@ impl ImportMap {
151 let mut last_batch_start = 0; 81 let mut last_batch_start = 0;
152 82
153 for idx in 0..importables.len() { 83 for idx in 0..importables.len() {
154 if let Some(next_item) = importables.get(idx + 1) { 84 let key = fst_path(&importables[last_batch_start].1.path);
155 if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { 85 if let Some((_, next_import_info)) = importables.get(idx + 1) {
86 if key == fst_path(&next_import_info.path) {
156 continue; 87 continue;
157 } 88 }
158 } 89 }
159 90
160 let key = fst_path(&importables[last_batch_start].1.path);
161 builder.insert(key, last_batch_start as u64).unwrap(); 91 builder.insert(key, last_batch_start as u64).unwrap();
162 92
163 last_batch_start = idx + 1; 93 last_batch_start = idx + 1;
@@ -185,6 +115,7 @@ impl ImportMap {
185 is_type_in_ns: bool, 115 is_type_in_ns: bool,
186 original_import_info: &ImportInfo, 116 original_import_info: &ImportInfo,
187 ) { 117 ) {
118 let _p = profile::span("collect_trait_assoc_items");
188 for (assoc_item_name, item) in &db.trait_data(tr).items { 119 for (assoc_item_name, item) in &db.trait_data(tr).items {
189 let module_def_id = match item { 120 let module_def_id = match item {
190 AssocItemId::FunctionId(f) => ModuleDefId::from(*f), 121 AssocItemId::FunctionId(f) => ModuleDefId::from(*f),
@@ -210,6 +141,84 @@ impl ImportMap {
210 } 141 }
211} 142}
212 143
144fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap {
145 let _p = profile::span("collect_import_map");
146
147 let def_map = db.crate_def_map(krate);
148 let mut import_map = ImportMap::default();
149
150 // We look only into modules that are public(ly reexported), starting with the crate root.
151 let empty = ImportPath { segments: vec![] };
152 let root = def_map.module_id(def_map.root());
153 let mut worklist = vec![(root, empty)];
154 while let Some((module, mod_path)) = worklist.pop() {
155 let ext_def_map;
156 let mod_data = if module.krate == krate {
157 &def_map[module.local_id]
158 } else {
159 // The crate might reexport a module defined in another crate.
160 ext_def_map = module.def_map(db);
161 &ext_def_map[module.local_id]
162 };
163
164 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
165 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
166 if per_ns.is_none() {
167 None
168 } else {
169 Some((name, per_ns))
170 }
171 });
172
173 for (name, per_ns) in visible_items {
174 let mk_path = || {
175 let mut path = mod_path.clone();
176 path.segments.push(name.clone());
177 path
178 };
179
180 for item in per_ns.iter_items() {
181 let path = mk_path();
182 let path_len = path.len();
183 let import_info =
184 ImportInfo { path, container: module, is_trait_assoc_item: false };
185
186 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
187 import_map.collect_trait_assoc_items(
188 db,
189 tr,
190 matches!(item, ItemInNs::Types(_)),
191 &import_info,
192 );
193 }
194
195 match import_map.map.entry(item) {
196 Entry::Vacant(entry) => {
197 entry.insert(import_info);
198 }
199 Entry::Occupied(mut entry) => {
200 // If the new path is shorter, prefer that one.
201 if path_len < entry.get().path.len() {
202 *entry.get_mut() = import_info;
203 } else {
204 continue;
205 }
206 }
207 }
208
209 // If we've just added a path to a module, descend into it. We might traverse
210 // modules multiple times, but only if the new path to it is shorter than the
211 // first (else we `continue` above).
212 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
213 worklist.push((mod_id, mk_path()));
214 }
215 }
216 }
217 }
218
219 import_map
220}
221
213impl PartialEq for ImportMap { 222impl PartialEq for ImportMap {
214 fn eq(&self, other: &Self) -> bool { 223 fn eq(&self, other: &Self) -> bool {
215 // `fst` and `importables` are built from `map`, so we don't need to compare them. 224 // `fst` and `importables` are built from `map`, so we don't need to compare them.
@@ -240,17 +249,12 @@ impl fmt::Debug for ImportMap {
240} 249}
241 250
242fn fst_path(path: &ImportPath) -> String { 251fn fst_path(path: &ImportPath) -> String {
252 let _p = profile::span("fst_path");
243 let mut s = path.to_string(); 253 let mut s = path.to_string();
244 s.make_ascii_lowercase(); 254 s.make_ascii_lowercase();
245 s 255 s
246} 256}
247 257
248fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
249 let lhs_str = fst_path(&lhs.path);
250 let rhs_str = fst_path(&rhs.path);
251 lhs_str.cmp(&rhs_str)
252}
253
254#[derive(Debug, Eq, PartialEq, Hash)] 258#[derive(Debug, Eq, PartialEq, Hash)]
255pub enum ImportKind { 259pub enum ImportKind {
256 Module, 260 Module,
@@ -338,6 +342,7 @@ impl Query {
338 } 342 }
339 343
340 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { 344 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool {
345 let _p = profile::span("import_map::Query::import_matches");
341 if import.is_trait_assoc_item { 346 if import.is_trait_assoc_item {
342 if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { 347 if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) {
343 return false; 348 return false;
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 9014468ea..08407ebfa 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -4,11 +4,11 @@
4use std::collections::hash_map::Entry; 4use std::collections::hash_map::Entry;
5 5
6use base_db::CrateId; 6use base_db::CrateId;
7use hir_expand::name::Name; 7use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
8use hir_expand::MacroDefKind;
9use once_cell::sync::Lazy; 8use once_cell::sync::Lazy;
10use rustc_hash::{FxHashMap, FxHashSet}; 9use rustc_hash::{FxHashMap, FxHashSet};
11use stdx::format_to; 10use stdx::format_to;
11use syntax::ast;
12 12
13use crate::{ 13use crate::{
14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId, 14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
@@ -53,12 +53,13 @@ pub struct ItemScope {
53 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will 53 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
54 // be all resolved to the last one defined if shadowing happens. 54 // be all resolved to the last one defined if shadowing happens.
55 legacy_macros: FxHashMap<Name, MacroDefId>, 55 legacy_macros: FxHashMap<Name, MacroDefId>,
56 attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
56} 57}
57 58
58pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { 59pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
59 BuiltinType::ALL 60 BuiltinType::ALL
60 .iter() 61 .iter()
61 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) 62 .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
62 .collect() 63 .collect()
63}); 64});
64 65
@@ -169,6 +170,16 @@ impl ItemScope {
169 self.legacy_macros.insert(name, mac); 170 self.legacy_macros.insert(name, mac);
170 } 171 }
171 172
173 pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
174 self.attr_macros.insert(item, call);
175 }
176
177 pub(crate) fn attr_macro_invocs(
178 &self,
179 ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
180 self.attr_macros.iter().map(|(k, v)| (*k, *v))
181 }
182
172 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { 183 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
173 self.unnamed_trait_imports.get(&tr).copied() 184 self.unnamed_trait_imports.get(&tr).copied()
174 } 185 }
@@ -307,6 +318,7 @@ impl ItemScope {
307 unnamed_consts, 318 unnamed_consts,
308 unnamed_trait_imports, 319 unnamed_trait_imports,
309 legacy_macros, 320 legacy_macros,
321 attr_macros,
310 } = self; 322 } = self;
311 types.shrink_to_fit(); 323 types.shrink_to_fit();
312 values.shrink_to_fit(); 324 values.shrink_to_fit();
@@ -317,6 +329,7 @@ impl ItemScope {
317 unnamed_consts.shrink_to_fit(); 329 unnamed_consts.shrink_to_fit();
318 unnamed_trait_imports.shrink_to_fit(); 330 unnamed_trait_imports.shrink_to_fit();
319 legacy_macros.shrink_to_fit(); 331 legacy_macros.shrink_to_fit();
332 attr_macros.shrink_to_fit();
320 } 333 }
321} 334}
322 335
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 6208facd5..3f90bda74 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -130,7 +130,7 @@ impl<'a> Ctx<'a> {
130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
131 }; 131 };
132 132
133 self.add_attrs(item.into(), attrs.clone()); 133 self.add_attrs(item.into(), attrs);
134 134
135 Some(item) 135 Some(item)
136 } 136 }
@@ -276,10 +276,11 @@ impl<'a> Ctx<'a> {
276 let visibility = self.lower_visibility(enum_); 276 let visibility = self.lower_visibility(enum_);
277 let name = enum_.name()?.as_name(); 277 let name = enum_.name()?.as_name();
278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); 278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
279 let variants = match &enum_.variant_list() { 279 let variants =
280 Some(variant_list) => self.lower_variants(variant_list), 280 self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() {
281 None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), 281 Some(variant_list) => this.lower_variants(variant_list),
282 }; 282 None => IdRange::new(this.next_variant_idx()..this.next_variant_idx()),
283 });
283 let ast_id = self.source_ast_id_map.ast_id(enum_); 284 let ast_id = self.source_ast_id_map.ast_id(enum_);
284 let res = Enum { name, visibility, generic_params, variants, ast_id }; 285 let res = Enum { name, visibility, generic_params, variants, ast_id };
285 Some(id(self.data().enums.alloc(res))) 286 Some(id(self.data().enums.alloc(res)))
@@ -822,7 +823,7 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
822 known::type_name, 823 known::type_name,
823 known::variant_count, 824 known::variant_count,
824 ] 825 ]
825 .contains(&name) 826 .contains(name)
826} 827}
827 828
828fn lower_abi(abi: ast::Abi) -> Interned<str> { 829fn lower_abi(abi: ast::Abi) -> Interned<str> {
@@ -854,7 +855,7 @@ impl UseTreeLowering<'_> {
854 // E.g. `use something::{inner}` (prefix is `None`, path is `something`) 855 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
855 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) 856 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
856 Some(path) => { 857 Some(path) => {
857 match ModPath::from_src(self.db, path, &self.hygiene) { 858 match ModPath::from_src(self.db, path, self.hygiene) {
858 Some(it) => Some(it), 859 Some(it) => Some(it),
859 None => return None, // FIXME: report errors somewhere 860 None => return None, // FIXME: report errors somewhere
860 } 861 }
@@ -873,7 +874,7 @@ impl UseTreeLowering<'_> {
873 } else { 874 } else {
874 let is_glob = tree.star_token().is_some(); 875 let is_glob = tree.star_token().is_some();
875 let path = match tree.path() { 876 let path = match tree.path() {
876 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?), 877 Some(path) => Some(ModPath::from_src(self.db, path, self.hygiene)?),
877 None => None, 878 None => None,
878 }; 879 };
879 let alias = tree.rename().map(|a| { 880 let alias = tree.rename().map(|a| {
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index cc9944a22..b1e1b70d0 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -426,7 +426,7 @@ impl<'a> Printer<'a> {
426 w!(self, " {{"); 426 w!(self, " {{");
427 self.indented(|this| { 427 self.indented(|this| {
428 for item in &**items { 428 for item in &**items {
429 this.print_mod_item((*item).into()); 429 this.print_mod_item(*item);
430 } 430 }
431 }); 431 });
432 wln!(self, "}}"); 432 wln!(self, "}}");
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index b362add5c..57686dc6e 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -359,3 +359,41 @@ trait Tr<'a, T: 'a>: Super {}
359 "#]], 359 "#]],
360 ) 360 )
361} 361}
362
363#[test]
364fn inherit_visibility() {
365 check(
366 r#"
367pub(crate) enum En {
368 Var1(u8),
369 Var2 {
370 fld: u8,
371 },
372}
373
374pub(crate) trait Tr {
375 fn f();